//-*-c++-*--------------------------------------------------------------
//  nsrTypes.cpp
//   Low level descriptor types
//
//      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:
//    Uint64
//    TypeTimeZone
//    TimeStamp
//    Bytes
//    ZeroBytes
//    Dchars
//    RegIDFlags
//    RegID
//    CharSpec
//    Dstring
//    LogicalBlockAddr
//    ExtLength
//    ShortAllocDesc
//    LongAllocDesc
//    ExtendedAllocDesc
//    ExtentDesc
//    DescriptorTag
//  
//----------------------------------------------------------------------
//
// $Source: /projects/HMS/nsr/udfCore/descr/nsrTypes.cpp,v $
// $Revision: 1.29 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/06/25 23:18:35 $

#include "nsrLib.h"

// Uint64
NSR::Uint64::Uint64( UINT16 o ) :
    field(o,8),
    lval ( 0 ),
    hval ( 4 )
{
    lval = 0;
    hval = 0;
}

NSR::Uint64 &
NSR::Uint64::operator=(UINT32 v)
{
    lval = v;
    hval = 0;
    return *this;
}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::Uint64::operator != ( const Uint64 & obj ) const
{
    return ( (lval != obj.lval) || (hval != obj.hval) ? True : False );
}
#endif

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

    lval .toISO( rbp );
    hval .toISO( rbp );
}

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

    lval .fromISO( rbp );
    hval .fromISO( rbp );
}

// TypeTimeZone

NSR::TypeTimeZone::TypeTimeZone(UINT16 o) :
    field(o,2),
    tzType   ( 12,  4 ),
    timeZone (  0, 12 )
{
    init();
}

void
NSR::TypeTimeZone::init()
{
    tzType = 1;               // OSTA restriction
}

void
NSR::TypeTimeZone::clear()
{
    tzType   .clear();
    timeZone .clear();

    init();
}

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

    tzType   .toISO(rbp);
    timeZone .toISO(rbp);
}

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

    tzType   .fromISO(rbp);
    timeZone .fromISO(rbp);
}

// TimeStamp

NSR::TimeStamp::TimeStamp( UINT16 o ) :
    field(o,12),
    ttz_               (  0 ),
    year_              (  2 ),
    month_             (  4 ),
    day_               (  5 ),
    hour_              (  6 ),
    minute_            (  7 ),
    second_            (  8 ),
    centiSeconds_      (  9 ),
    hectoMicroSeconds_ ( 10 ),
    microSeconds_      ( 11 )
{}

// ISSUE: Timezone inefficiency
//
// This code calculates the timezone EVERY TIME a time_t struct is
// assigned into a timestamp. This should be done much less
// frequently. Can this be made into a static member function? Note
// that it must take the value off of the disk when read, and only set
// it to the local timezone when written. A quick workaround is to set
// it to -2047, which means that the time zone is unavailable.
// Updated by charleyb 07/27/95, per GKG 06/02/95 modifications.

NSR::INT16
NSR::TimeStamp::timeZone(time_t t) const
{
#ifndef NO_TIMEZONE_SUPPORT
    if ( t != -1 ) {            // Must not be bad time
        struct tm *uctp = gmtime(&t);
        if ( uctp ) {           // Must have system support
            struct tm uct_t,loc_t;

            memcpy(&uct_t,gmtime( &t ),sizeof(struct tm));
            memcpy(&loc_t,localtime( &t ),sizeof(struct tm));

            uct_t.tm_isdst = loc_t.tm_isdst;
            INT16 val = ((long)t - (long)mktime(&uct_t)) / 60;

            if ( val >= -1440 && val <= 1440 ) // Must be in valid range
                return (val);
        }
    }
#endif
    return -2047;               // ISO value for unknown tz.
}

NSR::INT32
NSR::TimeStamp::timeDST(time_t t) const
{
    struct tm *tm_t;

    tm_t = localtime(&t);
    return tm_t->tm_isdst;
}

NSR::INT16
NSR::TimeStamp::currentTimeZone() const
{
    time_t now = time( 0 );
    return timeZone(now);
}

NSR::INT32
NSR::TimeStamp::currentDST() const
{
    time_t now = time( 0 );
    return timeDST(now);
}

NSR::TimeStamp &
NSR::TimeStamp::operator=( time_t t )
{
    ttz_.timeZone = timeZone(t);
    struct tm *lt = localtime( &t );

    year_     = lt->tm_year + 1900;
    month_    = lt->tm_mon + 1;
    day_      = lt->tm_mday;
    hour_     = lt->tm_hour;
    minute_   = lt->tm_min;
    second_   = lt->tm_sec;
    centiSeconds_      .clear();
    hectoMicroSeconds_ .clear();
    microSeconds_      .clear();

    return *this;
}

