#ifndef _NSRTYPES_ // -*-c++-*-
#define _NSRTYPES_

//----------------------------------------------------------------------
//  nsrTypes.h
//   Lowest-level descriptor types for ISO/IEC 13346
//
//      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:
//    FieldInfo
//    OpenBytes
//    Uint8
//    Uint16
//    Int16
//    Uint32
//    Uint64
//    Bit8
//    Ubits8
//    Bit16
//    Bits16
//    Ubits16
//    Ubits32
//    TypeTimeZone
//    TimeStamp
//    Bytes
//    ZeroBytes
//    Dchars
//    RegIDFlags
//    RegID
//    DomainFlags
//    DomainRegID
//    ImplRegID
//    OSTARegID
//    CharSpec
//    Dstring
//    LogicalBlockAddr
//    ExtLength
//    ShortAllocDesc
//    OSTAADFlags
//    LongAllocDesc
//    ExtendedAllocDesc
//    ExtentDesc
//    DescriptorTag
//  
//----------------------------------------------------------------------
// $Source: /projects/HMS/nsr/udfCore/descr/nsrTypes.h,v $
// $Revision: 1.34 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/05/23 09:25:49 $
//----------------------------------------------------------------------
// This file defines some of the very basic types utilized in the NSR
// format. All of these types are intended to be used to build the
// higher-level NSR structures. They are NOT general-purpose types,
// and therefore have very limited support for operator overloading,
// etc.

public:

// Class: Field
// 
// All of the fields inside the NSR structures are built out of the
// Field class. It is an abstract base class which captures the
// essense of a field, in that it associates with each instance an
// offset inside of its containing structure. This association is made
// when the field is instantiated. In addition, each field derived
// from it must supply its own functions to translate between the disk
// and memory formats, by overloading the toISO() and fromISO() pure
// virtual functions.
//
// Constructors
//
// Note that since these are NOT general purpose types, their
// constructors REQUIRE an offset and/or a length. Initial values are
// optional. If offsets are not desired, a zero should be passed in.
//
// We tried to make it easy to assign into them, to extract
// information from them, and to compare them with each other or with
// information in a similar type. Because they do not have a default
// constructor, they cannot be passed as arguments or returned from
// function calls.
//
// Responsibilities
//
// These simple types are responsible for translating between their
// memory images and what must go onto the disk to conform with the
// NSR standard. The member functions for this are toISO() and
// fromISO, which are responsible for going to and from the disk
// image, respectively.
//
// Nesting
//
// Fields may be complex, as in containing other fields inside of
// them. As long as toISO() inside the complex field calls toISO() on
// all of its constituent fields, everything will work properly. The
// Uint64 example provided below demonstrates this clearly.
//
// Using Fields
//
// The single argument to the toISO() and fromISO() member functions
// is a byte pointer. This is the location where the ISO structure
// resides or is to reside. For example, if a Uint32 structure called
// lengthOfADs is to be written to an address contained in nsrptr, the
// program should call:
// 
// lengthOfADs.toISO(nsrptr);
//
// In addition, when these fields are instantiated, they may be
// assigned locations or offsets inside their enclosing structure.
// This offset is then used in toISO() and fromISO(). This allows the
// pointer to the enclosing structure to be passed to all of its
// constituent fields when toISO() or fromISO() is called on each of
// them.
//
// For example, consider the simple structure of Uint64, consisting
// of two Uint32 fields. These fields may be instantiated inside the
// Uint64 class as shown below:
//
//     Uint32 lvalue(0);
//     Uint32 hvalue(4);
//
// If this is done, then when Uint64::toISO(nsrptr) is called, it can
// simply do the following:
//
//     lvalue.toISO(nsrptr);
//     hvalue.toISO(nsrptr);
//
// Note that the location of these fields is declared ONLY ONCE -
// rather than in both toISO() and fromISO().
//
// Since Uint64 is a field as well, it will hold its own offset inside
// its containing structure. As long as it adds this offset into its
// supplied toISO() and fromISO() pointers, this property will be
// properly propagated up as high as desired.

// METHOD: Field::Field()
//
//    The Field constructor accepts an offset as its argument. This is
//    the offset into the containing structure of the beginning of
//    that field.
//
// CLEAN: Field class constructor
//
//    The Field class itself does NOT require a field location
//    (offset) to be assigned at construction.  Does ANYONE use it
//    without a field offset at construction time? If not, remove
//    default offset in constructor signature.

// METHOD: Field::toISO
//
//    toISO takes a BYTE_PTR as an argument as the location in memory of
//    the beginning of the enclosing structure of the field. It
//    translates from the Field class in memory to the disk image at
//    the supplied location.

// METHOD: Field::fromISO
//
//    fromISO takes a BYTE_PTR as an argument as the location in memory
//    of the beginning of the enclosing structure of the field. It
//    translates from the disk image at the supplied location to the
//    Field class in memory.

// METHOD: Field::fieldStart()
//
//    The fieldStart() member function is used to set or get the value of
//    the offset. If no arguments, it returns the value. Otherwise, it
//    sets the value of the offset to the value of the argument
//    provided.


class FieldInfo {

protected:

    UINT16 offs;
    UINT16 leng;

    // Make assignment operator and copy constructor private.
    // This will prevent ALL classes containing these from simply
    // doing a memberwise copy or assignment, which is NOT what they
    // want to do anyway.
    FieldInfo& operator=( const FieldInfo & fi ) {
        fprintf(stderr,"FieldInfo Assignment operator called with offs=%d, len=%d\n",
                fi.offs,fi.leng);
        return *this;
    }
    FieldInfo( const FieldInfo & fi ) {
        fprintf(stderr,"FieldInfo Copy Constructor called with offs=%d, len=%d\n",
                fi.offs,fi.leng);
    }

public:

    void len( UINT16 l ) { leng = l; }

    void start( UINT16 o ) { offs = o; }
    UINT16 start() const { return offs; }

    UINT16 len() const { return leng; }
    UINT16 after() const { return offs+leng; }

    FieldInfo( UINT16 o, UINT16 l ) { offs = o; leng = l; }

};

// Class: OpenBytes
//
// The OpenBytes class may be used on its own inside a descriptor. It
// becomes a placeholder, having everything needed except any data
// contents and to/fromISO. 
//
// It is useful for allowing other fields to be mapped inside of a
// portion of an enclosing structure. This may be done inside of a
// class, or in a derived class. This class has been designed to
// facilitate the imposition of specific meaning upon implementation
// use fields, and other variable-content fields in ISO.
//
// NOTE that OpenBytes do not support assignment, and only support
// retrieving the fieldStart and length via the fieldStart() and
// field.len() methods. They ARE, however, variable length, supporting
// the field.len(len) method.
//
// An example of how it should be used when a special class is derived
// from a base class containing an OpenBytes member is shown below:
//
// class MyGenericDesc : TaggedDescriptor {
//     Uint16    descNum ;
// public:
//     OpenBytes impUse  ;
//     MyGenericDesc() :
//         descNum ( 0 ),
//         impUse  ( 2, 4 ) {}
//     toISO(BYTE_PTR rbp) {
//         descNum.toISO(rbp);
//      // NOTE: no toISO for impUse!
//     }
//     ...
// class MySpecialDesc : MyGenericDesc {
//     Uint16 myInfo1;
//     Uint16 myInfo2;
// public:
//     MySpecialDesc () : // Because derived, only need to mention my
//                        // unique fields. Others are done in base
//                        // class. 
//         myInfo1 ( impUse.field.start() + 0 ),
//         myInfo2 ( impUse.field.start() + 2 ) {}
//     toISO(BYTE_PTR rbp) {
//         MyGenericDesc::toISO(rbp); // MUST to base toISO()
//         myInfo1.toISO(rbp);   // Order is not important here
//         myInfo2.toISO(rbp);
//     }
//     ...

