//-*-c++-*--------------------------------------------------------------
//  nsrAux.cpp
//   Miscellaneous low-level objects used by various parts of code.
//
//      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:
//   String
//   SmallByteArray
//   ByteArray
//   ByteArrayRef
//   PathElement
//   PathElementList
//   Bitmap
//  
//----------------------------------------------------------------------
//
// $Source: /projects/HMS/nsr/udfCore/sys/nsrAux.cpp,v $
// $Revision: 1.45 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/06/25 23:14:26 $
//

#include "nsrLib.h"

#define BITS_PER_BYTE   8       // For Bitmap methods

#ifdef OLD_STRING

NSR::String::String( CONST_CHAR_PTR s )
{
    if (s==0) {    // constructed string is in error!
        str    = 0;
        strLen = 0;
        return;
    }
    strLen = StrLen(s);
    str = (CHAR_PTR)AllocateMemory(strLen+1);
    if (str)
        StrCpy(str, s);
    else
        strLen = 0;
}

NSR::String::String( CONST_BYTE_PTR s, UINT16 maxLen, CharSetType cst )
{
    if (s==0) {
        str    = 0;        // to set error condition
        strLen = 0;        // to set error condition
        return;
    }
    // For now, OK to have non-0x08 OCUs converted as though ASCII.
    if (cst == charset_OCU && *s == 0x08 && maxLen > 0) {
        s++;
        maxLen--;
        cst = charset_Ascii;
    }
    strLen = maxLen;
    str = (CHAR_PTR)AllocateMemory(strLen+1);
    if (str)
    {
        StrNCpy(str, (CONST_CHAR_PTR)s, strLen);
        str[strLen] = '\0';
        strLen = StrLen(str);
    }
    else
        strLen = 0;
}

void
NSR::String::copy( const String &obj )
{
    strLen = obj.strLen;
    if ( obj.str == 0 ) {       // propagate error
        str = 0;
    } else {
        if (str)
            FreeMemory(str);
        str = (CHAR_PTR)AllocateMemory(strLen+1);
        if (str)
        {
            StrNCpy(str, obj.str, strLen);
            str[strLen] = '\0';
        }
        else
            strLen = 0;
    }
}


NSR::String &
NSR::String::operator+= (const String &obj )
{
    static const UINT32 MAX_STRING_LEN = 65534UL;  // based on UINT16 strLen sta te
    UINT32 availLen = MAX_STRING_LEN - (UINT32) strLen; //space avail for append
    UINT32 copyLen = (UINT32) obj.length();
    if (copyLen > availLen)
        copyLen = availLen;   // only copy up to length available
    if (copyLen > 0) {
        CHAR_PTR newStr = (CHAR_PTR)AllocateMemory(strLen + copyLen + 1);
        if (newStr != NULL) {
            toMem(newStr);                          // copy original str
            CHAR_PTR appendStart = newStr + strLen;
            obj.toMemArea( (BYTE_PTR) appendStart,
                           copyLen );                       // append copyLen bytes
            CHAR_PTR nullAddr = appendStart + copyLen;
            *nullAddr = '\0';                       // null terminate
            if (str)
                FreeMemory(str);
            str = newStr;
            strLen += copyLen;
        }
        else
            strLen = 0;
    }
    return *this;

} //String::operator+()


NSR::Boolean
NSR::String::operator == ( const String &obj ) const
{
    if (obj.strLen != strLen)   // False if different lengths
        return False;
    if (obj.strLen == 0 && strLen == 0)               // True if both Zero length
        return True;
    if (obj.str == 0 || str == 0) // False if either in error
        return False;
    return (StrCmp(str, obj.str) == 0 ? True : False);
}

NSR::Boolean
NSR::String::operator != ( const String &obj ) const
{
    return ( *this == obj ) ? False : True ;
}

NSR::String&
NSR::String::remove( UINT16 maxLen )
{
    if (maxLen < strLen) {
        if (str != 0) {
            for (UINT32 i=maxLen; i<=strLen; i++) 
                str[i] = '\0';
        }
        strLen = maxLen;
    }
    return *this;
}

#else   // OLD_STRING

NSR::String::String( CONST_BYTE_PTR s, UINT16 maxLen, CharSetType cst ) :
                    RWCString((CONST_CHAR_PTR) s,maxLen)
{
    if (length() > 0) {
        // For now, OK to have non-0x08 OCUs converted as though ASCII.
        if (cst == charset_OCU &&
            *s == 0x08 ) {
            remove(0,1);
        }
    }
    // This incredibly defensive programming is meant to work around some
    // sort of bug in RW or G++... first() was not working on an empty string.
    if (length() > 0) {
        size_t where = first('\0');
        if(where < length()) {
            remove(where);
        }
    }
}


#endif  // OLD_STRING

//----------------------------------------------------------------------
// METHOD: String::toMem()                            --DVM
//      
//  Copies string to memory, at supplied address.
//
//  This method simply copies the contents of the String to memory as
//  a a standard c string at the address supplied. It is
//  null-terminated, which means that String::length()+1 bytes should
//  be allocated before this is called.
//
// ARGS:
//  CHAR_PTR   s  IN   Destination location
//
// RETURNS:
//  NONE
// 
// PRE-CONDITIONS:
//  Destination has room for len + 1 bytes.
// 
// POST-CONDITIONS: none.
// 
// ERRORS:
//  NONE.
// 
// NOTES:
//  Uses memcpy() library call.
//
//----------------------------------------------------------------------