NSR::TimeStamp::operator time_t() const {

    struct tm lt;
    time_t tmp;

    lt.tm_year  = year_ - 1900;
    lt.tm_mon   = month_ - 1;
    lt.tm_mday  = day_;
    lt.tm_hour  = hour_;
    lt.tm_min   = minute_;
    lt.tm_sec   = second_;

    // This calls mktime repeatedly until the system daylight savings
    // time state is the same before and after the call. That way, if
    // the DST changes, the proper value will be used.
    UINT32 tmp_isdst;
    do {
        tmp_isdst   = currentDST();
        lt.tm_isdst = tmp_isdst;
        tmp         = mktime(&lt);
    } while (tmp_isdst != currentDST());

#ifndef NO_TIMEZONE_SUPPORT
    if (ttz_.timeZone != -2047) {
        tmp -= 60*ttz_.timeZone;
        tmp += 60*currentTimeZone();
    }
#endif // NO_TIMEZONE_SUPPORT

    return tmp;
}

void NSR::TimeStamp::clear() {

    ttz_               .clear();
    year_              .clear();
    month_             .clear();
    day_               .clear();
    hour_              .clear();
    minute_            .clear();
    second_            .clear();
    centiSeconds_      .clear();
    hectoMicroSeconds_ .clear();
    microSeconds_      .clear();
}

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

    rbp+=field.start();

    ttz_               .toISO(rbp);
    year_              .toISO(rbp);
    month_             .toISO(rbp);
    day_               .toISO(rbp);
    hour_              .toISO(rbp);
    minute_            .toISO(rbp);
    second_            .toISO(rbp);
    centiSeconds_      .toISO(rbp);
    hectoMicroSeconds_ .toISO(rbp);
    microSeconds_      .toISO(rbp);

}

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

    rbp+=field.start();

    ttz_               .fromISO(rbp);
    year_              .fromISO(rbp);
    month_             .fromISO(rbp);
    day_               .fromISO(rbp);
    hour_              .fromISO(rbp);
    minute_            .fromISO(rbp);
    second_            .fromISO(rbp);
    centiSeconds_      .fromISO(rbp);
    hectoMicroSeconds_ .fromISO(rbp);
    microSeconds_      .fromISO(rbp);
}

// Bytes

NSR::Bytes::Bytes(UINT16 o, UINT16 l) :
    field(o,l),
    value(l)
{}

#ifdef NSR_VERIFY
NSR::Boolean
NSR::Bytes::operator != ( const Bytes & obj ) const
{
    return ( value != obj.value ? True : False );
}
#endif

void
NSR::Bytes::setFieldLen( UINT16 l )
{
    if ( field.len() != l ) {
        value.setLen(l);
        field.len(l);
    }
}

// ZeroBytes

// Dchars

NSR::Dchars::Dchars( UINT16 o ) :
    field(o,0),
    string("") {
}

// NOTE that this changes the field length based upon the length of
// the string....
NSR::Dchars &
NSR::Dchars::operator=( const String &str ) {

    string = str;
    if ( string.length() > 254 ) {
        string.remove(254);
    }
    // zero-length strings handled as zero-length fields.
    UINT16 sl = string.length();
    field.len(sl>0?sl+1:sl);
    return *this;
}

// Since the following is only used at instantiation and on reads, it
// need not do the truncation. However, JUST IN CASE it sees more use,
// truncation is done. NOTE that this leaves Dchars in the only state
// in which the length of the string differs from the field.len. It
// stays in this state until the Dchars field is assigned into. This
// means that if a Dchars field is read in, it will go back out the
// exact same way unless it is altered, even if it could be written
// taking up fewer bytes.

void
NSR::Dchars::setFieldLen( UINT16 l )
{
    if (string.length() > l-1) {
        string.remove( l-1 );
    }
    field.len( l );
}

void
NSR::Dchars::clear()
{
    string.remove(0);
}

void
NSR::Dchars::toISO(BYTE_PTR rbp)
{
    rbp += field.start();
    if (field.len() > 0)
        string.toMemOCU(rbp, field.len());
}

void
NSR::Dchars::fromISO(CONST_BYTE_PTR rbp, CharSetType cst)
{
    rbp += field.start();
    string = String( rbp,field.len(),cst );
}

// RegIDFlags

NSR::RegIDFlags::RegIDFlags ( UINT16 o ) :

    field( o, 1 ),
    dirty    ( 0 ),
    protect  ( 1 ),
    reserved ( 2, 6)
{}

void
NSR::RegIDFlags::clear()
{
    dirty    .clear();          // OSTA 2.1.2.1
    protect  .clear();          // OSTA 2.1.2.1
    reserved .clear();
}

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

    dirty    .toISO( rbp );
    protect  .toISO( rbp );
    reserved .toISO( rbp );
}

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

    dirty    .fromISO( rbp );
    protect  .fromISO( rbp );
    reserved .fromISO( rbp );
}