class OpenBytes {

public:
    FieldInfo field;

    void setfieldLen( UINT16 l ) { field.len(l); }

    OpenBytes( UINT16 o, UINT16 l ) :
        field( o, l){
    }


};

// Class: Uint8
// Class: Int8
// Class: Uint16
// Class: Int16
// Class: Uint32
// Class: Int32
//
// These are simple fields, requiring an offset when instantiated, and
// suitable only for inclusion inside other structures (classes). They
// all support assignment from and casting into values of their
// corresponding non-field types. (For example, Uint16 is the field
// type corresponding to UINT16.)
//
// Byte Swapping
//
// Each of these fields performs the appropriate byte swapping, if
// required, inside the toISO() and fromISO() methods. This is, of
// course, a fundamental part of mapping the memory images of these
// types to their on-disk images. The standard requires little-endian
// (like Intel) representations, which may not match native
// representations.
//
// This implementation never converts between disk and memory
// images in place, but rather always copies between the two. During
// the copy, it moves information inside these fields a byte at a
// time such that the two representations are correct.
//
// This avoids the messiness of compile-time flags telling the code to
// do the swap or not, as well as the complexity of the ifdefs.
//
// CLEAN: Unused UintXX, IntXX constructors
//
//    If no one is using the constructors which supply a value as
//    well as an offset, these should be removed.

class Uint8 {

public:
    FieldInfo field;
private:
    UINT8 value;  
public:
    Uint8( UINT16 o ) :
        field(o,1),
        value(0){
    }
    Uint8 & operator=(UINT8 v) {
        value = v;
        return *this;
    }
    Uint8 & operator&=(UINT8 x) { value &= x; return *this; }
    Uint8 & operator|=(UINT8 x) { value |= x; return *this; }
    operator UINT8() const { return value; }
    void clear() { value = 0; }
    void toISO( BYTE_PTR rbp ) { *(rbp+field.start()) = value; }
    void fromISO( CONST_BYTE_PTR rbp ) { value = *(rbp+field.start()); }
};

class Int8 {

public:
    FieldInfo field;
private:
    INT8 value;  
public:
    Int8( UINT16 o ) :
        field(o,1),
        value(0){
    }
    Int8 & operator=(INT8 v) {
        value = v;
        return *this;
    }
    Int8 & operator&=(INT8 x) { value &= x; return *this; }
    Int8 & operator|=(INT8 x) { value |= x; return *this; }
    operator INT8() const { return value; }
    void clear() { value = 0; }
    void toISO( BYTE_PTR rbp ) { *(rbp+field.start()) = value; }
    void fromISO( CONST_BYTE_PTR rbp ) {
        value = *(rbp+field.start());
        // Sign extend
        if (rbp[0] & 0x80)
            value = (INT8)(value | ~0xffUL);
    }
};

class Uint16 {

public:
    FieldInfo field;
private:
    UINT16 value;  
public:
    Uint16( UINT16 o ) :
        field(o,2),
        value(0) {
    }
    Uint16 & operator=(UINT16 v) {
        value = v;
        return *this;
    }
    operator UINT16() const { return value; }
    Uint16 & operator&=(UINT16 x) { value &= x; return *this; }
    Uint16 & operator|=(UINT16 x) { value |= x; return *this; }
    Uint16 & operator+=(UINT16 x) { value += x; return *this; }
    Uint16 & operator-=(UINT16 x) { value -= x; return *this; }
    
    void clear() { value = 0; }

    void toISO( BYTE_PTR rbp ) {
        rbp += field.start();
        rbp[0] = (UINT8)(value & 0x00ffL);
        rbp[1] = (UINT8)((value >> 8) & 0x00ffL);
    }
    void fromISO( CONST_BYTE_PTR rbp ) {
        rbp += field.start();
        value = (UINT16)(((rbp[1] &0xffL) << 8) |
                         (rbp[0] & 0xffL));
    }
};

class Int16 {

public:
    FieldInfo field;
private:
    INT16 value;  
public:
    Int16( UINT16 o ) :
        field(o,2),
        value(0){
    }
    Int16 & operator=(INT16 v) {
        value = v;
        return *this;
    }

    operator INT16() const { return value; }
    Int16 & operator&=(INT16 x) { value &= x; return *this; }
    Int16 & operator|=(INT16 x) { value |= x; return *this; }
    Int16 & operator+=(INT16 x) { value += x; return *this; }
    Int16 & operator-=(INT16 x) { value -= x; return *this; }

    void clear() { value = 0; }

    void toISO( BYTE_PTR rbp ) {

        rbp += field.start();

        rbp[0] = (UINT8)( value       & 0xffL);
        rbp[1] = (UINT8)((value >> 8) & 0xffL);
    }

    void fromISO( CONST_BYTE_PTR rbp ) {

        rbp += field.start();

        value = (UINT16)(((rbp[1] & 0xffL) << 8) |
                         (rbp[0] & 0xffL));
        // Sign extend
        if (rbp[1] & 0x80)
            value = (INT16)(value | ~0xffffUL);
    }
};


class Uint32 {

public:
    FieldInfo field;
private:
    UINT32 value;  
public:
    Uint32( UINT16 o = 0 ) :    // to support Uint32Table
        field(o,4),
        value(0){
    }
    Uint32 & operator=(UINT32 v) {
        value = v;
        return *this;
    }

    operator UINT32() const { return value; }
    Uint32 & operator&=(UINT32 x) { value &= x; return *this; }
    Uint32 & operator|=(UINT32 x) { value |= x; return *this; }
    Uint32 & operator+=(UINT32 x) { value += x; return *this; }
    Uint32 & operator-=(UINT32 x) { value -= x; return *this; }

    void clear() { value = 0; }

    void toISO( BYTE_PTR rbp ) {

        rbp += field.start();

        rbp[0] = (UINT8)( value        & 0xffL);
        rbp[1] = (UINT8)((value >>  8) & 0xffL);
        rbp[2] = (UINT8)((value >> 16) & 0xffL);
        rbp[3] = (UINT8)((value >> 24) & 0xffL);
    }

    void fromISO( CONST_BYTE_PTR rbp ) {

        rbp += field.start();

        value = (((rbp[3] & 0xffL) << 24) |
                 ((rbp[2] & 0xffL) << 16) |
                 ((rbp[1] & 0xffL) <<  8) |
                 ( rbp[0] & 0xffL) );
    }
};

class Int32 {

public:
    FieldInfo field;
private:
    INT32 value;  
public:
    Int32( UINT16 o = 0 ) :    // to support Int32Table
        field(o,4),
        value(0){
    }
    Int32 & operator=(INT32 v) {
        value = v;
        return *this;
    }

    operator INT32() const { return value; }
    Int32 & operator&=(INT32 x) { value &= x; return *this; }
    Int32 & operator|=(INT32 x) { value |= x; return *this; }
    Int32 & operator+=(INT32 x) { value += x; return *this; }
    Int32 & operator-=(INT32 x) { value -= x; return *this; }

    void clear() { value = 0; }

    void toISO( BYTE_PTR rbp ) {

        rbp += field.start();

        rbp[0] = (UINT8)( value        & 0xffL);
        rbp[1] = (UINT8)((value >>  8) & 0xffL);
        rbp[2] = (UINT8)((value >> 16) & 0xffL);
        rbp[3] = (UINT8)((value >> 24) & 0xffL);
    }

    void fromISO( CONST_BYTE_PTR rbp ) {

        rbp += field.start();

        value = (((rbp[3] & 0xffL) << 24) |
                 ((rbp[2] & 0xffL) << 16) |
                 ((rbp[1] & 0xffL) <<  8) |
                 ( rbp[0] & 0xffL) );
    }
};