#ifdef OLD_STRING

void
NSR::String::toMem( CHAR_PTR s ) const
{
    if ( s != 0 ) {
        if ( str != 0 )
            MemCpy( s, str, strLen+1);
        else
            *s='\0';
    }
}

#else

void
NSR::String::toMem( CHAR_PTR s ) const
{
    if ( s != 0 ) {
        if ( !isNull() )
            MemCpy( s, (CONST_CHAR_PTR) *this, length()+1);
        else
            *s='\0';
    }
}

#endif  // OLD_STRING

//----------------------------------------------------------------------
// METHOD: String::toMemArea()                        --DVM
//      
//  Copies string to memory, at supplied address with limited len.
//
//  This method should fill out memLen bytes with the contents of the
//  string. If memLen is larger than the string length, all unused
//  bytes will be set to zero. Otherwise, no null termination will be
//  supplied.
//
// ARGS:
//  BYTE_PTR   s       IN   Destination location
//  UINT16     memLen  IN   Max bytes available
//
// RETURNS:
//  NONE
// 
// PRE-CONDITIONS:  memLen bytes available at destination.
// 
// POST-CONDITIONS: none.
// 
// ERRORS:
//  NONE.
// 
// NOTES:
//  Uses memcpy() library call.
//
//----------------------------------------------------------------------

#ifdef OLD_STRING

void
NSR::String::toMemArea( BYTE_PTR s, UINT16 memLen ) const
{
    if ( s != 0 ) {
        if ( memLen > strLen ) {
            if ( str != 0 ) {
                MemCpy( s, str, strLen );
                MemSet(s+strLen,0,memLen - strLen);
            } else {
                MemSet(s,0,memLen);
            }
        } else {
            if ( str != 0 ) MemCpy( s, str, memLen );
        }
    }
}

#else

void
NSR::String::toMemArea( BYTE_PTR s, UINT16 memLen ) const
{
    if ( s != 0 ) {
        if ( memLen > length() ) {
            if ( !isNull() ) {
                MemCpy( s, (CONST_CHAR_PTR) *this, length() );
                MemSet(s+length(),0,memLen - length());
            } else {
                MemSet(s,0,memLen);
            }
        } else {
            if ( !isNull() ) MemCpy( s, (CONST_CHAR_PTR) *this, memLen );
        }
    }
}

#endif  // OLD_STRING
//----------------------------------------------------------------------
// METHOD: String::toMemOCU()                        --DVM
//      
//  Copies string, converting to OSTA Compressed Unicode to memory.
//
//  This method should fill out memLen bytes with the contents of the
//  string. If memLen is larger than the string length, all unused
//  bytes will be set to zero. Otherwise, no null termination will be
//  supplied. The first byte will be set to an 0x08, to indicate 8-bit
//  compression.
//
// ARGS:
//  BYTE_PTR   s       IN   Destination location
//  UINT16     memLen  IN   Max bytes available
//
// RETURNS:
//  NONE
// 
// PRE-CONDITIONS:  memLen bytes available at destination.
// 
// POST-CONDITIONS: none.
// 
// ERRORS:
//  NONE.
// 
// NOTES:
//  Uses memcpy() library call.
//
//----------------------------------------------------------------------

#ifdef OLD_STRING

void
NSR::String::toMemOCU( BYTE_PTR s, UINT16 memLen ) const
{
    if ( s != 0 ) {
        *s = 0x08;
        toMemArea(s+1, memLen - 1);
    }
}

#else

void
NSR::String::toMemOCU( BYTE_PTR s, UINT16 memLen ) const
{
    if ( !isNull() ) {
        *s = 0x08;
        toMemArea(s+1, memLen - 1);
    }
}

#endif  // OLD_STRING

// SmallByteArray

void
NSR::SmallByteArray::copy( const SmallByteArray &obj )
{
    baLen = obj.baLen;
    if (obj.bytes == 0) {
        bytes = 0;
    } else {
        bytes = new BYTE [baLen==0?1:baLen];
        if ( bytes != 0 ) {
            for (UINT16 i=0; i<baLen; i++) 
                bytes[i] = obj.bytes[i];
        }
    }
}

NSR::SmallByteArray::SmallByteArray( UINT16 l )
{
    baLen = l;
    bytes = new BYTE[baLen==0?1:baLen];
    clear();
}

NSR::SmallByteArray::SmallByteArray( CONST_BYTE_PTR b, UINT16 l)
{
    baLen = l;
    if ( b == 0 ) {
        bytes = 0;              // to set error condition
        return;
    }
    bytes = new BYTE[baLen==0?1:baLen];
    fromMem( b );
}

NSR::Boolean
NSR::SmallByteArray::operator == ( const SmallByteArray &obj ) const
{
    if (obj.baLen != baLen)         // False if different lengths
        return False;
    if (baLen == 0)               // True if both Zero length
        return True;
    if (obj.bytes == 0 || bytes == 0) // False if either in error
        return False;
    for (unsigned i=0; i<baLen; i++) // False if any BYTE not same
        if (obj.bytes[i] != bytes[i]) return False;
    return True;
}

NSR::Boolean
NSR::SmallByteArray::operator != ( const SmallByteArray &obj ) const
{
    return ( *this == obj ) ? False : True ;
}