// RegID

NSR::RegID::RegID ( UINT16 o ) :
    field(o,32),
    flags  (  0 ),
    ID     (  1, 23 ),
    suffix ( 24, 8 )
{
    init();
}

NSR::Error
NSR::RegID::error() const {
    Error err;
    if (( err = ID     .error()) ) return err;
    if (( err = suffix .error()) ) return err;
    return err;
}

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

    bad += ( flags  != obj.flags  );
    bad += ( ID     != obj.ID     );
    bad += ( suffix != obj.suffix );

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

void
NSR::RegID::clear()
{
    flags  .clear();
    ID     .clear();
    suffix .clear();

    init();
}

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

    flags  .toISO(rbp);
    ID     .toISO(rbp);
    suffix .toISO(rbp);
}

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

    flags  .fromISO(rbp);
    ID     .fromISO(rbp);
    suffix .fromISO(rbp);
}

// DomainFlags

NSR::DomainFlags::DomainFlags ( UINT16 o ) :

    field( o, 1 ),
    hardWriteProtect ( 0 ),
    softWriteProtect ( 1 ),
    reserved         ( 2, 6)
{}

void
NSR::DomainFlags::clear()
{
    hardWriteProtect .clear();
    softWriteProtect .clear();
    reserved         .clear();
}

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

    hardWriteProtect .toISO( rbp );
    softWriteProtect .toISO( rbp );
    reserved         .toISO( rbp );
}

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

    hardWriteProtect .fromISO( rbp );
    softWriteProtect .fromISO( rbp );
    reserved         .fromISO( rbp );
}

// DomainRegID

NSR::DomainRegID::DomainRegID ( UINT16 o ) :
    field(o,32),
    flags        (  0 ),
    ID           (  1, 23 ),
    OSTARevision ( 24 ),
    domainFlags  ( 26 ),
    reserved     ( 27,  5 )
{
    init();
}

void
NSR::DomainRegID::init()
{
    ID           = OSTAID ;     // OSTA 2.2.4.4,2.3.2.5
    OSTARevision = OSTARev;     // OSTA 2.1.2.3
}
    
NSR::WriteProtectType
NSR::DomainRegID::writeProtect()
{
    if ( domainFlags.hardWriteProtect )
        return wrprot_Hard;
    if ( domainFlags.softWriteProtect )
        return wrprot_Soft;
    else
        return wrprot_None;
}

void
NSR::DomainRegID::writeProtect( WriteProtectType wpt )
{
    switch(wpt) {
    case wrprot_Soft:
        domainFlags.softWriteProtect = 1;
        domainFlags.hardWriteProtect = 0;
        break;
    case wrprot_Hard:
        domainFlags.softWriteProtect = 0;
        domainFlags.hardWriteProtect = 1;
        break;
    default: // wrprot_None
        domainFlags.softWriteProtect = 0;
        domainFlags.hardWriteProtect = 0;
    }
}

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

    bad += ( flags        != obj.flags         );
    bad += ( ID           != obj.ID            );
    bad += ( OSTARevision != obj.OSTARevision  );
    bad += ( domainFlags  != obj.domainFlags   );
    bad += ( reserved     != obj.reserved      );

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

void
NSR::DomainRegID::clear()
{
    flags        .clear();
    ID           .clear();
    OSTARevision .clear();
    domainFlags  .clear();
    reserved     .clear();

    init();
}

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

    flags        .toISO(rbp);
    ID           .toISO(rbp);
    OSTARevision .toISO(rbp);
    domainFlags  .toISO(rbp);
    reserved     .toISO(rbp);
}

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

    flags        .fromISO(rbp);
    ID           .fromISO(rbp);
    OSTARevision .fromISO(rbp);
    domainFlags  .fromISO(rbp);
    reserved     .fromISO(rbp);
}

// OSTARegID

NSR::OSTARegID::OSTARegID ( UINT16 o ) :
    field(o,32),
    flags        (  0 ),
    ID           (  1, 23 ),
    OSTARevision ( 24 ),
    osClass      ( 26 ),
    osIdentifier ( 27 ),
    reserved     ( 28,  4 )
{
    init();
}

void
NSR::OSTARegID::init()
{
    OSTARevision = DomainRegID::OSTARev; // OSTA 2.1.2.3
    osClass      = writeOSClass      ;
    osIdentifier = writeOSIdentifier ;
}
    