// Class: Uint64
//
// The Uint64 class is a 64-bit field holding an unsigned number.
//
// It does not (yet) support any arithmetic, although it could be
// changed to do that. Instead, it simply supports access to its value
// via assignment (from a UINT32, which gets placed into its less
// significant 32 bits, as well as through the member functions low()
// and high(). No casting operator to UINT32, for example, is
// provided.
//
// Note that this is a good example of a nested class, as it consists
// of two Uint32 fields.
//
// METHOD: Uint64::Uint64()
// METHOD: Uint64::operator=()
// METHOD: Uint64::toISO()
// METHOD: Uint64::fromISO()
// METHOD: Uint64::field.len()

// METHOD: Uint64::low()
// METHOD: Uint64::high()
//
// If called with no arguments, these return the low and high 32 bits
// of the 64-bit value, respectively. If they are supplied with a
// UINT32 value as an argument, they set the fields appropriately.

class Uint64 {

public:
    FieldInfo field;
private:
    Uint32 lval;
    Uint32 hval;
public:
    Uint64( UINT16 o );
    Uint64 & operator=(UINT32 v);
    UINT32  low() const { return lval; }
    UINT32 high() const { return hval; }
    void  low( UINT32 lv ) { lval = lv; }
    void high( UINT32 hv ) { hval = hv; }

#ifdef NSR_VERIFY
    Boolean operator !=( const Uint64 & obj ) const;
#endif
    // CSB added 10/10/95.
    // operator ::UINT64(void) const { return UINT64(lval, hval); }
    operator UINT32(void) const { return lval; }

    void clear() { hval = 0; lval = 0; }
    void toISO( BYTE_PTR rbp );
    void fromISO( CONST_BYTE_PTR rbp );
};

// Class: Bit
// Class: Ubits8
// Class: Ubits16
// Class: Bits16
// Class: Ubits32
// Class: Bits32
//
// These are fields which do not fall on byte boundaries. Their
// offsets and lengths, required at instantiation, are in bits, rather
// than bytes.
//
// They USE USE one of the other Uints/Ints in order to read and write
// to and from ISO. Note that if a 32-bit field is split into pieces,
// it should instantiate multiple Ubits32 fields inside of itself.
//
// They do no checking for overlap, etc. The offset is from the LSB
// into the containing field.
// 
// They support casting into their corresponding UINT types, as well
// as assigment from those types.
//
// The toISO() and fromISO() methods still accept a byte pointer, as
// all the others. (i.e., rbp is not a bit pointer).

class Bit8 {

public:
    FieldInfo field;
private:
    UINT8 value;
public:

    Bit8( UINT16 o ) :
        field(o,1),
        value(0) {
    }
    Bit8 & operator=(UINT8 v) {
        value = v != 0 ? (1 << field.start()) : 0;
        return *this;
    }
    operator UINT8() const {
        return value;
    }

    void clear() { value = 0; }

    void toISO( BYTE_PTR rbp ) {
        Uint8 temp(0);
        temp.fromISO(rbp);
        temp &= ~(1 << field.start());
        temp |= value;
        temp.toISO(rbp);
    }
            
    void fromISO( CONST_BYTE_PTR rbp ) {
        Uint8 temp(0);
        temp.fromISO(rbp);
        value = (temp & (1 << field.start()));
    }

};

class Ubits8 {

public:
    FieldInfo field;
private:
    UINT8 value;
    UINT8 mask;
public:

    Ubits8( UINT16 o, UINT8 len ) :
        field(o,1),
        value(0){
        mask = ((UINT8)(~(UINT8)0 << (8 - len)) >> (8 - len));
    }
    Ubits8 & operator=(UINT8 v) {
        value = v & mask;
        return *this;
    }
    operator UINT8() const { return value; }

    void clear() { value = 0; }

    void toISO( BYTE_PTR rbp ) {
        Uint8 temp(0);
        temp.fromISO(rbp);
        temp &= ~(mask << field.start());
        temp |= (value << field.start());
        temp.toISO(rbp);
    }
            
    void fromISO( CONST_BYTE_PTR rbp ) {
        Uint8 temp(0);
        temp.fromISO(rbp);
        value = (temp >> field.start()) & mask;
    }

};

class Bit16 {

public:
    FieldInfo field;
private:
    UINT16 value;
public:
    Bit16( UINT16 o ) :
        field(o,2),
        value(0){
    }
    Bit16 & operator=(UINT8 v) {
        value = v != 0 ? (1 << field.start()) : 0;
        return *this;
    }
    operator UINT16() const {
        return (value ? 1 : 0) ;
    }
    void clear() { value = 0; }

    void toISO( BYTE_PTR rbp ) {
        Uint16 temp(0);
        temp.fromISO(rbp);
        temp &= ~(1 << field.start());
        temp |= value;
        temp.toISO(rbp);
    }
            
    void fromISO( CONST_BYTE_PTR rbp ) {
        Uint16 temp(0);
        temp.fromISO(rbp);
        value = (temp & (1 << field.start()));
    }

};

class Bits16 {

public:
    FieldInfo field;
private:
    INT16 value;
    UINT16 mask;
    UINT16 smask; // Sign mask
public:
    Bits16( UINT16 o, UINT8 len, INT16 v = 0 ) :
        field(o,2){
        mask  = ((UINT16)(~(UINT16)0 << (16 - len)) >> (16 - len));
        smask = 1 << (len-1);
        value = v<0?(v|~mask):(v&mask);
        }
    Bits16 & operator=(INT16 v) {
        value = v<0?(v|~mask):(v&mask);
        return *this;
    }
    operator INT16() const { return value; }
    void clear() { value = 0; }
    void toISO( BYTE_PTR rbp ) {
        Uint16 temp(0);
        temp.fromISO(rbp);
        temp &= ~(mask << field.start());
        temp |= ((value&mask) << field.start());
        temp.toISO(rbp);
    }
            
    void fromISO( CONST_BYTE_PTR rbp ) {
        Uint16 temp(0);
        temp.fromISO(rbp);
        value = (temp >> field.start());
        value = value&smask?(value|~mask):(value&mask);
    }

};

class Ubits16 {

public:
    FieldInfo field;
private:
    UINT16 value;
    UINT16 mask;
public:
    Ubits16( UINT16 o, UINT8 len, UINT16 v = 0 ) :
        field(o,2){
        mask = ((UINT16)(~(UINT16)0 << (16 - len)) >> (16 - len));
        value = v & mask;
    }
    Ubits16 & operator=(UINT16 v) {
        value = v & mask;
        return *this;
    }
    // CSB added 9-8-95.
    UINT16 operator&(UINT16 v) const {
        return (value & v);
    }
    // CSB added 9-6-95.  Is this correct, DVM?
    const Ubits16& operator |=(UINT16 v) {
        value |= (v & mask);
        return *this;
    }
    // CSB added 9-6-95.  Is this correct, DVM?
    const Ubits16& operator &=(UINT16 v) {
        value &= (v & mask);
        return *this;
    }
    operator UINT16() const { return value; }
    void clear() { value = 0; }
    void toISO( BYTE_PTR rbp ) {
        Uint16 temp(0);
        temp.fromISO(rbp);
        temp &= ~(mask << field.start());
        temp |= (value << field.start());
        temp.toISO(rbp);
    }
            
    void fromISO( CONST_BYTE_PTR rbp ) {
        Uint16 temp(0);
        temp.fromISO(rbp);
        value = (temp >> field.start()) & mask;
    }

};

