//-*-c++-*--------------------------------------------------------------
//  nsrFile.cpp
//   File descriptors, etc.
//
//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett- Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.
//
//  CLASSES:
//   ClassName1
//   ClassName2
//  
//----------------------------------------------------------------------
//
// $Source: /projects/HMS/nsr/udfCore/descr/nsrFile.cpp,v $
// $Revision: 1.37 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/06/21 23:34:47 $

#include "nsrLib.h"

// SpaceBitmapDesc
NSR::SpaceBitmapDesc::SpaceBitmapDesc( UINT32 nb ) :
    TaggedDescriptor( tag_SBD, 24 ), // Stops at end of fields.
    numBits_  (  16 ),
    numBytes_ (  20 )
{
    numBits_ = nb;
    bodyInit();
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::SpaceBitmapDesc::operator != ( const SpaceBitmapDesc & obj ) const
{
    UINT16 bad = 0;

    bad += ( numBits_  != obj.numBits_  );
    bad += ( numBytes_ != obj.numBytes_ );

    return bad != 0 ? True : False;
}

NSR::Error
NSR::SpaceBitmapDesc::bodyVerifyISO( CONST_BYTE_PTR rbp )
{
    SpaceBitmapDesc tmp(0);
    tmp.bodyFromISO(rbp);
    if (tmp != *this) {
        return Error(error_VerifySBD);
    } else {
        return Error(error_None);
    }
}
#endif

void
NSR::SpaceBitmapDesc::bodyClear(void) 
{
    numBits_  = 0;
    numBytes_ = 0;
}

void
NSR::SpaceBitmapDesc::bodyInit(void) 
{
    numBytes_ = (numBits_+7)/8;
}

void
NSR::SpaceBitmapDesc::bodyToISO( BYTE_PTR rbp )
{
    numBits_  .toISO( rbp );
    numBytes_ .toISO( rbp );
}

void
NSR::SpaceBitmapDesc::bodyFromISO( CONST_BYTE_PTR rbp )
{
    numBits_  .fromISO( rbp );
    numBytes_ .fromISO( rbp );
}

// ICBFlags
NSR::ICBFlags::ICBFlags( UINT16 o ) :
    field(o,2),
    adType              (  0, 3 ),
    miscCharacteristics (  3 ,10 ),
    reserved            ( 13, 3 ) {

    init();
}

void
NSR::ICBFlags::init()
{
}        

#ifdef NSR_VERIFY
NSR::Boolean
NSR::ICBFlags::operator != ( const ICBFlags & obj ) const
{
    UINT16 bad = 0;

    bad += ( adType               != obj.adType               );
    bad += ( miscCharacteristics  != obj.miscCharacteristics  );
    bad += ( reserved             != obj.reserved             );

    return bad != 0 ? True : False;
}
#endif

void
NSR::ICBFlags::clear()
{
    adType              .clear();
    miscCharacteristics .clear();
    reserved            .clear();

    init();
}

void
NSR::ICBFlags::toISO( BYTE_PTR rbp )
{
    reserved = 0;
    rbp += field.start();

    adType              .toISO( rbp );
    miscCharacteristics .toISO( rbp );
    reserved            .toISO( rbp );
}

void
NSR::ICBFlags::fromISO( CONST_BYTE_PTR rbp )
{
    rbp += field.start();

    adType              .fromISO( rbp );
    miscCharacteristics .fromISO( rbp );
    reserved            .fromISO( rbp );
}

// ICBTag

// NOTE:  FileType has been replaced by icbType.  --CSB 6-9-95
NSR::ICBTag::ICBTag( UINT16 o, ICBType icbType,  ADType at ) : 

    field( o, 20 ),
    priNoDirectEntries (  0 ),
    strategyType       (  4 ),
    strategyParm       (  6 ),
    maxEntries         (  8 ),
    reserved           ( 10, 1 ),
    fileType_          ( 11 ),
    parentICB          ( 12 ),
    flags              ( 18 ) {

    fileType_    = icbType;
    flags.adType = at;

    init();
}

NSR::ADType
NSR::ICBTag::adType(void) const
{
    switch (flags.adType) {
    case ad_Short    :  return ad_Short;
    case ad_Long     :  return ad_Long;
    case ad_Extended :  return ad_Extended;
    case ad_Embedded :  return ad_Embedded;
    default          :  return ad_Unknown;
    }
}

NSR::ICBType
NSR::ICBTag::icbType () const
{
    // RECALL:  If the ICBTag is storing any of the FileType 
    //   types, then it will report that it is merely an 
    //   icb_FileEntry.

    switch( fileType_ ) {
    case       icb_UnallocatedSpaceEntry:
        return icb_UnallocatedSpaceEntry;
    case       icb_PartIntegrityEntry:
        return icb_PartIntegrityEntry;
    case       icb_IndirectEntry:
        return icb_IndirectEntry;
    case       icb_TerminalEntry:
        return icb_TerminalEntry;
    default:
        return icb_FileEntry;
    }
}

void
NSR::ICBTag::init() {
    strategyType       = 4; // OSTA 2.3.5.1
    maxEntries         = 1;
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::ICBTag::operator != ( const ICBTag & obj ) const
{
    UINT16 bad = 0;
    
    bad += ( priNoDirectEntries != obj.priNoDirectEntries );
    bad += ( strategyType       != obj.strategyType       );
    bad += ( strategyParm       != obj.strategyParm       );
    bad += ( maxEntries         != obj.maxEntries         );
    bad += ( reserved           != obj.reserved           );
    bad += ( fileType_          != obj.fileType_          );
    bad += ( parentICB          != obj.parentICB          );
    bad += ( flags              != obj.flags              );

    return ( bad != 0 ? True : False );
}
#endif

void
NSR::ICBTag::clear()
{
    priNoDirectEntries .clear();
    strategyType       .clear();
    strategyParm       .clear();
    maxEntries         .clear();
    reserved           .clear();
    fileType_          .clear();
    parentICB          .clear();
    flags              .clear();

    init();
}

void
NSR::ICBTag::toISO( BYTE_PTR rbp)
{
    rbp += field.start();

    priNoDirectEntries .toISO( rbp );
    strategyType       .toISO( rbp );
    strategyParm       .toISO( rbp );
    maxEntries         .toISO( rbp );
    reserved           .toISO( rbp );
    fileType_          .toISO( rbp );
    parentICB          .toISO( rbp );
    flags              .toISO( rbp );

}

void
NSR::ICBTag::fromISO( CONST_BYTE_PTR rbp)
{
    rbp += field.start();

    priNoDirectEntries .fromISO( rbp );
    strategyType       .fromISO( rbp );
    strategyParm       .fromISO( rbp );
    maxEntries         .fromISO( rbp );
    reserved           .fromISO( rbp );
    fileType_          .fromISO( rbp );
    parentICB          .fromISO( rbp );
    flags              .fromISO( rbp );
}

// FilePerms

NSR::FilePerms::FilePerms( UINT16 o ) :

    field(o,4),
    all      (  0, 15 ),
    reserved ( 15, 17 )
{
    init();
}

void
NSR::FilePerms::init()
{
    reserved = 0;
}

void
NSR::FilePerms::clear()
{
    all      .clear();
    reserved .clear();

    init();
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::FilePerms::operator != ( const FilePerms & obj ) const
{
    UINT16 bad = 0;
    
    bad += ( all      != obj.all      );
    bad += ( reserved != obj.reserved );

    return ( bad != 0 ? True : False );
}
#endif

void
NSR::FilePerms::toISO( BYTE_PTR rbp ) {

    rbp += field.start();

    all     .toISO( rbp );
    reserved.toISO( rbp );
}

void
NSR::FilePerms::fromISO( CONST_BYTE_PTR rbp ) {

    rbp += field.start();

    all     .fromISO( rbp );
    reserved.fromISO( rbp );
}

// FileEntry

void
NSR::FileEntry::affixFloatingFields() {

    extendedAttr_.setFieldLen(lenExtendedAttr);
    allocDescTable_.field.start(extendedAttr_.field.after());
}

// if ( at == ad_Embedded ) n is numBytes.
NSR::FileEntry::FileEntry( unsigned n, ADType at ) : 

    TaggedDescriptor( tag_FE ), // Size varies.
    icbTag                (  16, icb_FileEntry, at ),
    uid                   (  36 ),
    gid                   (  40 ),
    permissions           (  44 ),
    fileLinkCount         (  48 ),
    recordFormat          (  50 ),
    recordDisplayAttr     (  51 ),
    recordLength          (  52 ),
    infoLength            (  56 ),
    logicalBlocksRecorded (  64 ),
    accessTime            (  72 ),
    modifyTime            (  84 ),
    attributeTime         (  96 ),
    checkpoint            ( 108 ),
    extendedAttrICB       ( 112 ),
    implementID           ( 128 ),
    uniqueID              ( 160 ),
    lenExtendedAttr       ( 168 ),
    lenAllocDesc          ( 172 ),
    extendedAttr_         ( 176, 0 ), // length floats
    allocDescTable_       (   0, n, at ) { // start floats

    lenAllocDesc = allocDescTable_.field.len();
    affixFloatingFields();
    descLen(allocDescTable_.field.after());

    bodyInit();
}

NSR::UINT16
NSR::FileEntry::unusedBytes( UINT16 blockLen ) const
{
    return blockLen - descLen();
}

// All of the three following methods zap out all EAs or ADs.
// They set their lengths to zero if any error occurs.
// numADTEnts() DOES change the adType, regardless of success or failure.

NSR::Error
NSR::FileEntry::setEALen( UINT16 blockLen, UINT16 eaLen )
{
    // First, set length to zero.
    lenExtendedAttr = 0;
    affixFloatingFields();
    descLen(allocDescTable_.field.after());
    if ( eaLen != 0 ) {
        // See if supplied length is appropriate
        if ( unusedBytes(blockLen) < eaLen )
            return Error(error_FileEntry_full);
        if ( EAPadLen(eaLen) != 0 )
            return Error(error_EA_Invalid_EA_length);

        // Finally, set length to supplied len.
        lenExtendedAttr = eaLen;
        affixFloatingFields();
        descLen(allocDescTable_.field.after());
    }
    return Error(error_None);
}

// This form preserves same type of ADs
NSR::Error
NSR::FileEntry::numADTEnts( UINT16 blockLen, UINT16 n )
{
    return numADTEnts(blockLen,n,allocDescTable_.adType());
}

// This form changes to a new type of AD.
NSR::Error
NSR::FileEntry::numADTEnts( UINT16 blockLen, UINT16 n, ADType at )
{
    // Try it.
    icbTag.adType(at);
    allocDescTable_.fitEnts(n,at);
    lenAllocDesc = allocDescTable_.field.len();
    descLen(allocDescTable_.field.after());
    if ( descLen() > blockLen ) {
        // If it did not fit, shrink to zero.
        // Leave adType in new state.
        allocDescTable_.fitEnts(0,at);
        lenAllocDesc = allocDescTable_.field.len();
        descLen(allocDescTable_.field.after());
        return Error(error_FileEntry_full);
    }
    return Error(error_None);
}

// ISSUE: Single Surface- how do we clear out all fields but keep the
// ADtype and File type the same? Do we need to do this? Should we
// support a separate method accepting the same args as the
// constructor here? (probably). The alternative is to save off the
// initial values of these things at construction time, and set their
// values once again. This includes the length of the descriptor, etc.
// This is perhaps the best way to make a descriptor reusable.

// NOTE that this returns the maximum number of ADTEntries that will
// fit in the FE ALONGSIDE the currently-reserved EASpace.

NSR::UINT16
NSR::FileEntry::maxADTEnts( UINT16 blockLen ) const
{
  return maxADTEnts(blockLen,allocDescTable_.adType());
}

NSR::UINT16
NSR::FileEntry::maxADTEnts( UINT16 blockLen, ADType at ) const
{
  return allocDescTable_.maxADs(blockLen - allocDescTable_.field.start(),
                                at);
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::FileEntry::operator != ( const FileEntry & obj ) const
{
    UINT16 bad = 0;

    bad += ( icbTag                != obj.icbTag                );
    bad += ( uid                   != obj.uid                   );
    bad += ( gid                   != obj.gid                   );
    bad += ( permissions           != obj.permissions           );
    bad += ( fileLinkCount         != obj.fileLinkCount         );
    bad += ( recordFormat          != obj.recordFormat          );
    bad += ( recordDisplayAttr     != obj.recordDisplayAttr     );
    bad += ( recordLength          != obj.recordLength          );
    bad += ( infoLength            != obj.infoLength            );
    bad += ( logicalBlocksRecorded != obj.logicalBlocksRecorded );
    bad += ( accessTime            != obj.accessTime            );
    bad += ( modifyTime            != obj.modifyTime            );
    bad += ( attributeTime         != obj.attributeTime         );
    bad += ( checkpoint            != obj.checkpoint            );
    bad += ( extendedAttrICB       != obj.extendedAttrICB       );
    bad += ( implementID           != obj.implementID           );
    bad += ( uniqueID              != obj.uniqueID              );
    bad += ( lenExtendedAttr       != obj.lenExtendedAttr       );
    bad += ( lenAllocDesc          != obj.lenAllocDesc          );
    bad += ( extendedAttr_         != obj.extendedAttr_          );
    if (Trace::logAlgorithms()) {
        printf("Before verify AllocDesc: bad %d.\n", bad);
    }
    bad += ( allocDescTable_       != obj.allocDescTable_        );
    if (Trace::logAlgorithms()) {
        printf("After verify AllocDesc: bad %d.\n", bad);
        allocDescTable_.dump("member");
        obj.allocDescTable_.dump("other ");
    }

    return ( bad != 0 ? True : False );

}

NSR::Error
NSR::FileEntry::bodyVerifyISO( CONST_BYTE_PTR rbp )
{
    FileEntry tmp(0);
    tmp.bodyFromISO(rbp);
    if (tmp != *this) {
        return Error(error_VerifyFE);
    } else {
        return Error(error_None);
    }
}
#endif

NSR::Error
NSR::FileEntry::bodyError() const
{
    Error err;

    if (( err = implementID     .error()) ) return err;
    if (( err = extendedAttr_   .error()) ) return err;
    if (( err = allocDescTable_ .error()) ) return err;
    return err;
}

void
NSR::FileEntry::bodyClear()
{
    // icbTag                (not here?)
    uid                   .clear();
    gid                   .clear();
    permissions           .clear();
    fileLinkCount         .clear();
    recordFormat          .clear();
    recordDisplayAttr     .clear();
    recordLength          .clear();
    infoLength            .clear();
    logicalBlocksRecorded .clear();
    accessTime            .clear();
    modifyTime            .clear();
    attributeTime         .clear();
    checkpoint            .clear();
    extendedAttrICB       .clear();
    implementID           .clear();
    uniqueID              .clear();
    lenExtendedAttr       .clear();
    // lenAllocDesc          (not here)
    extendedAttr_         .clear();
    allocDescTable_       .clear();
}

void
NSR::FileEntry::bodyInit()
{
    fileLinkCount     = 0;      // OSTA 2.3.6.1
    recordFormat      = 0;      // OSTA 2.3.6.2
    recordDisplayAttr = 0;      // OSTA 2.3.6.2
    recordLength      = 0;      // OSTA 2.3.6.2
    checkpoint        = 1;      // ISO 4/14.9.15
    implementID       .descVersionNo(descVersion_);
    uniqueID          = 0;      // OSTA 2.3.6.4
}

void
NSR::FileEntry::bodyToISO( BYTE_PTR rbp )
{
    icbTag                .toISO( rbp );
    uid                   .toISO( rbp );
    gid                   .toISO( rbp );
    permissions           .toISO( rbp );
    fileLinkCount         .toISO( rbp );
    recordFormat          .toISO( rbp );
    recordDisplayAttr     .toISO( rbp );
    recordLength          .toISO( rbp );
    infoLength            .toISO( rbp );
    logicalBlocksRecorded .toISO( rbp );
    accessTime            .toISO( rbp );
    modifyTime            .toISO( rbp );
    attributeTime         .toISO( rbp );
    checkpoint            .toISO( rbp );
    extendedAttrICB       .toISO( rbp );
    implementID           .toISO( rbp );
    uniqueID              .toISO( rbp );
    lenExtendedAttr       .toISO( rbp );
    lenAllocDesc          .toISO( rbp );
    extendedAttr_         .toISO( rbp );
    if (Trace::logAlgorithms()) {
        allocDescTable_.dump("==In bodyToISO(), adt");
        printf("==In bodyToISO(), fileEntry.error() is (%ld) [%s].\n", 
               (UINT32)error(), error().message());
    }
    allocDescTable_       .toISO( rbp );
    if (Trace::logAlgorithms()) {
        allocDescTable_.dump("==After bodyToISO(), adt");
        printf("==After bodyToISO(), fileEntry.error() is (%ld) [%s].\n", 
               (UINT32)error(), error().message());
    }
}

void
NSR::FileEntry::bodyFromISO( CONST_BYTE_PTR rbp )
{
    icbTag                .fromISO( rbp );
    uid                   .fromISO( rbp );
    gid                   .fromISO( rbp );
    permissions           .fromISO( rbp );
    fileLinkCount         .fromISO( rbp );
    recordFormat          .fromISO( rbp );
    recordDisplayAttr     .fromISO( rbp );
    recordLength          .fromISO( rbp );
    infoLength            .fromISO( rbp );
    logicalBlocksRecorded .fromISO( rbp );
    accessTime            .fromISO( rbp );
    modifyTime            .fromISO( rbp );
    attributeTime         .fromISO( rbp );
    checkpoint            .fromISO( rbp );
    extendedAttrICB       .fromISO( rbp );
    implementID           .fromISO( rbp );
    uniqueID              .fromISO( rbp );
    lenExtendedAttr       .fromISO( rbp );
    lenAllocDesc          .fromISO( rbp );

    affixFloatingFields();
    allocDescTable_.fitToLen(lenAllocDesc,icbTag.adType());

    extendedAttr_         .fromISO( rbp );

    if (Trace::logAlgorithms()) {
        allocDescTable_.dump("==In bodyFromISO(), adt");
        printf("==In bodyFromISO(), fileEntry.error() is (%ld) [%s].\n", 
               (UINT32)error(), error().message());
    }
    allocDescTable_       .fromISO( rbp );
    if (Trace::logAlgorithms()) {
        allocDescTable_.dump("==After bodyFromISO(), adt");
        printf("==After bodyFromISO(), fileEntry.error() is (%ld) [%s].\n", 
               (UINT32)error(), error().message());
    }
}

// AllocExtentDesc

NSR::AllocExtentDesc::AllocExtentDesc( unsigned n,
                                       ADType at ) :  

    TaggedDescriptor( tag_AED, 24 ), // Note ADs not included.
    prevAllocExtentLoc ( 16 ),
    lenAllocDesc       ( 20 ),
    allocDescTable_     ( 24 , n, at ) {

    // prevAllocExtentLoc = 0; (done in initializer)
    lenAllocDesc = allocDescTable_.field.len();
}

// This form preserves same type of ADs
NSR::Error
NSR::AllocExtentDesc::numADTEnts( UINT16 blockLen, UINT16 n )
{
    return numADTEnts(blockLen,n,allocDescTable_.adType());
}

// This form changes to a new type of AD.
NSR::Error
NSR::AllocExtentDesc::numADTEnts( UINT16 blockLen, UINT16 n, ADType at )
{
    // Try it.
    allocDescTable_.fitEnts(n,at);
    lenAllocDesc = allocDescTable_.field.len();
    descLen(allocDescTable_.field.after());
    if ( descLen() > blockLen ) {
        // If it did not fit, shrink to zero.
        // Leave adType in new state.
        allocDescTable_.fitEnts(0,at);
        lenAllocDesc = allocDescTable_.field.len();
        descLen(allocDescTable_.field.after());
        return Error(error_AllocExtentDesc_full);
    }
    return Error(error_None);
}

NSR::UINT16
NSR::AllocExtentDesc::maxADTEnts( UINT16 blockLen ) const
{
    return maxADTEnts(blockLen,allocDescTable_.adType());
}

NSR::UINT16
NSR::AllocExtentDesc::maxADTEnts( UINT16 blockLen, ADType at ) const
{
    return allocDescTable_.maxADs(blockLen - allocDescTable_.field.start(),
                                at);
}

void
NSR::AllocExtentDesc::dump(CONST_CHAR_PTR message) const
{
  printf("%s: prevBlock: %ld, aed length: %ld,\n",
         message,
         (UINT32)prevAllocExtentLoc, 
         (UINT32)lenAllocDesc);
  allocDescTable_.dump("---AED---");
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::AllocExtentDesc::operator != ( const AllocExtentDesc & obj ) const
{
    UINT16 bad = 0;
    if (Trace::logAlgorithms()) {
        printf("enter AllocExtentDesc::operator !=()\n");
    }

    bad += ( prevAllocExtentLoc != obj.prevAllocExtentLoc  );
    bad += ( lenAllocDesc       != obj.lenAllocDesc        );
    bad += ( allocDescTable_    != obj.allocDescTable_      );
    if (Trace::logAlgorithms()) {
        printf("exit AllocExtentDesc::operator !=(), bad is %d.\n", bad);
    }

    return bad != 0 ? True : False;
}

NSR::Error
NSR::AllocExtentDesc::bodyVerifyISO( CONST_BYTE_PTR rbp )
{
    AllocExtentDesc tmp(0,allocDescTable_.adType());
    tmp.bodyFromISO(rbp);
    if (tmp != *this) {
        return Error(error_VerifyAED);
    } else {
        return Error(error_None);
    }
}
#endif

NSR::Error
NSR::AllocExtentDesc::bodyError() const
{
    return allocDescTable_.error();
}

void
NSR::AllocExtentDesc::bodyClear() {

    prevAllocExtentLoc .clear();
    lenAllocDesc       .clear();
    allocDescTable_    .clear();
}

void
NSR::AllocExtentDesc::bodyToISO( BYTE_PTR rbp ) {

    prevAllocExtentLoc .toISO( rbp );
    lenAllocDesc       .toISO( rbp );
    allocDescTable_    .toISO( rbp );

}

void
NSR::AllocExtentDesc::bodyFromISO( CONST_BYTE_PTR rbp ) {

    prevAllocExtentLoc .fromISO( rbp );
    lenAllocDesc       .fromISO( rbp );

    allocDescTable_    .fitToLen( lenAllocDesc );
    allocDescTable_    .fromISO( rbp );
}

// IndirectEntry

NSR::IndirectEntry::IndirectEntry() : 

    TaggedDescriptor( tag_IE, 52 ),
    icbTag      ( 16, icb_IndirectEntry ),
    indirectICB ( 36 ) {

}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::IndirectEntry::operator != ( const IndirectEntry & obj ) const
{
    UINT16 bad = 0;

    bad += ( icbTag      != obj.icbTag       );
    bad += ( indirectICB != obj.indirectICB  );

    return bad != 0 ? True : False;
}

NSR::Error
NSR::IndirectEntry::bodyVerifyISO( CONST_BYTE_PTR rbp )
{
    IndirectEntry tmp;
    tmp.bodyFromISO(rbp);
    if (tmp != *this) {
        return Error(error_VerifyIE);
    } else {
        return Error(error_None);
    }
}
#endif

NSR::Error
NSR::IndirectEntry::bodyError() const
{
    return Error(error_None);
}

void
NSR::IndirectEntry::bodyClear() {

    // icbTag      (not here)
    indirectICB .clear();
}

void
NSR::IndirectEntry::bodyToISO( BYTE_PTR rbp ) {

    icbTag      .toISO( rbp ); 
    indirectICB .toISO( rbp );
}

void
NSR::IndirectEntry::bodyFromISO( CONST_BYTE_PTR rbp ) {

    icbTag      .fromISO( rbp ); 
    indirectICB .fromISO( rbp ); 
}

// TerminalEntry

NSR::TerminalEntry::TerminalEntry() : 

    TaggedDescriptor( tag_TE, 36 ),
    icbTag ( 16, icb_TerminalEntry ) {

}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::TerminalEntry::operator != ( const TerminalEntry & obj ) const
{
    UINT16 bad = 0;

    bad += ( icbTag != obj.icbTag );

    return bad != 0 ? True : False;
}

NSR::Error
NSR::TerminalEntry::bodyVerifyISO( CONST_BYTE_PTR rbp )
{
    TerminalEntry tmp;
    tmp.bodyFromISO(rbp);
    if (tmp != *this) {
        return Error(error_VerifyTE);
    } else {
        return Error(error_None);
    }
}
#endif

NSR::Error
NSR::TerminalEntry::bodyError() const
{
    return Error(error_None);
}

void
NSR::TerminalEntry::bodyClear() {
    // icbTag.clear(); (not here)
}

void
NSR::TerminalEntry::bodyToISO( BYTE_PTR rbp ) {
    icbTag.toISO( rbp ); 
}

void
NSR::TerminalEntry::bodyFromISO( CONST_BYTE_PTR rbp ) {
    icbTag.fromISO( rbp );
}

// FileCharacteristics

NSR::FileCharacteristics::FileCharacteristics( UINT16 o ) :

    field(o,1),
    hidden    ( 0 ),
    directory ( 1 ),
    deleted   ( 2 ),
    parent    ( 3 ),
    reserved  ( 4, 4 ) {

}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::FileCharacteristics::operator != ( const FileCharacteristics & obj ) const
{
    UINT16 bad = 0;

    bad += ( hidden    != obj.hidden     );
    bad += ( directory != obj.directory  );
    bad += ( deleted   != obj.deleted    );
    bad += ( parent    != obj.parent     );
    bad += ( reserved  != obj.reserved   );

    return bad != 0 ? True : False;
}
#endif

void
NSR::FileCharacteristics::clear() {

    hidden    .clear();
    directory .clear();
    deleted   .clear();
    parent    .clear();
    reserved  .clear();

}

void
NSR::FileCharacteristics::toISO( BYTE_PTR rbp ) {

    rbp += field.start();

    reserved  .clear();
    hidden    .toISO( rbp );
    directory .toISO( rbp );
    deleted   .toISO( rbp );
    parent    .toISO( rbp );
    reserved  .toISO( rbp );

}

void
NSR::FileCharacteristics::fromISO( CONST_BYTE_PTR rbp ) {

    rbp += field.start();

    hidden    .fromISO( rbp );
    directory .fromISO( rbp );
    deleted   .fromISO( rbp );
    parent    .fromISO( rbp );
    reserved  .fromISO( rbp );

}

// FileIdentifierDesc

void
NSR::FileIdentifierDesc::affixFloatingFields() {
    implementUse.setFieldLen( implementLength -
                              implementID.field.len());

    fileIdentifier.field.start(implementUse.field.after());
    fileIdentifier.setFieldLen(lenFileID); // For fromISO()

    padding.field.start(fileIdentifier.field.after());
    padding.setFieldLen(4*(UINT16(fileIdentifier.field.after()+3)/4) -
                        fileIdentifier.field.after());
}

NSR::FileIdentifierDesc::FileIdentifierDesc( const String &id ) :

    TaggedDescriptor( tag_FID ), // descriptor len varies
    fileVersionNo       ( 16 ),
    fileCharacteristics ( 18 ),
    lenFileID           ( 19 ),
    icbAddr             ( 20 ),
    implementLength     ( 36 ),
    implementID         ( 38 ),
    implementUse        ( 70, 0 ),  // length floats
    fileIdentifier      (  0 ),     // start, length float
    padding             (  0, 0 ) { // start, length float

    bodyInit();
    fileID(id);                 // This MUST affix floaters, etc.
}

void
NSR::FileIdentifierDesc::fileID( const String &id ) {
    fileIdentifier = id;
    lenFileID      = fileIdentifier.field.len();
    affixFloatingFields();
    descLen(padding.field.after());
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::FileIdentifierDesc::operator != ( const FileIdentifierDesc & obj ) const
{
    UINT16 bad = 0;

    bad += ( fileVersionNo       != obj.fileVersionNo        );
    bad += ( fileCharacteristics != obj.fileCharacteristics  );
    bad += ( lenFileID           != obj.lenFileID            );
    bad += ( icbAddr             != obj.icbAddr              );
    bad += ( implementLength     != obj.implementLength      );
    bad += ( implementID         != obj.implementID          );
    bad += ( implementUse        != obj.implementUse         );
    bad += ( fileIdentifier      != obj.fileIdentifier       );
    bad += ( padding             != obj.padding              );

    return bad != 0 ? True : False;
}

NSR::Error
NSR::FileIdentifierDesc::bodyVerifyISO( CONST_BYTE_PTR rbp )
{
    FileIdentifierDesc tmp;
    tmp.bodyFromISO(rbp);
    if (tmp != *this) {
        return Error(error_VerifyFID);
    } else {
        return Error(error_None);
    }
}
#endif

NSR::Error
NSR::FileIdentifierDesc::bodyError() const
{
    Error err;

    if (( err = implementID    .error()) ) return err;
    if (( err = implementUse   .error()) ) return err;
    if (( err = fileIdentifier .error()) ) return err;
    return err;
}

void
NSR::FileIdentifierDesc::bodyClear()
{ 
    fileVersionNo       .clear();
    fileCharacteristics .clear();
    lenFileID           .clear();
    icbAddr             .clear();
    implementLength     .clear();
    implementID         .clear();
    implementUse        .clear();
    fileIdentifier      .clear();
    padding             .clear();
}

void
NSR::FileIdentifierDesc::bodyInit()
{
    implementLength = implementID.field.len();
    fileVersionNo   = 1;      // OSTA 3.2.1.1
    icbAddr         .extType( ext_Recorded );
    implementID     .descVersionNo(descVersion_);
}

void
NSR::FileIdentifierDesc::bodyToISO( BYTE_PTR rbp )
{ 
    fileVersionNo       .toISO( rbp );
    fileCharacteristics .toISO( rbp );
    lenFileID           .toISO( rbp );
    icbAddr             .toISO( rbp );
    implementLength     .toISO( rbp );
    implementID         .toISO( rbp );
    implementUse        .toISO( rbp );
    fileIdentifier      .toISO( rbp );
    padding             .toISO( rbp );
}

void
NSR::FileIdentifierDesc::bodyFromISO( CONST_BYTE_PTR rbp )
{
    fileVersionNo       .fromISO( rbp );
    fileCharacteristics .fromISO( rbp );
    lenFileID           .fromISO( rbp );
    icbAddr             .fromISO( rbp );
    implementLength     .fromISO( rbp );
    implementID         .fromISO( rbp );

    affixFloatingFields();

    implementUse        .fromISO( rbp );
    fileIdentifier      .fromISO( rbp, readCSType_ );
    padding             .fromISO( rbp );
}

// ISSUE: Hole in preventing descLen from getting too large:
// Constructor does NOT check for this, in:
// - FileEntry
// - AllocExtentDesc
// - UnallocatedSpaceEntry
// PLUS, don't want to put size into an error category, since error is
// designed to capture to/fromISO() errors, rather than this sort of
// construction error. ACTION should be to set it to the maximum
// allowed if more than that is requested. ??? Then should the
// resizing change to do that as well? NO ERROR is returned!

// UnallocatedSpaceEntry

NSR::UnallocatedSpaceEntry::UnallocatedSpaceEntry( UINT32 n ) : 

    TaggedDescriptor( tag_USE ), // length calculated
    icbTag          ( 16, icb_UnallocatedSpaceEntry, ad_Short ),
    lenAllocDesc    ( 36 ),
    allocDescTable_ ( 40, n, ad_Short ) {

    descLen(allocDescTable_.field.after());

    bodyInit();
}

NSR::Error
NSR::UnallocatedSpaceEntry::numADTEnts( UINT16 blockLen, UINT16 n )
{
    // Try it.
    allocDescTable_.fitEnts(n,allocDescTable_.adType());
    lenAllocDesc = allocDescTable_.field.len();
    descLen(allocDescTable_.field.after());
    if ( descLen() > blockLen ) {
        // If it did not fit, shrink to zero.
        allocDescTable_.fitEnts(0,allocDescTable_.adType());
        lenAllocDesc = allocDescTable_.field.len();
        descLen(allocDescTable_.field.after());
        return Error(error_UnallocatedSpaceEntry_full);
    }
    return Error(error_None);
}

NSR::UINT16
NSR::UnallocatedSpaceEntry::maxADTEnts( UINT16 blockLen ) const
{
    return allocDescTable_.maxADs(blockLen - allocDescTable_.field.start(),
                                  allocDescTable_.adType());
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::UnallocatedSpaceEntry::operator != ( const UnallocatedSpaceEntry & obj ) const
{
    UINT16 bad = 0;

    bad += ( icbTag          != obj.icbTag          );
    bad += ( lenAllocDesc    != obj.lenAllocDesc    );
    bad += ( allocDescTable_ != obj.allocDescTable_  );

    return bad != 0 ? True : False;
}

NSR::Error
NSR::UnallocatedSpaceEntry::bodyVerifyISO( CONST_BYTE_PTR rbp )
{
    UnallocatedSpaceEntry tmp(0);
    tmp.bodyFromISO(rbp);
    if (tmp != *this) {
        return Error(error_VerifyUSE);
    } else {
        return Error(error_None);
    }
}
#endif

NSR::Error
NSR::UnallocatedSpaceEntry::bodyError() const
{
    return allocDescTable_.error();
}

void
NSR::UnallocatedSpaceEntry::bodyClear()
{ 
    // icbTag         (not here)
    lenAllocDesc    .clear();
    allocDescTable_ .clear();
}

void
NSR::UnallocatedSpaceEntry::bodyInit()
{
    lenAllocDesc = allocDescTable_.field.len();
}

void
NSR::UnallocatedSpaceEntry::bodyToISO( BYTE_PTR rbp )
{ 
    icbTag          .toISO( rbp ); 
    lenAllocDesc    .toISO( rbp ); 
    allocDescTable_ .toISO( rbp );
}

void
NSR::UnallocatedSpaceEntry::bodyFromISO( CONST_BYTE_PTR rbp )
{
    icbTag          .fromISO( rbp ); 
    lenAllocDesc    .fromISO( rbp );

    allocDescTable_ .fitToLen(lenAllocDesc);
    allocDescTable_ .fromISO( rbp );
}

// PathComponent

void
NSR::PathComponent::init()
{
    // componentFileVersion = 0; This is default value, so no need to init.
}

NSR::PathComponent::PathComponent() :

    componentType        ( 0 ),
    lenComponentID       ( 1 ),
    componentFileVersion ( 2 ),
    componentID          ( 4 ) {

    init();
}

NSR::PathComponent&
NSR::PathComponent::operator =( const PathElement& pe )
{
    clear();

    switch ( pe.type ) {
    case path_Custom_Root   : componentType = pc_FSRoot ; break;
    case path_Standard_Root : componentType = pc_DirRoot; break;
    case path_Parent        : componentType = pc_Parent ; break;
    case path_Same          : componentType = pc_Same   ; break;
    case path_Name          : componentType = pc_Name   ;

        componentID    = pe.name;
        lenComponentID = componentID.field.len();
        break;

    default: err = error_Empty_path_element;
    }

    return *this;
}

NSR::PathComponent::operator NSR::PathElement() {

    PathElement pe;
    switch ( componentType ) {
    case pc_FSRoot  : pe.type = path_Custom_Root  ; break;
    case pc_DirRoot : pe.type = path_Standard_Root; break;
    case pc_Parent  : pe.type = path_Parent       ; break;
    case pc_Same    : pe.type = path_Same         ; break;
    case pc_Name    : pe.type = path_Name         ; break;
    default: err = error_Unknown_path_component;
    }
    pe.name = componentID;
    return ( pe );
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::PathComponent::operator != ( const PathComponent & obj ) const
{
    UINT16 bad = 0;

    bad += ( componentType        != obj.componentType         );
    bad += ( lenComponentID       != obj.lenComponentID        );
    bad += ( componentFileVersion != obj.componentFileVersion  );
    bad += ( componentID          != obj.componentID           );

    return bad != 0 ? True : False;
}

NSR::Error
NSR::PathComponent::verifyISO( BYTE_PTR rbp )
{
    PathComponent tmp;
    tmp.fromISO(rbp);
    if (tmp != *this) {
        return Error(error_VerifyPC);
    } else {
        return Error(error_None);
    }
}
#endif

void
NSR::PathComponent::clear()
{
    err = error_None;

    componentType        .clear();
    lenComponentID       .clear();
    componentFileVersion .clear();
    componentID          .clear();

    init();
}

void
NSR::PathComponent::toISO( BYTE_PTR rbp )
{
    componentType        .toISO( rbp );
    lenComponentID       .toISO( rbp );
    componentFileVersion .toISO( rbp );
    componentID          .toISO( rbp );

#ifdef NSR_VERIFY
    if (debug.verifyISO()) {
        err = verifyISO( rbp);
        if ( err )  debug.holdImage( rbp, descLen() );
    }
#endif
}

void
NSR::PathComponent::fromISO( CONST_BYTE_PTR rbp )
{
    componentType        .fromISO( rbp );
    lenComponentID       .fromISO( rbp );
    componentFileVersion .fromISO( rbp );

    componentID          .setFieldLen(lenComponentID);

    componentID          .fromISO( rbp, readCSType_ );
}