#ifdef NSR_VERIFY
NSR::Boolean
NSR::OSTARegID::operator != ( const OSTARegID & obj ) const
{
    UINT16 bad = 0;

    bad += ( flags        != obj.flags         );
    bad += ( ID           != obj.ID            );
    bad += ( OSTARevision != obj.OSTARevision  );
    bad += ( osClass      != obj.osClass       );
    bad += ( osIdentifier != obj.osIdentifier  );
    bad += ( reserved     != obj.reserved      );

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

void
NSR::OSTARegID::clear()
{
    flags        .clear();
    ID           .clear();
    OSTARevision .clear();
    osClass      .clear();
    osIdentifier .clear();
    reserved     .clear();

    init();
}

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

    flags        .toISO(rbp);
    ID           .toISO(rbp);
    OSTARevision .toISO(rbp);
    osClass      .toISO(rbp);
    osIdentifier .toISO(rbp);
    reserved     .toISO(rbp);
}

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

    flags        .fromISO(rbp);
    ID           .fromISO(rbp);
    OSTARevision .fromISO(rbp);
    osClass      .fromISO(rbp);
    osIdentifier .fromISO(rbp);
    reserved     .fromISO(rbp);
}

// ImplRegID

NSR::ImplRegID::ImplRegID ( UINT16 o ) :
    field(o,32),
    flags        (  0 ),
    ID           (  1, 23 ),
    osClass      ( 24 ),
    osIdentifier ( 25 ),
    descVersion  ( 26 ),
    librVersion  ( 27 ),
    implRegNo    ( 28 ),
    implVersion  ( 30 ),
    implRevision ( 31 )
{
    init();
}

void
NSR::ImplRegID::init()
{
    ID           = HPID              ;
    osClass      = OSTARegID::writeOSClass      ;
    osIdentifier = OSTARegID::writeOSIdentifier ;
    librVersion  = HPVersion         ;
    implRegNo    = UserRegNo         ;
    implVersion  = UserVersion       ;
    implRevision = UserRevision      ;
}
    
NSR::Error
NSR::ImplRegID::error() const {
    Error err;
    err = ID .error();
    return err;
}

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

    bad += ( flags        != obj.flags         );
    bad += ( ID           != obj.ID            );
    bad += ( osClass      != obj.osClass       );
    bad += ( osIdentifier != obj.osIdentifier  );
    bad += ( descVersion  != obj.descVersion   );
    bad += ( librVersion  != obj.librVersion   );
    bad += ( implRegNo    != obj.implRegNo     );
    bad += ( implVersion  != obj.implVersion   );
    bad += ( implRevision != obj.implRevision  );

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

void
NSR::ImplRegID::clear()
{
    flags        .clear();
    ID           .clear();
    osClass      .clear();
    osIdentifier .clear();
    descVersion  .clear();
    librVersion  .clear();
    implRegNo    .clear();
    implVersion  .clear();
    implRevision .clear();

    init();
}

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

    flags        .toISO(rbp);
    ID           .toISO(rbp);
    osClass      .toISO(rbp);
    osIdentifier .toISO(rbp);
    descVersion  .toISO(rbp);
    librVersion  .toISO(rbp);
    implRegNo    .toISO(rbp);
    implVersion  .toISO(rbp);
    implRevision .toISO(rbp);
}

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

    flags        .fromISO(rbp);
    ID           .fromISO(rbp);
    osClass      .fromISO(rbp);
    osIdentifier .fromISO(rbp);
    descVersion  .fromISO(rbp);
    librVersion  .fromISO(rbp);
    implRegNo    .fromISO(rbp);
    implVersion  .fromISO(rbp);
    implRevision .fromISO(rbp);
}

// CharSpec

NSR::CharSpec::CharSpec ( UINT16 o ) :
    field(o,64),
    charSetType_ (  0 ),
    charSetInfo_ (  1, 63 )
{
    init();
}

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

    bad += ( charSetType_ != obj.charSetType_  );
    bad += ( charSetInfo_ != obj.charSetInfo_  );

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

void
NSR::CharSpec::clear()
{
    charSetType_ .clear();
    charSetInfo_ .clear();

    init();
}

// CS0 : OSTA 2.2.8.2.1, 2.2.2.5, 2.2.2.6, 2.2.4.1, 2.3.2.5

void
NSR::CharSpec::init()
{
    charSetType_ = OSTAType;
    charSetInfo_ = OSTAInfo;
}

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

    charSetType_ .toISO(rbp);
    charSetInfo_ .toISO(rbp);
}

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

    charSetType_ .fromISO(rbp);
    charSetInfo_ .fromISO(rbp);
}

// Dstring

NSR::Dstring::Dstring( const UINT16 o, const UINT8 len ) :

    field(o,len),
    nchars ( len - 1 )
{}

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

    bad += ( str    != obj.str     );
    bad += ( nchars != obj.nchars  );

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

void
NSR::Dstring::clear()
{
    str    .remove(0);
    nchars .clear();
}

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

    str    .toMemOCU(rbp,field.len()-1);
    nchars .toISO(rbp);
}