class Ubits32 {

public:
    FieldInfo field;
private:
    UINT32 value;
    UINT32 mask;
public:
    Ubits32( UINT16 o, UINT8 len, UINT32 v = 0 ) :
        field(o,4){
        mask = ((UINT32)(~(UINT32)0 << (32 - len)) >> (32 - len));
        value = v & mask;
    }
    Ubits32 & operator=(UINT32 v) {
        value = v & mask;
        return *this;
    }
    // CSB added 9-8-95.
    UINT32 operator&(UINT32 v) const {
        return (value & v);
    }
    // CSB added 9-8-95.  Is this correct, DVM?
    const Ubits32& operator |=(UINT32 v) {
        value |= (v & mask);
        return *this;
    }
    // CSB added 9-8-95.  Is this correct, DVM?
    const Ubits32& operator &=(UINT32 v) {
        value &= (v & mask);
        return *this;
    }
    operator UINT32() const { return value; }
    void clear() { value = 0; }
    void toISO( BYTE_PTR rbp ) {
        Uint32 temp(0);
        temp.fromISO(rbp);
        temp &= ~(mask << field.start());
        temp |= (value << field.start());
        temp.toISO(rbp);
    }
            
    void fromISO( CONST_BYTE_PTR rbp ) {
        Uint32 temp(0);
        temp.fromISO(rbp);
        value = (temp >> field.start()) & mask;
    }

};

// Class: TypeTimeZone
//
// The TypeTimeZone class holds the time zone type and time zone
// according to NSR (13346 1/7.3). It is a field with two sub fields,
// and is instantiated only inside the TimeStamp class.
//
// METHOD: TypeTimeZone::TypeTimeZone()
// METHOD: TypeTimeZone::field.len()
// METHOD: TypeTimeZone::toISO()
// METHOD: TypeTimeZone::fromISO()

class TypeTimeZone {

public:
    FieldInfo field;

    Ubits16 tzType   ;
    Bits16  timeZone ;
private:
    void init() ;
public:
    
    TypeTimeZone(UINT16 o) ;
    void clear() ;
    void toISO(BYTE_PTR rbp) ;
    void fromISO(CONST_BYTE_PTR rbp) ;
};

// Class: TimeStamp
//
// The TimeStamp class is a composite field, intended to be
// instantiated inside another structure.
//
// Access to the different fields is provided through the Time class.
// 
// TimeStamps may be cast into a Time class, and Time instances may be
// assigned into TimeStamps.
//
// The type and timezone field have been split out into two separate
// fields to make them easier to access. They are collapsed together
// only when toISO() is called. 
// 
// METHOD: TimeStamp::TimeStamp()
// METHOD: TimeStamp::operator=()
// METHOD: TimeStamp::Time()
// METHOD: TimeStamp::field.len()
// METHOD: TimeStamp::toISO()
// METHOD: TimeStamp::fromISO()
//
// CLEAN: TimeStamp type, timeZone
//
// If it is no more awkward to use, type and timezone should be
// offered as methods, rather than as publicly accessible fields.

class TimeStamp {

public:
    FieldInfo field;
private:
    TypeTimeZone ttz_               ;
    Int16        year_              ;
    Uint8        month_             ;
    Uint8        day_               ;
    Uint8        hour_              ;
    Uint8        minute_            ;
    Uint8        second_            ;
    Uint8        centiSeconds_      ;
    Uint8        hectoMicroSeconds_ ;
    Uint8        microSeconds_      ;

    INT16 timeZone(time_t t) const;
    INT32 timeDST(time_t t) const;

    INT16 currentTimeZone() const;
    INT32 currentDST() const;
    
public:

    TimeStamp( UINT16 o ) ;

    INT16 timeZone()          const { return ttz_.timeZone; }
    INT16 year()              const { return year_; }
    UINT8 month()             const { return month_; }
    UINT8 day()               const { return day_; }
    UINT8 hour()              const { return hour_; }
    UINT8 minute()            const { return minute_; }
    UINT8 second()            const { return second_; }
    UINT8 centiSeconds()      const { return centiSeconds_; }
    UINT8 hectoMicroSeconds() const { return hectoMicroSeconds_; }
    UINT8 microSeconds()      const { return microSeconds_; }

    TimeStamp & operator=( time_t t );
    operator time_t() const ;

    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

};

// Class: Bytes
//
// The Bytes class is a fixed length field which is interpreted as a
// number of bytes. No meaning is imposed on the bytes, and access to
// them is through casting the field to a BYTE_PTR. This returns a
// pointer to the beginning of the bytes in the field. When this field
// is toISO()ed and fromISO()ed, the bytes are simply copied to and
// from the supplied pointer, taking into account the length and
// offset associated with the field.
//
// This field is suitable for mapping other fields inside of it, but
// has the built-in inefficiency of being the target for the toISO()
// of the mapped fields, and the source for its own toISO() (which
// goes to the supplied byte pointer). For the more efficient scheme,
// use the Field class directly.
//
// This class, like all the other fields, supports toISO() and
// fromISO(), and holds inside of itself a length of BYTEs and an
// offset.
// 
// METHOD: Bytes::Bytes()
// METHOD: Bytes::field.len()
// METHOD: Bytes::operator BYTE_PTR()
// METHOD: Bytes::field.len BYTE_PTR()
// METHOD: Bytes::toISO()
// METHOD: Bytes::fromISO()

class Bytes {

public:
    FieldInfo field;
private:
    SmallByteArray value;
public:

    Bytes(UINT16 o, UINT16 l);
    void setFieldLen( UINT16 l);

//  Bytes & operator=( const SmallByteArray &obj ) { value = obj; return *this;}
//  operator SmallByteArray() const { return value; }

    Bytes & operator=( const String &str )
    {
        value = str;
        return *this;
    }
    operator String() const { return String(value); }

    operator BYTE_PTR() { return (BYTE_PTR)value; }
//  operator CHAR_PTR() const { return (CHAR_PTR)((BYTE_PTR)value); }
    Error error() const { return value.error(); }

#ifdef NSR_VERIFY
    Boolean operator !=( const Bytes & obj ) const ;
#endif

    void clear() {
        value.clear();
    }

    void toISO( BYTE_PTR rbp ) {
        rbp += field.start();
        value.toMem(rbp);
    }

    void fromISO( CONST_BYTE_PTR rbp ) {
        rbp += field.start();
        value.fromMem(rbp);
    }
};

// Class: ZeroBytes
//
// The ZeroBytes class is a fixed length field which only ever and
// always writes zeros. It (for now) ignores the contents of the field
// on fromISO(). No access to these fields is provided.
//
// METHOD: ZeroBytes::ZeroBytes()
// METHOD: ZeroBytes::field.len()
// METHOD: ZeroBytes::toISO()
// METHOD: ZeroBytes::fromISO()

class ZeroBytes {

public:
    FieldInfo field;
    void setFieldLen( UINT16 l ) { field.len(l); }
    ZeroBytes( UINT16 o, UINT16 l ) :
        field(o,l) {
    }

#ifdef NSR_VERIFY
    Boolean operator != ( const ZeroBytes & obj ) const {
        return False;
    }
#endif

    void clear() {}
    
    void toISO( BYTE_PTR rbp ) {

        rbp += field.start();
        memset( rbp, 0, field.len() );
    }

    void fromISO( CONST_BYTE_PTR rbp ) {

        rbp += field.start();
    }

};        

// Class: Dchars
//
// The Dchars class is a fixed length field which supports simple
// conversion to and from a string, as well as CHAR_PTR. Its constructor
// requires a field location and a length, which never changes.
// 
// METHOD: Dchars::Dchars()
// METHOD: Dchars::field.len()
// METHOD: Dchars::operator String()
// METHOD: Dchars::operator CHAR_PTR()
// METHOD: Dchars::toISO()
// METHOD: Dchars::fromISO()

class Dchars {

public:
    FieldInfo field;
private:
    String string;
public:

    Dchars(UINT16 o);
    Dchars & operator=( const String &str );

    void setFieldLen( UINT16 l) ;

    operator String() const { return string; }
    Error error() const { return string.error(); }

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

    void clear();
    void toISO(BYTE_PTR rbp) ;
    void fromISO(CONST_BYTE_PTR rbp, CharSetType cst) ;
};

//----------------------------------------------------------------------
// ENUM: UserRegistration
//
//  Registered users of HP UDF.
//
// DEFINITIONS:
//  ureg_HP_Test            descr
//  ureg_HP_ArchiveServer   descr
//  ureg_SoftwareArchitects descr
//
// USES:
//  One of these values should be placed into the
//  NSR::ImplRegID::implRegNo static.
//
// NOTES:
//  This is not necessarily an exhaustive list.
//
//----------------------------------------------------------------------
// Private comments go here - will not be extracted into HTML.
//----------------------------------------------------------------------
enum UserRegistration {
    ureg_HP_Test                  =  0,
    ureg_HP_ArchiveServer         = 10,
    ureg_SoftwareArchitects       = 20
};

//----------------------------------------------------------------------
// ENUM: OSClass
//
//  Valid UDF-defined OS Classes, used in RegIDs.
//
// DEFINITIONS:
//  osclass_Undefined   Not specified
//  osclass_DOS         DOS and Windows
//  osclass_OS2         OS/2
//  osclass_Macintosh   Macintosh OS
//  osclass_Unix        Unix
//
// USES:
//  Used to test and set the osClass field in RegIDs.
//
//----------------------------------------------------------------------
// Private comments go here - will not be extracted into HTML.
//----------------------------------------------------------------------
enum OSClass {
    osclass_DOS       = 1,
    osclass_OS2       = 2,
    osclass_Macintosh = 3,
    osclass_Unix      = 4
};

//----------------------------------------------------------------------
// ENUM: OSIdentifier
//
//  Valid UDF-defined OS Identifiers, used in RegIDs.
//
// DEFINITIONS:
//  osid_Generic       Not specified
//  osid_IBM_AIX       AIX operating system
//  osid_SUN_Solaris   Solaris
//  osid_HP_UX         HP-UX
//  osid_SGI_Irix      Irix
//
// USES:
//  Used to test and set osIdentifier fields in RegIDs.
//
// NOTES:
//  optional
//
//----------------------------------------------------------------------
// Private comments go here - will not be extracted into HTML.
//----------------------------------------------------------------------
enum OSIdentifier {
    osid_Generic     = 0,
    osid_IBM_AIX     = 1,
    osid_SUN_Solaris = 2,
    osid_HP_UX       = 3,
    osid_SGI_Irix    = 4
};
    
// Class: RegIDFlags
//
// The RegIDFlags class is a base class which does nothing more than to
// provide three open fields, for an implementation to define and use.
//
// METHOD: RegIDFlags::RegIDFlags()
// METHOD: RegIDFlags::field.len()
// METHOD: RegIDFlags::field.after()
// METHOD: RegIDFlags::toISO()
// METHOD: RegIDFlags::fromISO()

class RegIDFlags {

public:
    FieldInfo field;
    Bit8      dirty;
    Bit8      protect;
    Ubits8    reserved;

    RegIDFlags( UINT16 o ) ;

#ifdef NSR_VERIFY
    Boolean operator != ( const RegIDFlags & obj ) const {
        return ( (dirty != obj.dirty) || (protect != obj.protect) ?
                 True : False ) ;
    }
    
#endif
        
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

};

// ISSUE: RegIDs need UNIFIED source for IDs
// static const data member should be set to our implementation ID.
// Then, RegID may support a method checking to see whether it matches
// our implementation.
// Proposed methods:
//   void  markThisImplementation()
//   Boolean isThisImplementation()
// Domain identifiers should be handled likewise:
//   void  markThisDomain()
//   Boolean isThisDomain()

// Class: RegID
//
// The RegID class enforces the OSTA requirements for RegIDs. It
// allows access (currently) only to the Identifier field, and does
// NOT allow access to the suffix (OSTA specifies what this should
// be).
//
// METHOD: RegID::RegID()
// METHOD: RegID::field.len()
// METHOD: RegID::field.after()
// METHOD: RegID::toISO()
// METHOD: RegID::fromISO()

class RegID {

public:
    FieldInfo field;
protected:
    RegIDFlags flags  ;
    Bytes      ID     ;
    Bytes      suffix ;

public:

    RegID ( UINT16 o ) ;

    Boolean isDirty() const { return flags.dirty ? True : False; }
    Boolean isProtected()   { return flags.protect ? True : False; }

    void id( const String & ident ) { ID = ident; }
    String id() const { return String(ID); }

    void init() {}
    Error error() const ;

#ifdef NSR_VERIFY
    Boolean operator != ( const RegID & obj ) const ;
#endif
        
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;
};

// The following struct holds all of the information to be stuffed
// into the DomainRegId.

class DomainFlags {

public:
    FieldInfo field;
    Bit8      hardWriteProtect ;
    Bit8      softWriteProtect ;
    Ubits8    reserved         ;

    DomainFlags( UINT16 o ) ;

#ifdef NSR_VERIFY
    Boolean operator != ( const DomainFlags & obj ) const {
        return ( (hardWriteProtect != obj.hardWriteProtect) ||
                 (softWriteProtect != obj.softWriteProtect) ?
                 True : False ) ;
    }
    
#endif
        
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

};

enum WriteProtectType {
    wrprot_None,
    wrprot_Soft,
    wrprot_Hard
};

class DomainRegID {

public:
    FieldInfo field;
protected:
    RegIDFlags  flags        ;
    Bytes       ID           ;
    Uint16      OSTARevision ;
    DomainFlags domainFlags  ;
    ZeroBytes   reserved     ;

    static String HPEarlyID1 ;  // We DID use this for writing
    static String HPEarlyID2 ;  // We DID use this for writing
    static String OSTAID     ;  // We use this for writing

public:

    static UINT16 OSTARev    ;  // We use this in OSTARegID also.

    DomainRegID ( UINT16 o ) ;

    Boolean isUDF(void) {
        return ((String)ID == OSTAID)? True : False;
    }
    Boolean isEarlyHP(void) {
        return (((String)ID == HPEarlyID1) ||
                ((String)ID == HPEarlyID2))? True : False;
    }
    
    Boolean isDirty() const { return flags.dirty ? True : False; }
    Boolean isProtected()   { return flags.protect ? True : False; }

    String id() const { return String(ID); }

    WriteProtectType writeProtect() ;
    void writeProtect(WriteProtectType wpt) ;

    void init() ;
    Error error() const { return ID.error(); }

#ifdef NSR_VERIFY
    Boolean operator != ( const DomainRegID & obj ) const ;
#endif
        
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;
};

class OSTARegID {

public:
    FieldInfo field;
protected:
    RegIDFlags flags        ;
    Bytes      ID           ;
    Uint16     OSTARevision ;
    Uint8      osClass      ;
    Uint8      osIdentifier ;
    ZeroBytes  reserved     ;

public:

    // The following statics are used by the ImplRegID and the
    // OSTARegID. They must be instantiated and initialized by the
    // using implementation. See config/nsrStat.h for details.

    static UINT8  writeOSClass;
    static UINT8  writeOSIdentifier;

    OSTARegID ( UINT16 o ) ;

    Boolean isDirty() const { return flags.dirty ? True : False; }
    Boolean isProtected()   { return flags.protect ? True : False; }

    void id( const String & ident ) { ID = ident; }
    String id() const { return String(ID); }

    void init() ;
    Error error() const { return ID.error(); }

#ifdef NSR_VERIFY
    Boolean operator != ( const OSTARegID & obj ) const ;
#endif
        
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;
};