void
NSR::SmallByteArray::setLen( UINT16 l )
{
    if ( baLen != l ) {
        UINT16 newLen = l;
        if ( bytes != 0 ) {
            BYTE_PTR newBytes = new BYTE[newLen==0?1:newLen];
            if ( newBytes != 0 ) {
                INT16 padLen = newLen - baLen;
                if ( padLen > 0 ) {
                        // copy all existing bytes into new. Zero rest.
                    toMem(newBytes);
                    MemSet(newBytes+baLen,0,padLen);
                } else {
                        // copy all new bytes from this.
                    MemCpy(newBytes,bytes,newLen);
                }
            }
            free();
            bytes = newBytes;
            baLen = newLen;
        }
    }
}

void
NSR::SmallByteArray::clear()
{
    if ( bytes != 0 )
        MemSet( bytes,0,baLen);
}

void
NSR::SmallByteArray::toMem( BYTE_PTR b ) const
{
    if ( bytes != 0 && b != 0)
        MemCpy( b, bytes, baLen );
}

void
NSR::SmallByteArray::fromMem( CONST_BYTE_PTR b )
{
    if ( b != 0 ) {
        if ( bytes != 0 )
            MemCpy( bytes, b, baLen );
    } else {
        MemSet( bytes, 0, baLen );
    }
}

// ByteArray

void
NSR::ByteArray::copy( const ByteArray &obj )
{
    baLen_ = obj.baLen_;
    if (obj.bytes_ == 0) {
        bytes_ = 0;
    } else {
        bytes_ = (BYTE_PTR)AllocateMemory(baLen_==0?1:baLen_);
        if ( bytes_ != 0 ) {
            for (UINT32 i=0; i<baLen_; i++) 
                bytes_[i] = obj.bytes_[i];
        }
    }
}

NSR::ByteArray::ByteArray( UINT32 l )
{
    baLen_ = l;
    bytes_ = (BYTE_PTR)AllocateMemory(baLen_==0?1:baLen_);
    clear();
}

NSR::ByteArray::ByteArray( CONST_BYTE_PTR b, UINT32 l)
{
    baLen_ = l;
    if ( b == 0 ) {
        bytes_ = 0;              // to set error condition
        return;
    }
    bytes_ = (BYTE_PTR)AllocateMemory(baLen_==0?1:baLen_);
    fromMem( b );
}

NSR::Boolean
NSR::ByteArray::operator == ( const ByteArray &obj ) const
{
    if (obj.baLen_ != baLen_)         // False if different lengths
        return False;
    if (baLen_ == 0)               // True if both Zero length
        return True;
    if (obj.bytes_ == 0 || bytes_ == 0) // False if either in error
        return False;
    for (UINT32 i=0; i<baLen_; i++) // False if any BYTE not same
        if (obj.bytes_[i] != bytes_[i]) return False;
    return True;
}

NSR::Boolean
NSR::ByteArray::operator != ( const ByteArray &obj ) const
{
    return ( *this == obj ) ? False : True ;
}

void
NSR::ByteArray::setLen( UINT32 l )
{
    if ( baLen_ != l ) {
        UINT32 newLen = l;
        if ( bytes_ != 0 ) {
            BYTE_PTR newBytes = (BYTE_PTR)AllocateMemory(newLen==0?1:newLen);
            if ( newBytes != 0 ) {
                INT32 padLen = newLen - baLen_;
                if ( padLen > 0 ) {
                        // copy all existing bytes into new. Zero rest.
                    toMem(newBytes);
                    MemSet(newBytes+baLen_,0,padLen);
                } else {
                        // copy all new bytes from this.
                    MemCpy(newBytes,bytes_,newLen);
                }
            }
            free();
            bytes_ = newBytes;
            baLen_ = newLen;
        }
    }
}

void
NSR::ByteArray::clear()
{
    if ( bytes_ != 0 )
        MemSet( bytes_,0,baLen_);
}

void
NSR::ByteArray::toMem( BYTE_PTR b ) const
{
    if ( bytes_ != 0 && b != 0)
        MemCpy( b, bytes_, baLen_ );
}

void
NSR::ByteArray::fromMem( CONST_BYTE_PTR b )
{
    if ( b != 0 ) {
        if ( bytes_ != 0 )
            MemCpy( bytes_, b, baLen_ );
    } else {
        MemSet( bytes_, 0, baLen_ );
    }
}

//----------------------------------------------------------------------
// METHOD: ByteArray::insertBytes  --DVM
//      
//  Inserts bytes into a ByteArray leaving it larger than before.
//
//  If no insertion can be performed, it exits without doing anything.
//  If bp is NULL, it inserts len bytes of value zero.
//
// ARGS:
//  UINT32          offset  IN  Position at which to insert.
//  UINT32          len     IN  Number of bytes to insert.
//  CONST_BYTE_PTR  bp      IN  Pointer to bytes to be inserted, or NULL to
//                              cause zero-value bytes to be inserted.
//
// RETURNS:
//  none.
// 
// PRE-CONDITIONS:
//  none.
// 
// POST-CONDITIONS:
//  BytesArray is len longer.
// 
// ERRORS:
//  none.
// 
// NOTES:
//
//----------------------------------------------------------------------
// This was coded by Cary Boyd of SAI.
//----------------------------------------------------------------------
void
NSR::ByteArray::insertBytes( UINT32 offset,
                             UINT32 len,
                             CONST_BYTE_PTR bp )
{
    UINT32 bytesToMove;

    if (offset > baLen_)
        return;
    if (len == 0)
        return;
    bytesToMove = baLen_-offset;
    setLen(baLen_+len);
    if (bytesToMove > 0)
        MemMove(bytes_+offset+len,
                bytes_+offset,
                bytesToMove);
    if (bp)
        MemCpy(bytes_+offset, bp, len);
    else
        MemSet(bytes_+offset, 0, len);
}