void
NSR::Dstring::fromISO( CONST_BYTE_PTR rbp, CharSetType cst )
{
    rbp += field.start();

    nchars .fromISO(rbp);
    str    = String(rbp,nchars,cst);
    // VERIFY: Dstring violations should be checked here
    // (if anywhere).
}

// LogicalBlockAddr

NSR::LogicalBlockAddr::LogicalBlockAddr( UINT16 o ) :
    field(o,6),
    logicalBlockNo (0),
    partitionRefNo (4)
{}

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

    bad += ( logicalBlockNo != obj.logicalBlockNo  );
    bad += ( partitionRefNo != obj.partitionRefNo  );

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

void
NSR::LogicalBlockAddr::clear()
{
    logicalBlockNo .clear();
    partitionRefNo .clear();
}

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

    logicalBlockNo .toISO(rbp);
    partitionRefNo .toISO(rbp);
}

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

    logicalBlockNo .fromISO(rbp);
    partitionRefNo .fromISO(rbp);
}

// ExtLength

NSR::ExtLength::ExtLength( UINT16 o,
                           ExtType t,
                           UINT32 el ) :
    field(o,4),
    extType_ ( 30,  2, t ),
    length_  (  0, 30, el )
{}

NSR::ExtType
NSR::ExtLength::extType(void) const
{
    if      (extType_ == (UINT32)ext_Recorded) return ext_Recorded;
    else if (extType_ == (UINT32)ext_Allocated) return ext_Allocated;
    else if (extType_ == (UINT32)ext_Unallocated) return ext_Unallocated;
    else return ext_AllocExtent;
}

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

    bad += ( extType_ != obj.extType_ );
    bad += ( length_  != obj.length_  );

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

void
NSR::ExtLength::clear()
{
    extType_ .clear();
    length_  .clear();
}

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

    extType_ .toISO(rbp);
    length_  .toISO(rbp);
}

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

    extType_ .fromISO(rbp);
    length_  .fromISO(rbp);
}

// ShortAllocDesc

NSR::ShortAllocDesc::ShortAllocDesc( UINT16 o ) :

    field(o,8),
    extentLength   ( 0 ),
    extentPosition ( 4 )
{}

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

    bad += ( extentLength   != obj.extentLength    );
    bad += ( extentPosition != obj.extentPosition  );

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

void
NSR::ShortAllocDesc::clear()
{
    extentLength   .clear();
    extentPosition .clear();
}

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

    extentLength   .toISO ( rbp );
    extentPosition .toISO ( rbp );
}

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

    extentLength   .fromISO ( rbp );
    extentPosition .fromISO ( rbp );
}

#ifdef _INCL_SSOBJS_
void
NSR::ShortAllocDesc::toLogExtent( Partition * pp,
                                  LogExtent & le,
                                  Error & err ) const
{
    // ISSUE: Needs a way to set allocated extents to Erased
    // ISSUE:  ShortAD.toLogExtent - Turn on null ptr err.
#ifdef FUTURE
    if (pp == NULL) {
        err = error_Null_pointer;
        return;
    }
#endif
    le.reinit(pp,logBlockNo(),extLength(),err);
    if (!err) {
        if (extType() == ext_Recorded)
            le.extentType(Recorded);
        else if (extType() == ext_Unallocated)  // Unallocated & Unrecorded
            le.extentType(Imaginary);
        else if (extType() == ext_Allocated)
            le.extentType(Unerased);
        else if (extType() == ext_AllocExtent)
            le.extentType(Recorded);
        err = le.error();
    }
}

void
NSR::ShortAllocDesc::fromLogExtent( const LogExtent & le,
                                    Error & err )
{
    clear();
    logBlockNo(le.startBlock());
    extLength(le.infoLen());

    switch (le.extentType()) {
    case Imaginary:
        extType(ext_Unallocated);
        logBlockNo(0);
        break;
    case Recorded:
        extType(ext_Recorded);
        break;
    case Erased:
    case Unerased:
    default:
        extType(ext_Allocated);
    }
}

#endif // _INCL_SSOBJS_

// OSTAADFlags

NSR::OSTAADFlags::OSTAADFlags( UINT16 o ) :
    field(o,2),
    extentErased (  0 ),
    reserved     (  1, 15 )
{
    clear();
}

void
NSR::OSTAADFlags::clear()
{
    extentErased = False;
    reserved     = 0;
}

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

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

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

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

// LongAllocDesc

NSR::LongAllocDesc::LongAllocDesc( UINT16 o ) :
    field(o,16),
    extentLength   (  0 ),
    extentLocation (  4 ),
    flags          ( 10 ),
    implementUse   ( 12, 4 )
{}

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

    bad += ( extentLength   != obj.extentLength   );
    bad += ( extentLocation != obj.extentLocation );
    bad += ( flags          != obj.flags          );
    bad += ( implementUse   != obj.implementUse   );

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