class ImplRegID {

public:
    FieldInfo  field;
protected:
    RegIDFlags flags        ;
    Bytes      ID           ;
    Uint8      osClass      ;
    Uint8      osIdentifier ;
    Uint8      descVersion  ;
    Uint8      librVersion  ;
    Uint16     implRegNo    ;
    Uint8      implVersion  ;
    Uint8      implRevision ;

public:

    static String HPID;
    static String HPEarlyID;
    static UINT8  HPVersion;

    static UINT16 UserRegNo;
    static UINT8  UserVersion;
    static UINT8  UserRevision;

    ImplRegID ( UINT16 o ) ;

    void   descVersionNo( UINT8 v ) { descVersion = v; }

    Boolean isDirty() const { return flags.dirty   ? True : False; }
    Boolean isProtected()   { return flags.protect ? True : False; }

    String id() const { return String(ID); }

    UINT8  osClassId()      const { return osClass      ; }
    UINT8  osId()           const { return osIdentifier ; }
    UINT8  descVersionNo()  const { return descVersion  ; }
    UINT8  librVersionNo()  const { return librVersion  ; }
    UINT16 implRegistrNo()  const { return implRegNo    ; }
    UINT8  implVersionNo()  const { return implVersion  ; }
    UINT8  implRevisionNo() const { return implRevision ; }

    void getImplementInfo( ImplementationInfo & ii ) {
        ii.Id             = ID           ;
        ii.osClassId      = osClass      ;
        ii.osId           = osIdentifier ;
        ii.librVersionNo  = librVersion  ;
        ii.implRegistrNo  = implRegNo    ;
        ii.implVersionNo  = implVersion  ;
        ii.implRevisionNo = implRevision ;
    }

    void init() ;
    Error error() const ;

#ifdef NSR_VERIFY
    Boolean operator != ( const ImplRegID & obj ) const ;
#endif
        
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;
};

// Class: CharSpec
//
// The CharSpec class is a simple field type. The standard stuff is
// done here. It gives access to the character set type via the
// csType() method.
//
// METHOD: CharSpec::CharSpec()
// METHOD: CharSpec::csType()
// METHOD: CharSpec::field.len()
// METHOD: CharSpec::toISO()
// METHOD: CharSpec::fromISO()

// CLEAN: csType should be an enum.


class CharSpec {

public:
    FieldInfo field;
private:
    Uint8 charSetType_;
    Bytes charSetInfo_;
public:
    static UINT8  OSTAType;
    static String OSTAInfo;

    CharSpec ( UINT16 o ) ;

    UINT8 csType() const { return charSetType_; }
    void  csType(UINT8 cst) { charSetType_ = cst; }

    String csInfo() const { return String(charSetInfo_); }
    void  csInfo(const String &csi) { charSetInfo_ = csi; }

    CharSetType charSetType() const {
        if (csType() == OSTAType &&
            csInfo() == OSTAInfo)
            return charset_OCU;
        else
            return charset_Ascii;
    }
        
    Error error() const { return charSetInfo_.error(); }
    
#ifdef NSR_VERIFY
    Boolean operator != ( const CharSpec & obj ) const ;
#endif
private:
    void init() ;
public:
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

};

// Class: Dstring
//
// The Dstring class is a fixed length Field. This means that, like
// other fields, it is suitable only for instantiation inside of a
// containing NSR structure, and also that its length is fixed. The
// length of the field is set when it is constructed (instantiated),
// as is the offset of the field within its containing structure.
//
// The fieldLength, then, is not changeable by any operation - it is
// set at construction time (when it is instantiated), and is treated
// as a constant. It provides the hard limit on the length of the
// string, and is used by toISO() and fromISO() for placing the string
// length field and padding.
//
// Supported operations
//
//    Assignment and Casting
//    
//    The String casting operator (operator String()) is supported so
//    that Dstrings may be directly assigned into a string. The
//    assignment operator is supported for String types, so that
//    Strings may also be assigned into a Dstring.
//
//    The assignment operator does not support Dstrings, so that a
//    Dstring must be cast into a String before being assigned into
//    another Dstring. This makes it clearer(?) exactly what is going
//    on -- only the string element is being assigned, and the
//    fieldLength is left alone.
//
//    Comparing Dstrings
//
//    No comparison operators are supported for Dstrings. If two
//    Dstrings are to be compared, their Strings and fieldLengths
//    should be compared explicitly.
//
// METHOD: Dstring::Dstring()
// METHOD: Dstring::operator=()
// METHOD: Dstring::String()
// METHOD: Dstring::field.len()
// METHOD: Dstring::toISO()
// METHOD: Dstring::fromISO()

class Dstring {

public:
    FieldInfo field;
private:
    String str;
    Uint8  nchars;
public:

// Constructor
    Dstring( const UINT16 o, const UINT8 len ) ;

    Dstring & operator=( const String &s ) {

        str = s;
        // Can ONLY fit field.len()-2 bytes in, since will need the
        // first byte reserved for the Unicode Compression algorithm,
        // and the last byte for the nchars.
        if ( str.length() >  (field.len()-2)) {
            // ONLY remove if need to. Otherwise, GROWS string.
            str.remove(field.len()-2);
        }
        // Compressed Unicode included in nchars, not in length().
        nchars = str.length() + 1;
        return *this;
    }

    operator String() const { return str; }
    Error error() const { return str.error(); }

#ifdef NSR_VERIFY
    Boolean operator != ( const Dstring & obj ) const ;
#endif

    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp, CharSetType cst ) ;

};

// Class: LogicalBlockAddr
//
// The LogicalBlockAddr class is a composite field which allows access
// to its constituent fields directly, and simply supports
// construction (of course), toISO(), and fromISO().
//
// METHOD: LogicalBlockAddr::LogicalBlockAddr()
// METHOD: LogicalBlockAddr::toISO()
// METHOD: LogicalBlockAddr::field.len()
// METHOD: LogicalBlockAddr::fromISO()

class LogicalBlockAddr {

public:
    FieldInfo field;
    Uint32    logicalBlockNo;
    Uint16    partitionRefNo;

    LogicalBlockAddr( UINT16 o ) ;

#ifdef NSR_VERIFY
    Boolean operator != ( const LogicalBlockAddr & obj ) const ;
#endif

    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

};

// Class: ExtLength
//
// The ExtLength class is a simple field type with two subfields.
//
// It is constructed with a mandatory field location (field.start), and an
// optional extent type and length. It provides member functions
// through which to access its two subfields containing the extent
// type and the extent length.
//
// METHOD: ExtLength::ExtLength()
// METHOD: ExtLength::extType()
// METHOD: ExtLength::length()
// METHOD: ExtLength::field.len()
// METHOD: ExtLength::toISO()
// METHOD: ExtLength::fromISO()

enum ExtType {
    ext_Recorded    = 0,        // extent allocated and recorded
    ext_Allocated   = 1,        // extent allocated but unrecorded
    ext_Unallocated = 2,        // extent unallocated and unrecorded
    ext_AllocExtent = 3         // extent is next extent of ADs
};

class ExtLength {

public:
    FieldInfo field;
private:
    Ubits32 extType_ ;
    Ubits32 length_  ;
public:
    ExtLength( UINT16 o, ExtType t = ext_Recorded, UINT32 el = 0 ) ;

    void extType(ExtType et)    { extType_ = (UINT32)et; }
    ExtType extType(void) const ;

    static UINT32 maxLength(void) { return 0x3fffffffL; }

    void length(UINT32 el)     { length_ = el; }
    UINT32 length(void) const { return length_; }

#ifdef NSR_VERIFY
    Boolean operator != ( const ExtLength & obj ) const ;
#endif

    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

};