//----------------------------------------------------------------------
// METHOD: ByteArray::removeBytes  --DVM
//      
//  Removes bytes from a ByteArray, leaving it shorter.
//
//  If removal is not possible, the ByteArray is unaffected.
//
// ARGS:
//  UINT32          offset  IN  Position at which to start.
//  UINT32          len     IN  Number of bytes to remove.
//
// RETURNS:
//  none.
// 
// PRE-CONDITIONS:
//  none.
// 
// POST-CONDITIONS:
//  BytesArray is len shorter.
// 
// ERRORS:
//  none.
// 
// NOTES:
//
//----------------------------------------------------------------------
// This was coded by Cary Boyd of SAI.
//----------------------------------------------------------------------
void
NSR::ByteArray::removeBytes( UINT32 offset,
                             UINT32 len )
{
    UINT32 bytesToMove;

    if (offset >= baLen_)
        return;
    if (len == 0)
        return;
    if (len > baLen_ - offset)
        len = baLen_ - offset;
    bytesToMove = baLen_-(offset+len);
    if (bytesToMove > 0)
        MemMove(bytes_+offset,
                bytes_+offset+len,
                bytesToMove);
    setLen(baLen_-len);
}

#ifdef OLD_BYTE_ARRAY_REF

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::ByteArrayRef()                        --JKH
//
// Constructor for the ByteArrayRef object.  
//
// ARGS:  
//
// const ByteArray& theArray  IN   Reference to the ByteArray to which this
//                                 ByteArrayRef will refer.
//
// RETURNS:     none
// PRE-CONDS:   none
// POST-CONDS:  
//
// NOTES:
//  The ByteArrayRef object will be constructed and initialized with
//  offset of 0 and length equal to the length of the ByteArray
//  referred to
//------------------------------------------------------------------

NSR::ByteArrayRef::ByteArrayRef( ByteArray& theArray ) : barrp_(&theArray)
{
    offset_ = 0;
    length_ = theArray.length();
}

//------------------------------------------------------------------------
// METHOD:  ByteArrayRef::ByteArrayRef()                        --JKH
//
// Alternate form of the constructor for the ByteArrayRef object.
//
// ARGS:
//
// const ByteArray& theArray  IN   reference to the ByteArray to which this
//                                 ByteArrayRef will refer.
// UINT32 off:                IN   the offset into the ByteArray
// UINT32 len:                IN   the number of bytes of the ByteArray to 
//                                 address
//
// RETURNS:     none
// PRE-CONDS:   none
// POST-CONDS:
//
// --The ByteArrayRef object will be constrcted and initialized to the 
//   specified length and offset values.
//
// NOTES:
//
// The off and len parameters must specify a region within the argument 
// ByteArray; if either parameter is out of bounds, any subsequent calls to 
// the (BYTE_PTR) casting operator to return NULL, and calls to toMem() and
// fromMem() will fail.  The len parameter must also be a positive number.
//-----------------------------------------------------------------------------

NSR::ByteArrayRef::ByteArrayRef(ByteArray& theArray,UINT32 off,UINT32 len)
        : barrp_(&theArray),
          offset_(off),
          length_(len)
{
    // Nothing to do
}

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::offset()                              --JKH
//
// This function sets the ByteArrayRef's offset to the new value.
//
// ARGS:
//
// UINT32 newoffset  IN   The value of the new offset.
//
// RETURNS:  
//
// Returns the previous value of offset.
//
// PRE-CONDS:   none
// POST-CONDS:
//
// --The offset will be set to the new value, regardless of whether it is in
//   range.
//-----------------------------------------------------------------------------

NSR::UINT32
NSR::ByteArrayRef::offset( UINT32 newoffset )
{
    UINT32      oldval;

    oldval = offset_;
    offset_ = newoffset;
    return oldval;
}

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::length()                              --JKH
//
// This method sets the ByteArrayRef object's length field.
//
// ARGS:
//
// UINT32 newlength   IN   The value of the new length.
//
// RETURNS:  
//
// Returns the old value of length.
//
// PRE-CONDS:   none
// POST-CONDS:
//
// --The length will be set to the new value, regardless of whether it is in
//   range.
//-----------------------------------------------------------------------------

NSR::UINT32
NSR::ByteArrayRef::length( UINT32 newlength )
{
    UINT32      oldval;

    oldval = length_;
    length_ = newlength;
    return oldval;
}

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::toMem()                               --JKH
//
// Copies the memory referenced by the ByteArrayRef to the specified data 
// buffer.
//
// ARGS:
//
// BYTE_PTR buf  OUT  The data buffer. 
//
// RETURNS:  
//
// Returns True on success, False on failure.
//
// PRE-CONDS: 
//
// --The ByteArrayRef is valid:  its offset and length specify a valid 
//   region within the ByteArray to which the Ref refers.
//
// POST-CONDS:
//
// --Memory referenced by the ByteArrayRef will be copied to the specified
//   data buffer.
// --If the ByteArrayRef is invalid, the function does nothing.
//-----------------------------------------------------------------------------