void
NSR::LongAllocDesc::clear()
{
    extentLength   .clear();
    extentLocation .clear();
    flags          .clear();
    implementUse   .clear();
}

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

    extentLength   .toISO( rbp );
    extentLocation .toISO( rbp );
    flags          .toISO( rbp );
    implementUse   .toISO( rbp );
}

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

    extentLength   .fromISO( rbp );
    extentLocation .fromISO( rbp );
    flags          .fromISO( rbp );
    implementUse   .fromISO( rbp );
}

#ifdef _INCL_SSOBJS_
void
NSR::LongAllocDesc::toLogExtent( LogicalVolume * lvp,
                                 LogExtent & le,
                                 Error & err ) const
{
    // ISSUE: Needs a way to set allocated extents to Erased
    // ISSUE:  LongAD.toLogExtent - Turn on null ptr err.
#ifdef FUTURE
    if (lvp == NULL) {
        err = error_Null_pointer;
        return;
    }
#endif
    le.reinit(lvp->partitionp(partRefNo()),logBlockNo(),extLength(),err);
    if (!err) {
        if (extType() == ext_Recorded)
            le.extentType(Recorded);
        else if (extType() == ext_Unallocated)
            le.extentType(Imaginary);
        else if (extType() == ext_Allocated) {
            if (isErased())
                le.extentType(Erased);
            else
                le.extentType(Unerased);
        }
        else if (extType() == ext_AllocExtent)
            le.extentType(Recorded);
        err = le.error();
    }
}

void
NSR::LongAllocDesc::fromLogExtent( const LogExtent & le,
                                   Error & err )
{
    err = error_None;           // At LEAST clear it out..
    
    clear();
    logBlockNo(le.startBlock());
    extLength(le.infoLen());
    partRefNo(le.logVolumep()->partRefNo(le.partitionp()));
    
    switch (le.extentType()) {
    case Imaginary:
        extType(ext_Unallocated);
        logBlockNo(0);
        break;
    case Recorded:
        extType(ext_Recorded);
        break;
    case Erased:
        markErased();
    case Unerased:
    default:
        extType(ext_Allocated);
    }
}

#endif // _INCL_SSOBJS_

// ExtendedAllocDesc

NSR::ExtendedAllocDesc::ExtendedAllocDesc( UINT16 o ) :
    field(o,20),
    extentLength      (  0 ),
    recordedLength    (  4 ),
    informationLength (  8 ),
    extentLocation    ( 12 ),
    flags             ( 18 )
{}

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

    bad += ( extentLength      != obj.extentLength       );
    bad += ( recordedLength    != obj.recordedLength     );
    bad += ( informationLength != obj.informationLength  );
    bad += ( extentLocation    != obj.extentLocation     );
    bad += ( flags             != obj.flags              );

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

void
NSR::ExtendedAllocDesc::clear()
{
    extentLength      .clear();
    recordedLength    .clear();
    informationLength .clear();
    extentLocation    .clear();
    flags             .clear();
}

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

    extentLength      .toISO( rbp );
    recordedLength    .toISO( rbp );
    informationLength .toISO( rbp );
    extentLocation    .toISO( rbp );
    flags             .toISO( rbp );
}

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

    extentLength      .fromISO( rbp );
    recordedLength    .fromISO( rbp );
    informationLength .fromISO( rbp );
    extentLocation    .fromISO( rbp );
    flags             .fromISO( rbp );
}

#ifdef _INCL_SSOBJS_
void
NSR::ExtendedAllocDesc::toLogExtent( LogicalVolume * lvp,
                                     LogExtent & le,
                                     Error & err ) const
{
    // ISSUE: Needs a way to set allocated extents to Erased
    // ISSUE:  ExtendedAD.toLogExtent - Turn on null ptr err.
#ifdef FUTURE
    if (lvp == NULL) {
        err = error_Null_pointer;
        return;
    }
#endif
    // ISSUE: ExtendedAD.toLE: Does NOT support extra extended alloc fields.
    le.reinit(lvp->partitionp(partRefNo()),logBlockNo(),extLength(),err);
    if (!err) {
        if (extType() == ext_Recorded)
            le.extentType(Recorded);
        else if (extType() == ext_Unallocated)
            le.extentType(Imaginary);
        else if (extType() == ext_Allocated) {
            if (isErased())
                le.extentType(Erased);
            else
                le.extentType(Unerased);
        }
        else if (extType() == ext_AllocExtent)
            le.extentType(Recorded);
        err = le.error();
    }
}