// Class: ShortAllocDesc
// Class: LongAllocDesc
// Class: ExtendedAllocDesc
//
// These classes are fields which do not offer direct access to any of
// their data members. Methods are provided for field access.
//
// The standard Field methods are supported, where the location of the
// field inside its containing class must be supplied. Note that in
// the common cases where ADs are concatenated, and are not associated
// to a fixed address inside their containing structure, the field
// location may be initially set to 0 or the location of the start of
// the ADs, with the code manually incrementing the byte pointer it
// passes in by field.len() to get to the subsequent field.
//
// METHOD: ShortAllocDesc::ShortAllocDesc()
// METHOD: ShortAllocDesc::toISO()
// METHOD: ShortAllocDesc::fromISO()
//
// METHOD: LongAllocDesc::LongAllocDesc()
// METHOD: LongAllocDesc::toISO()
// METHOD: LongAllocDesc::fromISO()
//
// METHOD: ExtendedDesc::LongAllocDesc()
// METHOD: ExtendedDesc::toISO()
// METHOD: ExtendedDesc::fromISO()
//
// CLEAN: AD arrays
//
// We COULD add a method to add the field.len() into the field location
// as an iterator sort of thing to help the toISO() and fromISO() of
// sets of ADs located together. This MAY be harder on the looping
// function than simply allowing him to essentially address these as
// an array in C would, by adding field.len() to the rbp, and checking
// for it going past its allowed bounds.
//
// We COULD EVEN provide a sort of ExtentOfADs field, which supported
// this concept as well, although it is likely that the boundary
// conditions in handling the continuation extent stuff would make
// this messier than might at first be thought.

// METHOD: ShortAllocDesc::extType()
// METHOD: ShortAllocDesc::extLength()
// METHOD: ShortAllocDesc::LogBlockNo()
//
// METHOD: LongAllocDesc::extType()
// METHOD: LongAllocDesc::extLength()
// METHOD: LongAllocDesc::LogBlockNo()
// METHOD: LongAllocDesc::PartRefNo()
//
// METHOD: ExtendedAllocDesc::extType()
// METHOD: ExtendedAllocDesc::extLength()
// METHOD: ExtendedAllocDesc::recLength()
// METHOD: ExtendedAllocDesc::infoLength()
// METHOD: ExtendedAllocDesc::LogBlockNo()
// METHOD: ExtendedAllocDesc::PartRefNo()
//
// The access to the fields in an allocation descriptor is provided by
// a set of set and get methods. If no args are supplied, the value is
// returned.  Otherwise, the field is set to the supplied value.
//
// NOTE that direct access is given via these methods to the
// subfields, like extType, rather than requiring the user of this
// class to know that the type is buried inside the length field.
// Also, the logBlockNo and PartRefNo are offered directly, saving the
// user from going through the extentLocation.

// METHOD: ShortAllocDesc::field.len()
// METHOD: LongAllocDesc::field.len()
// METHOD: ExtendedAllocDesc::field.len()
//
// The field.len() method returns the number of bytes occupied by the
// allocation descriptor when in the ISO form.

// METHOD: ShortAllocDesc::markContinued()
// METHOD: LongAllocDesc::markContinued()
// METHOD: ExtendedAllocDesc::markContinued()
// METHOD: ShortAllocDesc::isContinued()
// METHOD: LongAllocDesc::isContinued()
// METHOD: ExtendedAllocDesc::isContinued()
//
// These methods are used to support allocation extents. If an extent
// is to be changed to an allocation extent, markContinued() sets it
// to an allocation extent, and isContinued checks to see if the
// extent is of that type.

// METHOD: shortAllocDesc::impUseLen()
// METHOD: LongAllocDesc::impUseLen()
// METHOD: ExtendedAllocDesc::impUseLen()
// METHOD: LongAllocDesc::impUse()
// METHOD: ExtendedAllocDesc::impUse()
//
// These methods return the length of the impUse fields, and a pointer
// to the implementation use field of the descriptors, respectively.
// Note that other structures may be overlaid on top of these fields,
// and toISO(), fromISO() can use the address this returns as their
// arguments.

class ShortAllocDesc {

public:
    FieldInfo field;
private:
    ExtLength extentLength;
    Uint32    extentPosition;
public:
    ShortAllocDesc( UINT16 o = 0 ) ; // to support ADTable

    ExtType extType()  const { return extentLength.extType(); }
    void extType( ExtType et ) { extentLength.extType(et);   }

    UINT32  extLength()  const { return extentLength.length(); }
    void extLength( UINT32 el ) { extentLength.length(el);  }

    UINT32 logBlockNo()  const    { return extentPosition; }
    void logBlockNo( UINT32 lbn ) { extentPosition = lbn;  }

    UINT16 impUseLen() const { return 0; }

    void markContinued()  { extType(ext_AllocExtent); }
    Boolean isContinued() const {
        
        return (extType() == ext_AllocExtent) ? True : False;

    }

#ifdef NSR_VERIFY
    Boolean operator != ( const ShortAllocDesc & obj ) const ;
#endif
        
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;
#ifdef _INCL_SSOBJS_
    void toLogExtent( Partition * pp,
                      LogExtent & le,
                      Error & err ) const;
    void fromLogExtent( const LogExtent & le,
                        Error & err );
#endif // _INCL_SSOBJS_
};

class OSTAADFlags {

public:
    FieldInfo field;
private:
    Bit16   extentErased;
    Ubits16 reserved;
public:
    OSTAADFlags( UINT16 o ) ;

    Boolean isErased() const { return extentErased ? True : False; }
    void markErased() { extentErased = 1; }
    void markUnerased() { extentErased = 0; }

#ifdef NSR_VERIFY
    Boolean operator != ( const OSTAADFlags & obj ) const {
        return extentErased != obj.extentErased ? True : False;
    }
#endif
        
    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

};

class LongAllocDesc {

public:
    FieldInfo field;
protected:
    ExtLength        extentLength   ;
    LogicalBlockAddr extentLocation ;
    OSTAADFlags      flags          ;
    Bytes            implementUse   ;

public:

    LongAllocDesc( UINT16 o = 0 ) ; // to support ADTable

    ExtType extType()    const { return extentLength.extType(); }
    void extType( ExtType et ) { extentLength.extType(et);   }

    UINT32  extLength()   const { return extentLength.length(); }
    void extLength( UINT32 el ) { extentLength.length(el);   }

    UINT32 logBlockNo()     const { return extentLocation.logicalBlockNo; }
    void logBlockNo( UINT32 lbn ) { extentLocation.logicalBlockNo = lbn;  }

    UINT16 partRefNo()     const { return extentLocation.partitionRefNo; }
    void partRefNo( UINT16 prn ) { extentLocation.partitionRefNo = prn;  }

    void markErased()        { flags.markErased(); }
    Boolean isErased() const { return flags.isErased(); }

    BYTE_PTR impUse()           { return (BYTE_PTR)implementUse; }
    UINT16 impUseLen() const { return implementUse.field.len(); }

    void markContinued()  { extType(ext_AllocExtent); }
    Boolean isContinued() const {
        
        return (extType() == ext_AllocExtent) ? True : False;

    }

#ifdef NSR_VERIFY
    Boolean operator != ( const LongAllocDesc & obj ) const ;
#endif

    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

#ifdef _INCL_SSOBJS_
    void toLogExtent( LogicalVolume * lvp,
                      LogExtent & le,
                      Error & err ) const;
    void fromLogExtent( const LogExtent & le,
                        Error & err );
#endif // _INCL_SSOBJS_
};