NSR::Boolean
NSR::ByteArrayRef::toMem( BYTE_PTR buf ) const
{
    if((isValid() == False) || (buf == NULL)) {
        return False;
    }

    CONST_BYTE_PTR bptr = ((CONST_BYTE_PTR) *barrp_) + offset_;
    (void) memmove(buf,bptr,length_);
    return True;
}

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::fromMem()                             --JKH
//
// Copies from the specified data buffer to the memory referenced by the 
// ByteArrayRef.
//
// ARGS:
//
// const BYTE_PTR buf  IN        The data buffer. 
//
// RETURNS:  
//
// Returns True on success, False on failure.
//
// PRE-CONDS:
//
// --The ByteArrayRef is valid:  its offset and length specify a valid
//   region with the ByteArray to which the Ref refers.
//
// POST-CONDS:
//
// --Memory from the specified data buffer will be copied to memory referenced
//   by the ByteArrayRef.
// --If the ByteArrayRef is invalid, the function does nothing.
//-----------------------------------------------------------------------------

NSR::Boolean
NSR::ByteArrayRef::fromMem( CONST_BYTE_PTR buf )
{
    BYTE_PTR bptr;

    if((isValid() == False) || (buf == NULL)) {
        return False;
    }

    bptr = ((BYTE_PTR) *barrp_) + offset_;
    (void) memmove(bptr,buf,length_);
    return True;
}

#else   // This is the new ByteArrayRef code

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::ByteArrayRef()                        --JKH
//
// Constructor for the ByteArrayRef object.  
//
// ARGUMENTS:   (many signatures)
//
// BYTE_PTR     array     IN  Pointer to the memory to be referenced
// UINT32       arrayLen  IN  The size (capacity) of the memory pointed to by
//                            array
//
//      OR
//
// BYTE_PTR     array     IN  Pointer to the memory to be referenced
// UINT32       arrayLen  IN  The size (capacity) of the memory pointed to by
//                            array
// UINT32       offset    IN  Offset into the array
// UINT32       length    IN  Length of the referenced region
//
//      OR
// 
// const ByteArray& theArray  IN   Reference to the ByteArray to which this
//                                 ByteArrayRef will refer.
//
//      OR
//
// const ByteArray& theArray  IN   Reference to the ByteArray to which this
//                                 ByteArrayRef will refer.
// UINT32       offset        IN  Offset into the array
// UINT32       length        IN  Length of the referenced region
//
// RETURNS:     none
// PRE-CONDS:   none
// POST-CONDS:  
//
// NOTES:
//  The ByteArrayRef object will be constructed and initialized with
//  offset of 0 and length equal to the length of the ByteArray
//  referred to
//
// The off and len parameters must specify a region within the argument 
// ByteArray; if either parameter is out of bounds, any subsequent calls to 
// the (BYTE_PTR) casting operator to return NULL, and calls to toMem() and
// fromMem() will fail.  The len parameter must also be a positive number.
//------------------------------------------------------------------

NSR::ByteArrayRef::ByteArrayRef
(
    BYTE_PTR    array,
    UINT32      arrayLen 
) : theArray_(array),arrayLen_(arrayLen),offset_(0),length_(arrayLen)
{
    // Nothing to do
}

NSR::ByteArrayRef::ByteArrayRef
(
    BYTE_PTR    array,
    UINT32      arrayLen,
    UINT32      offset,
    UINT32      length
) : theArray_(array),arrayLen_(arrayLen),offset_(offset),length_(length)
{
    // Nothing to do
}


NSR::ByteArrayRef::ByteArrayRef
( 
    ByteArray&  theArray 
)
{
    theArray_ = (BYTE_PTR) theArray;
    arrayLen_ = theArray.length();
    offset_ = 0;
    length_ = theArray.length();
}

NSR::ByteArrayRef::ByteArrayRef
(
    ByteArray&  theArray,
    UINT32      off,
    UINT32      len
) : offset_(off), length_(len)
{
    theArray_ = (BYTE_PTR) theArray;
    arrayLen_ = theArray.length();
}

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::offset()                              --JKH
//
// This function sets the ByteArrayRef's offset to the new value.
//
// ARGS:
//
// UINT32 newoffset  IN   The value of the new offset.
//
// RETURNS:  
//
// Returns the previous value of offset.
//
// PRE-CONDS:   none
// POST-CONDS:
//
// --The offset will be set to the new value, regardless of whether it is in
//   range.
//-----------------------------------------------------------------------------

NSR::UINT32
NSR::ByteArrayRef::offset( UINT32 newoffset )
{
    UINT32      oldval;

    oldval = offset_;
    offset_ = newoffset;
    return oldval;
}

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::length()                              --JKH
//
// This method sets the ByteArrayRef object's length field.
//
// ARGS:
//
// UINT32 newlength   IN   The value of the new length.
//
// RETURNS:  
//
// Returns the old value of length.
//
// PRE-CONDS:   none
// POST-CONDS:
//
// --The length will be set to the new value, regardless of whether it is in
//   range.
//-----------------------------------------------------------------------------

NSR::UINT32
NSR::ByteArrayRef::length( UINT32 newlength )
{
    UINT32      oldval;

    oldval = length_;
    length_ = newlength;
    return oldval;
}

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::toMem()                               --JKH
//
// Copies the memory referenced by the ByteArrayRef to the specified data 
// buffer.
//
// ARGS:
//
// BYTE_PTR buf  OUT  The data buffer. 
//
// RETURNS:  
//
// Returns True on success, False on failure.
//
// PRE-CONDS: 
//
// --The ByteArrayRef is valid:  its offset and length specify a valid 
//   region within the ByteArray to which the Ref refers.
//
// POST-CONDS:
//
// --Memory referenced by the ByteArrayRef will be copied to the specified
//   data buffer.
// --If the ByteArrayRef is invalid, the function does nothing.
//-----------------------------------------------------------------------------