void
NSR::ExtendedAllocDesc::fromLogExtent( const LogExtent & le,
                                       Error & err )
{
    // ISSUE: ExtendedAD.fromLE: Does NOT support extra extended alloc fields.
    clear();
    logBlockNo(le.startBlock());
    extLength(le.infoLen());
    partRefNo(le.logVolumep()->partRefNo(le.partitionp()));
    
    switch (le.extentType()) {
    case Imaginary:
        extType(ext_Unallocated);
        logBlockNo(0);
        break;
    case Recorded:
        extType(ext_Recorded);
        break;
    case Erased:
        markErased();
    case Unerased:
    default:
        extType(ext_Allocated);
    }
}

#endif // _INCL_SSOBJS_

// ExtentDesc

NSR::ExtentDesc::ExtentDesc( UINT16 o ) :
    field(o,8),
    length   ( 0 ),
    location ( 4 )
{}

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

    bad += ( length   != obj.length    );
    bad += ( location != obj.location  );

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

void
NSR::ExtentDesc::clear()
{
    length   .clear();
    location .clear();
}

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

    length   .toISO(rbp);
    location .toISO(rbp);
}

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

    length   .fromISO(rbp);
    location .fromISO(rbp);
}

#ifdef _INCL_SSOBJS_

void
NSR::ExtentDesc::toPhysExtent( PhysicalVolume * pvp,
                               PhysExtent & pe,
                               Error & err ) const
{
    pe.reinit(pvp,location,length / pvp->sectorSize(),err);
}

void
NSR::ExtentDesc::fromPhysExtent( const PhysExtent & pe,
                                 Error & err )
{
    err = pe.error();
    if (!err) {
        location = pe.startSector();
        length   = pe.numBytes();
    }
}

#endif // _INCL_SSOBJS_

// DescriptorTag

NSR::DescriptorTag::DescriptorTag( UINT16 o, TagType tid ) :
    field(o,16),
    tagId               (  0 ),
    descriptorVersion   (  2 ),
    tagChecksum         (  4 ),
    reserved            (  5 ),
    tagSerialNo         (  6 ),
    descriptorCRC       (  8 ),
    descriptorCRCLength ( 10 ),
    tagLocation         ( 12 )
{
    tagId = tid;
    descriptorVersion = 2;   // ISO/IEC 13346
}

void
NSR::DescriptorTag::print(CHAR_PTR hdrStr)
{
    printf("\n%s\n",hdrStr);
    printf(" tagId               = %u\n",UINT16(tagId) );
    printf(" descriptorVersion   = %u\n",UINT16(descriptorVersion) );
    printf(" tagChecksum         = %u\n",UINT8(tagChecksum) );
    printf(" reserved            = %u\n",UINT8(reserved) );
    printf(" tagSerialNo         = %u\n",UINT16(tagSerialNo) );
    printf(" descriptorCRC       = %u\n",UINT16(descriptorCRC) );
    printf(" descriptorCRCLength = %u\n",UINT16(descriptorCRCLength) );
    printf(" tagLocation         = %lu\n",UINT32(tagLocation) );
    printf("\n");
}

NSR::TagType
NSR::DescriptorTag::tagIdentifier() const
{
    if      ( tagId == (UINT16)tag_PVD  ) return tag_PVD;
    else if ( tagId == (UINT16)tag_AVD  ) return tag_AVD;
    else if ( tagId == (UINT16)tag_VDP  ) return tag_VDP;
    else if ( tagId == (UINT16)tag_IUVD ) return tag_IUVD;
    else if ( tagId == (UINT16)tag_PD   ) return tag_PD;
    else if ( tagId == (UINT16)tag_LVD  ) return tag_LVD;
    else if ( tagId == (UINT16)tag_USD  ) return tag_USD;
    else if ( tagId == (UINT16)tag_TD   ) return tag_TD;
    else if ( tagId == (UINT16)tag_LVID ) return tag_LVID;
    else if ( tagId == (UINT16)tag_FSD  ) return tag_FSD;
    else if ( tagId == (UINT16)tag_FID  ) return tag_FID;
    else if ( tagId == (UINT16)tag_AED  ) return tag_AED;
    else if ( tagId == (UINT16)tag_IE   ) return tag_IE;
    else if ( tagId == (UINT16)tag_TE   ) return tag_TE;
    else if ( tagId == (UINT16)tag_FE   ) return tag_FE;
    else if ( tagId == (UINT16)tag_EAHD ) return tag_EAHD;
    else if ( tagId == (UINT16)tag_USE  ) return tag_USE;
    else if ( tagId == (UINT16)tag_SBD  ) return tag_SBD;
    else if ( tagId == (UINT16)tag_PIE  ) return tag_PIE;
    else                                  return tag_Unknown;
};
        