class ExtendedAllocDesc {

public:
    FieldInfo field;
private:
    ExtLength        extentLength     ;
    ExtLength        recordedLength   ;
    Uint32           informationLength;
    LogicalBlockAddr extentLocation   ;
    OSTAADFlags      flags            ;

public:
    ExtendedAllocDesc( UINT16 o = 0 ) ; // to support ADTable

    ExtType extType()    const { return extentLength.extType(); }
    void extType( ExtType et ) { extentLength.extType(et);   }

    UINT32  extLength()   const { return extentLength.length(); }
    void extLength( UINT32 el ) { extentLength.length(el);   }

    UINT32  recLength()   const  { return recordedLength.length(); }
    void recLength( UINT32 rl )  { recordedLength.length(rl);   }

    UINT32  infoLength()   const { return informationLength; }
    void infoLength( UINT32 il ) { informationLength = il;   }

    UINT32 logBlockNo()  const    { return extentLocation.logicalBlockNo; }
    void logBlockNo( UINT32 lbn ) { extentLocation.logicalBlockNo = lbn;  }

    UINT16 partRefNo()  const     { return extentLocation.partitionRefNo; }
    void partRefNo( UINT16 prn )  { extentLocation.partitionRefNo = prn;  }

    void markErased()        { flags.markErased(); }
    Boolean isErased() const { return flags.isErased(); }

    void markContinued()  { extType(ext_AllocExtent); }
    Boolean isContinued() const {
        
        return (extType() == ext_AllocExtent) ? True : False;

    }

#ifdef NSR_VERIFY
    Boolean operator != ( const ExtendedAllocDesc & obj ) const ;
#endif

    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;

#ifdef _INCL_SSOBJS_
    void toLogExtent( LogicalVolume * lvp,
                      LogExtent & le,
                      Error & err ) const;
    void fromLogExtent( const LogExtent & le,
                        Error & err );
#endif // _INCL_SSOBJS_
};

// Class: ExtentDesc
//
// The ExtentDesc class is a composite field which allows public
// access to its constituent fields: length and location. It provides
// only the simplest of field methods, which are entirely predictable.
//
// METHOD: ExtentDesc::ExtentDesc()
// METHOD: ExtentDesc::toISO()
// METHOD: ExtentDesc::fromISO()

class ExtentDesc {

public:
    FieldInfo field;
    Uint32    length;
    Uint32    location;

    ExtentDesc( UINT16 o ) ;

#ifdef NSR_VERIFY
    Boolean operator != ( const ExtentDesc & obj ) const ;
#endif

    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;
#ifdef _INCL_SSOBJS_
    void toPhysExtent( PhysicalVolume * pvp,
                       PhysExtent & pe,
                       Error & err ) const;
    void fromPhysExtent( const PhysExtent & pe,
                         Error & err );
#endif // _INCL_SSOBJS_

};

// Class: DescriptorTag
// 
// The DescriptorTag is the first step away from simple fields into
// the realm of descriptors. It is a hybrid: It may be viewed as a
// field inside another descriptor, or as a descriptor itself.
//
// Use SearchDescriptor for searching through descriptor sequences
// when it is not known what type of descriptor is to be found next.
//
// It supports standard toISO() and fromISO() methods, as well as an
// isValid() method for checking for valid descriptorTags.
//
// METHOD: DescriptorTag::toISO()
// METHOD: DescriptorTag::fromISO()


// METHOD: DescriptorTag::DescriptorTag()
// METHOD: DescriptorTag::tagType()
//
// The type of descriptor tag is set when the constructor is called.
// Note that both the field location and tag type are required in the
// constructor. If the type is not known when constructed, the
// tag_Unknown is used, and the type is determined at the fromISO()
// call. The tagType() method returns the type of the tag.

// METHOD: DescriptorTag::tagLoc()
// METHOD: DescriptorTag::crcLen()
// METHOD: DescriptorTag::SerialNo()
// 
// Methods are provided for accessing and setting the tagSerialNo,
// crcLength, and tagLocation fields of the DescriptorTag. If no
// argument is supplied, they return the value. Otherwise, they set
// the field to the supplied value.
// 
// The tagLoc() method is used to set the location of the descriptor
// so that the descriptor tag may be written properly. Note that the
// location must be set before toISO() is called in order to conform
// to the standard.
//
// ISSUE: DescriptorTag::tagSerialNo() initialization
//
// OSTA says this must be set to the value in the PVD DescriptorTag.
// Should this be held in a static as the default? How should this be
// handled? How would it be initialized?
//
// ISSUE: DescriptorTag::calcCRC() limits
//
// If the length is set to a large value, this could go on forever.
// Should it limit itself or not? Should the limit be placed inside
// the set routine for the CRCLength?
//
// CLEAN: write() methods for descriptors?
// Each instance of toISO() is followed by a writeSector call. Given
// that the location of the descriptor must be recorded inside of it,
// and toISO() knows about its location, perhaps toISO() should be
// swallowed up by some sort of write() method, which does the toISO()
// and then writes it to the appropriate location. NOTE that
// Allocation Descriptors and File Identifier Descriptors are
// exceptions to this generalization.

enum TagType {
    tag_Unknown =   0,
    tag_PVD     =   1,
    tag_AVD     =   2,
    tag_VDP     =   3,
    tag_IUVD    =   4,
    tag_PD      =   5,
    tag_LVD     =   6,
    tag_USD     =   7,
    tag_TD      =   8,
    tag_LVID    =   9,
    tag_FSD     = 256,
    tag_FID     = 257,
    tag_AED     = 258,
    tag_IE      = 259,
    tag_TE      = 260,
    tag_FE      = 261,
    tag_EAHD    = 262,
    tag_USE     = 263,
    tag_SBD     = 264,
    tag_PIE     = 265
};

class DescriptorTag {

public:
    FieldInfo field;
private:

    Uint16  tagId               ;
    Uint16  descriptorVersion   ;
    Uint8   tagChecksum         ;
    Uint8   reserved            ;
    Uint16  tagSerialNo         ;
    Uint16  descriptorCRC       ;
    Uint16  descriptorCRCLength ;
    Uint32  tagLocation         ;

    static const UINT16 crc_table[256];

public:

    DescriptorTag( UINT16 o, TagType tid ) ;

    TagType tagIdentifier() const;
    void tagIdentifier(TagType t) { tagId = t; }
            
    void serialNo( UINT16 n )      { tagSerialNo = n; }
    UINT16 serialNo( ) const { return tagSerialNo; }

    void crcLen( UINT16 a )      { descriptorCRCLength = a; }
    UINT16 crcLen( ) const { return descriptorCRCLength; }

    void tagLoc( UINT32 a )      { tagLocation = a; }
    UINT32 tagLoc( ) const { return tagLocation; }

// This is temporary - it would be much nicer to provide an iostream
// method for this, but that may not work on Maestro.

    void print(CHAR_PTR hdrStr) ;

private:

    UINT16 calcCRC( CONST_BYTE_PTR rbp ) const;
    BYTE checksum( CONST_BYTE_PTR rbp ) const;

public:

#ifdef NSR_VERIFY
    Boolean operator != ( const DescriptorTag & obj ) const ;
#endif

    void clear() ;
    void toISO( BYTE_PTR rbp ) ;
    void fromISO( CONST_BYTE_PTR rbp ) ;
    Error hasGoodCRC( CONST_BYTE_PTR rbp ) const;
    Error isValid( CONST_BYTE_PTR rbp, const UINT32 location ) const;

};
// ISSUE: CRCs should be moved into TaggedDescriptor.
// Their automatic generation should be removed from toISO() of the
// tag, and be done explicitly. Note that this is because CRCs REALLY
// indicate not whether a tag is OK, but whether the body of a
// decriptor appears OK.
// The first step toward this has been taken, by supplying methods for
// generating and checking CRCs. The next step is to remove it from
// the tag altogether.

#endif