NSR::Boolean
NSR::ByteArrayRef::toMem( BYTE_PTR buf ) const
{
    if((isValid() == False) || (buf == NULL)) {
        return False;
    }

    CONST_BYTE_PTR bptr = ((CONST_BYTE_PTR) theArray_) + offset_;
    (void) memmove(buf,bptr,length_);
    return True;
}

//-----------------------------------------------------------------------------
// METHOD:  ByteArrayRef::fromMem()                             --JKH
//
// Copies from the specified data buffer to the memory referenced by the 
// ByteArrayRef.
//
// ARGS:
//
// const BYTE_PTR buf  IN        The data buffer. 
//
// RETURNS:  
//
// Returns True on success, False on failure.
//
// PRE-CONDS:
//
// --The ByteArrayRef is valid:  its offset and length specify a valid
//   region with the ByteArray to which the Ref refers.
//
// POST-CONDS:
//
// --Memory from the specified data buffer will be copied to memory referenced
//   by the ByteArrayRef.
// --If the ByteArrayRef is invalid, the function does nothing.
//-----------------------------------------------------------------------------

NSR::Boolean
NSR::ByteArrayRef::fromMem( CONST_BYTE_PTR buf )
{
    BYTE_PTR bptr;

    if((isValid() == False) || (buf == NULL)) {
        return False;
    }

    bptr = theArray_ + offset_;
    (void) memmove(bptr,buf,length_);
    return True;
}

#endif  // OLD_BYTE_ARRAY_REF

// PathElementList

void
NSR::PathElementList::copy( const PathElementList &obj ) {

    count = obj.count;
    element = new PathElement[size = obj.size];
    if (!element) { err = error_No_free_store; return; }
    for (UINT32 i=0; i<count; i++)
        element[i] = obj.element[i];

}

void
NSR::PathElementList::extend() {

    PathElement *tmp;
    tmp = new PathElement[size+10];
    if (!tmp) { err = error_No_free_store; return; }
    for (UINT32 i=0; i<count; i++)
        tmp[i] = element[i];
    size += 10;
    delete [] element;
    element = tmp;

}

void
NSR::PathElementList::remove( UINT32 x ) {

    if (x < count) {
        for (UINT32 i=x; i<(count-1); i++) 
            element[i] = element[i+1];
        count--;
    }

}

NSR::UINT32
NSR::PathElementList::totalBytes() const {

    UINT32 total = 0;
    for (unsigned i=0;i<count;i++)
        total += element[i].name.length() + 4;
    return total;

}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::Bitmap()                                    --JKH
//
// Constructor for the Bitmap object.
//
// ARGS:
//
// UINT32 size   IN   Specifies the size of the bitmap, in BITS
//
// PRE-CONDS:   none
// POST-CONDS:
//
// --Memory will be allocated for the bitmap of the specified size.
// --All bits will cleared (set to 0).
//-----------------------------------------------------------------------------