//
//  A Uint16 has been used for the tagId field, rather than TagType,
//  which is the name for the enum of all the different tagIds. This
//  is to be consistent with the other fields (i.e., using a field
//  instead of an enum type is consistent), and was chosen after it
//  was determined that there was no net advantage to the enum. This
//  is because the enum provides protection against assignment of a
//  non-enum value into the field. There are not (apparently) any
//  assignments currently, and there should not be in the future.
//
//  If the above function is changed to return a UINT16, the following
//  terser version may be used.
//
//  TagType tagIdentifier() {
//
//      if ((( tagId >= tag_PVD ) && (tagId <= tag_LVID)) ||
//          (( tagId >= tag_FSD ) && (tagId <= tag_PIE)))
//          return tagId;
//      else
//          return tag_Unknown;
//
//    }
//

const NSR::UINT16
NSR::DescriptorTag::crc_table[256]={
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 
    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 
    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 
    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

NSR::UINT16
NSR::DescriptorTag::calcCRC( CONST_BYTE_PTR rbp ) const
{
    UINT16 crc = 0;
    UINT16 n   = 0;

    rbp += 16;     // offset by length of DescriptorTag
    while ( n < descriptorCRCLength )
        crc = crc_table[(crc>>8 ^ rbp[n++]) & 0xff] ^ (crc<<8);
    return crc;
}

NSR::BYTE
NSR::DescriptorTag::checksum( CONST_BYTE_PTR rbp ) const
{
    BYTE i = 0,cksum = 0;
        
    while ( i <= 15 )
        cksum += rbp[i++];
    return cksum - rbp[tagChecksum.field.start()]; // Do not count checksum byte
}

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

    bad += ( tagId                != obj.tagId               );
    bad += ( descriptorVersion    != obj.descriptorVersion   );
    bad += ( tagChecksum          != obj.tagChecksum         );
    bad += ( reserved             != obj.reserved            );
    bad += ( tagSerialNo          != obj.tagSerialNo         );
    bad += ( descriptorCRC        != obj.descriptorCRC       );
    bad += ( descriptorCRCLength  != obj.descriptorCRCLength );
    bad += ( tagLocation          != obj.tagLocation         );

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

void
NSR::DescriptorTag::clear( )
{
    // tagId               (not here)
    descriptorVersion   = 2;
    tagChecksum         .clear( );
    reserved            .clear( );
    tagSerialNo         .clear( );
    descriptorCRC       .clear( );
    descriptorCRCLength .clear( );
    tagLocation         .clear( );
}

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

    tagId               .toISO( rbp );
    descriptorVersion   .toISO( rbp );
        // see tagChecksum below...
    reserved            .toISO( rbp );
    tagSerialNo         .toISO( rbp );

    descriptorCRC = calcCRC( rbp );

    descriptorCRC       .toISO( rbp );
    descriptorCRCLength .toISO( rbp );
    tagLocation         .toISO( rbp );

    tagChecksum = checksum( rbp );

    tagChecksum         .toISO( rbp );
}

// METHOD: DescriptorTag::fromISO()
//
// This operates the same way as any field would.

// METHOD: DescriptorTag::isValid()
//
// This method checks the validity of the tag in question by
//
// 1. Checking its checksum.
// 2. Verifying its location
// 3. Verifying its descriptor Version.
//
// Its signature is as follows:
//         (rbp,location) - tagLocation field checked against supplied
//                          value, plus checked for checksum and CRC
//                          integrity.
//
// Error codes:
//
//     error_None                       - Fine
//     error_Bad_tag_checksum           - tag checksum mismatch
//     error_Bad_tag_location           - tag location field mismatch
//     error_Bad_tag_descriptor_version - Not ISO/IEC 13346
//
// A separate method, hasGoodCRC() calculates a CRC and compares it
// with what is stored in the Tag, setting the following error if it
// they do not match. NOTE that it requires an input parameter which
// is the starting of the area to be CRC'ed.
//
// Error codes:
//
//     error_Bad_descr_CRC              - tag CRC mismatch

// ISSUE: Length for crc calculation should be limited

NSR::Error
NSR::DescriptorTag::hasGoodCRC( CONST_BYTE_PTR rbp ) const
{
    if ( descriptorCRC != calcCRC(rbp) )
        return Error(error_Bad_descr_CRC);
    return Error(error_None);
}

NSR::Error
NSR::DescriptorTag::isValid( CONST_BYTE_PTR rbp, const UINT32 location ) const
{
    if ( tagChecksum != checksum(rbp) )
        return Error(error_Bad_tag_checksum);
    if ( tagLocation != location )
        return Error(error_Bad_tag_location);
    if ( descriptorVersion != 2 )
        return Error(error_Bad_tag_descriptor_version);
    return Error(error_None);
}

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

    tagId               .fromISO( rbp );
    descriptorVersion   .fromISO( rbp );
    tagChecksum         .fromISO( rbp );
    reserved            .fromISO( rbp );
    tagSerialNo         .fromISO( rbp );
    descriptorCRC       .fromISO( rbp );
    descriptorCRCLength .fromISO( rbp );
    tagLocation         .fromISO( rbp );
}