NSR::Bitmap::Bitmap(UINT32 size) : nbits(size)
{
    nbytes = (nbits / BITS_PER_BYTE) + ((nbits % BITS_PER_BYTE) ? 1 : 0);
    bitmap = (BYTE_PTR)AllocateMemory(nbytes);
    if(bitmap == NULL)
    {
        return;
    }
    clearRange(0,size);         // Clear all bits to 0.
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::~Bitmap()                                   --JKH
//
// Destructor.
//
// ARGS:   none
//
// PRE-CONDS:  none
// POST-CONDS:
//
// --Memory allocated to the bitmap will be freed.
//
// ISSUE:  Bitmap::~Bitmap():  This function should be made inline--JKH
//-----------------------------------------------------------------------------

NSR::Bitmap::~Bitmap(void)
{
    free();
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::setBit()                                    --JKH
//
// Set the specified bit to 1.  Bits are specified starting from 0.
//
// ARGS:
//
// UINT32 which   IN   Specifies which bit to set, starting from 0.
//
// RETURNS:  
//
// On success, returns 0; on failure, -1.  
//
// PRE-CONDS:
//
// --Specified bit is in range
//
// POST-CONDS:
//
// --Specified bit will be set to 1.
// --If the which parameter is out range, the function does nothing.
//-----------------------------------------------------------------------------

NSR::INT32
NSR::Bitmap::setBit(UINT32 which)
{
    if(which >= nbits) {
        return -1;
    }

    bitmap[which / BITS_PER_BYTE] |= (0x01 << (which % BITS_PER_BYTE));
    return 0;
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::clearBit()                                  --JKH
//
// Clears the specified bit to 0.  Bits are specified starting from 0.
//
// ARGS:
//
// UINT32 which   IN   Specifies which bit to clear, starting from 0.
//
// RETURNS:  
//
// On success, returns 0; on failure, -1.  
//
// PRE-CONDS:
//
// --Specified bit is in range
//
// POST-CONDS:
//
// --Specified bit will be cleared to 0.
// --If the which parameter is out range, the function does nothing.
//-----------------------------------------------------------------------------

NSR::INT32
NSR::Bitmap::clearBit(UINT32 which)
{
    if(which >= nbits) {
        return -1;
    }

    bitmap[which / BITS_PER_BYTE] &= ~(0x01 << (which % BITS_PER_BYTE));
    return 0;
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap:: setRange()                                 --JKH
//
// Sets a range of bits to 1, beginning with the specified offset.
//
// ARGS:
//
// UINT32 offset   IN    Bit offset; specifies beginning of range to set
// UINT32 numbits  IN    Number of bits to set.
//
// RETURNS:  
//
// On success, returns 0; on failure, -1.
//
// PRE-CONDS:
//
// --The specified range is valid (within the bitmap)
//
// POST-CONDS:
//
// --The specified range of bits will be set to 1.
// --If the specified range is invalid, the function does nothing.
//-----------------------------------------------------------------------------

NSR::INT32
NSR::Bitmap::setRange(UINT32 offset,UINT32 numbits)
{
    INT32       i;

    if((offset + numbits) >= nbits) {
        return -1;
    }

    // The simple algorithm here is just to set the bits one at a time.  This
    // is quite inefficient, but we'll do it for now.

    for(i = offset; i < (offset + numbits); i++) {
        setBit(i);
    }

    return 0;
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::clearRange()                                --JKH
//
// Clears a range of bits to 0, beginning with the specified offset.

// ARGS:
//
// UINT32 offset   IN    Bit offset; specifies beginning of range to clear
// UINT32 numbits  IN    Number of bits to clear.
//
// RETURNS:  
//
// On success, returns 0; on failure, -1.
//
// PRE-CONDS:
//
// --The specified range is valid (within the bitmap)
//
// POST-CONDS:
//
// --The specified range of bits will be cleared to 0.
// --If the specified range is invalid, the function does nothing.
//-----------------------------------------------------------------------------

NSR::INT32
NSR::Bitmap::clearRange(UINT32 offset,UINT32 numbits)
{
    INT32       i;

    if((offset + numbits) >= nbits) {
        return -1;
    }

    // The simple algorithm here is just to clear the bits one at a time.  This
    // is quite inefficient, but we'll do it for now.

    for(i = offset; i < (offset + numbits); i++) {
        clearBit(i);
    }

    return 0;
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::readBit()                                   --JKH
//
// Returns the value of the specified bit.  If the specified bit is out of 
// range, the function returns -1.
//
// ARGS:
//
// UINT32 which   IN   Specifies which bit to read.
//
// RETURNS:
//
// Returns the value of the specified bit (0 or 1); if the bit is out of range,
// returns -1.
//
// PRE-CONDS:   none
// POST-CONDS:  see return values
//-----------------------------------------------------------------------------

NSR::INT32
NSR::Bitmap::readBit(UINT32 which) const
{
    BYTE        byte;

    if(which >= nbits) {
        return -1;
    }
    byte = bitmap[which / BITS_PER_BYTE] & (0x01 << (which % BITS_PER_BYTE));
    return (byte ? 1 : 0);
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::resize()                                    --JKH
//
// Resizes the bitmap to have a new size.
//
// As much of the old data is retained is possible; if the new size is
// smaller than the original bitmap, then newsize bits of the old bitmap
// will be retained.  If the new size is greater than that of the original
// bitmap, the original bitmap's data will be copied into the least-
// significant bits of the new bitmap, and the remainder of the bits will 
// be cleared to 0.
//
// ARGS:
//
// UINT32 newsize   IN   The new size of the bitmap, in BITS
//
// RETURNS:  
//
// Returns 0 on success, -1 on failure (no free store).
//
// PRE-CONDS:   none
// POST-CONDS:  see above.
//-----------------------------------------------------------------------------

NSR::INT32
NSR::Bitmap::resize(UINT32 newsize)
{
    INT32       i;
    UINT32      newbytes;
    BYTE_PTR    bptr;

    if(newsize == 0)
    {
        free();
        nbytes = nbits = 0;
        bitmap = NULL;
        return 0;
    }

    // Allocate new bitmap space

    newbytes = (newsize / BITS_PER_BYTE) + ((newsize % BITS_PER_BYTE) ? 1 : 0);
    bptr = (BYTE_PTR)AllocateMemory(newbytes);
    if(bptr == NULL) {
        nbytes = nbits = 0;
        return -1;
    }

    for(i = 0; i < newbytes; i++) {
        bptr[i] = 0;
    }

    // Copy old data

    if(nbytes <= newbytes) {           // The whole thing will fit
        MemMove(bptr,bitmap,nbytes);
    }
    else {
        MemMove(bptr,bitmap,newbytes);
    }
    nbytes = newbytes;
    nbits = newsize;
    free();
    bitmap = bptr;
        
    return 0;
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::countBits()                                 --JKH
//
// returns the number of bits in the bitmap with the specified value.
//
// ARGS: 
//
// UINT32 set  IN   if 0, look for clear bits; otherwise look for set bits.
//
// RETURNS:
//
// Returns the number of bits in the bitmap with the specified value.
//
// PRE-CONDS:   none
// POST-CONDS:  see returns.
//
// NOTES:
//
// If set is non-zero, it is interpreted to indicate that the function should
// count set bits (that is, if set is nonzero, it is set to 1).
//-----------------------------------------------------------------------------

NSR::UINT32
NSR::Bitmap::countBits(UINT32 set) const
{
    INT32       i;
    UINT32      count = 0;

    if(set) {
        set = 0x01;
    }
    for(i = 0; i < nbits; i++) {
        if(readBit(i) == set) {
            count++;
        }
    }
    return count;
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::rangeSize()                                 --JKH
//
// Returns the maximum number of contiguous bits in the bitmap with the 
// specified value.
//
// ARGS: 
//
// UINT32 set   IN   if 0, look for clear bits; otherwise look for set bits.
//
// RETURNS:
//
// Returns the maximum number of contiguous bits in the bitmap with the
// specified value.
//
// PRE-CONDS:   none
// POST-CONDS:  see return values
//-----------------------------------------------------------------------------

NSR::UINT32
NSR::Bitmap::rangeSize(UINT32 set) const
{
    INT32       i;
    UINT32      count = 0;
    UINT32      max = 0;

    if(set) {
        set = 0x01;
    }
    for(i = 0; i < nbits; i++) {
        if(readBit(i) == set) {
            count++;
        }
        else {
            if(count > max) {
                max = count;
            }
            count = 0;
        }
    }
    return ((count > max) ? count : max );
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::findSetRange()                              --JKH
//
// Returns the starting position of a block of contiguous set bits. 
//
// ARGS: 
//
// UINT32 numbits   IN   Size of the block to find
//
// RETURNS:
//
// Returns -1 if no block could be found of sufficient size; otherwise returns
// the starting bit position.
//
// PRE-CONDS:   none
// POST-CONDS:  see return values
//-----------------------------------------------------------------------------

NSR::INT32
NSR::Bitmap::findSetRange(UINT32 numbits) const
{
    INT32       i;
    INT32       start = -1;
    INT32       count = 0;

    for(i = 0; i < nbits; i++) {
        if(readBit(i)) {
            if(start == -1) {
                start = i;
            }
            count++;
            if(count == numbits) {
                return start;
            }
        } 
        else {
            if(start >= 0) {
                if(count >= numbits) {          // We're done
                    return start;
                }
            }
            count = 0;
            start = -1;
        }
    }
    return -1;
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::findClearRange()                            --JKH
//
// Returns the starting position of a block of contiguous clear bits. 
//
// ARGS: 
//
// UINT32 numbits   IN   Size of the block to find
//
// RETURNS:
//
// Returns -1 if no block could be found of sufficient size; otherwise returns
// the starting bit position.
//
// PRE-CONDS:   none
// POST-CONDS:  see return values
//-----------------------------------------------------------------------------

NSR::INT32
NSR::Bitmap::findClearRange(UINT32 numbits) const
{
    INT32       i;
    INT32       start = -1;
    INT32       count = 0;

    for(i = 0; i < nbits; i++) {
        if(!readBit(i)) {
            if(start == -1) {
                start = i;
            }
            count++;
            if(count == numbits) {
                return start;
            }
        } 
        else {
            if(start >= 0) {
                if(count >= numbits) {          // We're done
                    return start;
                }
            }
            count = 0;
            start = -1;
        }
    }
    return -1;
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::print()                                     --JKH
//
// For debugging purposes; prints the specified number of bits of the bitmap
// to screen.
//
// ARGS:   
//
// UINT32 numbits   IN   Number of bits to print
//
// RETURNS:   none
//
// PRE-CONDS:   none
// POST-CONDS:  
//
// --prints to screen the values of the first numbits bits in the bitmap,
//   though this number will not exceed the number of bits actually in the
//   bitmap.
//
// ISSUE:  Bitmap::print():  Currently ignores indent parameter         --JKH
//-----------------------------------------------------------------------------

#ifdef DEBUG 

void
NSR::Bitmap::print(UINT32 indent,const String& header,UINT32 numbits) const
{
    INT32       i,max;

    indent;                     // no op
    printf("%s\n",(CONST_CHAR_PTR) header);
    if(numbits > nbits) {
        max = nbits;
    }
    else {
        max = numbits;
    }
    for(i = 0; i < max; i++) {
        printf("%d ",(readBit(i) ? 1 : 0));
        if((i + 1) % 32 == 0) {
            printf("\n");
        }
    }
}
                
#endif
//--------------------------- Private Member Functions ------------------------

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::copy()                                      --JKH
//
// Implementation of copy construction.
//
// ARGS:       none
// RETURNS:    none
// PRE-CONDS:  none
// POST-CONDS:
//
// --All data from the bitmap will be copied.
//-----------------------------------------------------------------------------

void
NSR::Bitmap::copy(const Bitmap& bmap)
{
    nbits = bmap.nbits;
    nbytes = bmap.nbytes;
    if(bmap.bitmap == NULL) {
        bitmap = NULL;
    }
    else {
        INT32   i;
        bitmap = (BYTE_PTR)AllocateMemory(nbytes);
        if(bitmap != NULL) {
            for(i = 0; i < nbytes; i++) {
                bitmap[i] = bmap.bitmap[i];
            }
        }
    }
}

//-----------------------------------------------------------------------------
// METHOD:  Bitmap::free()                                      --JKH
//
// Frees dynamic memory associated with a Bitmap.
//
// ARGS:        none
// RETURNS:     none
// PRE-CONDS:   none
// POST-CONDS:  Dynamic memory associated with the Bitmap will be freed.
//-----------------------------------------------------------------------------

void
NSR::Bitmap::free(void)
{
    if(bitmap != NULL) {
        FreeMemory(bitmap);
        bitmap = NULL;
    }
}
