//____________________________________________________________________________
//
// (C) Copyright Seagate Software, Inc. 1994-1996
// © 1998 Seagate Software, Inc.  All rights reserved.
//
// All Rights Reserved Worldwide.
//
//____________________________________________________________________________
//
// FILE NAME :          mtf_api.c
//
// DESCRIPTION :        mtf api implementation 
//
// CREATED:             6/20/95
//
//____________________________________________________________________________
//
// $Revision:   1.35  $
//     $Date:   02 Feb 1995 15:47:04  $
//  $Modtime:   02 Feb 1995 15:37:38  $
//  
//____________________________________________________________________________
// *****************************************************************************/

#include <assert.h>
#include <time.h>
#include <string.h>
#include <wchar.h>
#include <stralign.h>

#include "stdafx.h"
#include "mtfapi.h"

static USHORT iCountMTFa = 0;  // Count of existing objects
//
//  Constructor
//
CMTFApi::CMTFApi(void)
{
    m_uAlignmentFactor = 0;

    m_iNumStrings = 0;
    for (int i = 0; i < iNUMSTRINGS; ++i){
        m_aszStrings[i] = 0;
    }

    iCountMTFa++;
}

//
// Destructor
//
CMTFApi::~CMTFApi()
{
    ClearStrings();

    iCountMTFa--;
}


/* ==================================================================================
     String Management
     When reading blocks, the strings are not null terminated -- we would like to 
     pull them out and deliver them back in the ####_INFO structures in a civilized
     (null terminated) way.  Thus, just set up an array of malloc'ec strings.  
     Each call that uses strings should first call "ClearStrings" -- strings returned
     to the user will only be good up until the next call...
================================================================================= */

// - returns the size of a wchar_t string
//   and returns zero for a null pointer
size_t CMTFApi::wstrsize(wchar_t *s)
{
    if (s)
        return wcslen(s) * sizeof(wchar_t);
    else 
        return 0;
}

// - returns the size of a wchar_t unaligned string
//   and returns zero for a null pointer
size_t CMTFApi::ua_wstrsize(wchar_t UNALIGNED *s)
{
    if (s)
        return ua_wcslen(s) * sizeof(wchar_t);
    else 
        return 0;
}


// - frees all allocated pointers in m_aszStrings and sets
//   m_iNumStrings to zero
void CMTFApi::ClearStrings()
{
    int i;
    for (i = 0; i < iNUMSTRINGS; ++i)
    {
        if (m_aszStrings[i])
            free(m_aszStrings[i]);         
        m_aszStrings[i] = 0;
    }

    m_iNumStrings = 0;
}


// - allocates a string in m_aszStrings that is a copy of pString
//   (pString need not be null terminated)
//   (note -- iSize is the size of the string in bytes -- not the length!!!!!
wchar_t * CMTFApi::MakeString(wchar_t UNALIGNED * pString, size_t iSize)
{
    size_t i;
    if (m_iNumStrings >= iNUMSTRINGS) {
        return NULL;
    }
    m_aszStrings[m_iNumStrings] = (wchar_t *)malloc(iSize + sizeof(wchar_t));
    if (!m_aszStrings[m_iNumStrings])
        return NULL;
    
    for (i = 0; i < iSize / sizeof(wchar_t); ++i)
        m_aszStrings[m_iNumStrings][i] = pString[i];
    
    m_aszStrings[m_iNumStrings][i] = L'\0';

    return m_aszStrings[m_iNumStrings++]; 
}


/* ==================================================================================
    Other data structures
================================================================================= */

#pragma pack(1)

/***********************************************************************************
************************************************************************************
************************************************************************************
****  MTF On Tape Structures 
************************************************************************************
************************************************************************************
***********************************************************************************/

/* ==================================================================================
     Common DBLK Header
     - The common dblk header exactly as it appears on tape in the head of the dblks
================================================================================== */
typedef struct { 

     UINT8              acBlockType[4];         /* 00h  Unique identifier, see above            */
     UINT32             uBlockAttributes;       /* 04h  Common attributes for this block        */
     UINT16             uOffsetToFirstStream;   /* 08h  Offset to data associated with this     */
                                                /*      DBLK, or offset to next DBLK or         */
                                                /*      filemark if there is no associated      */
                                                /*      data.                                   */
     UINT8              uOSID;                  /* 0Ah  Machine/OS id where written, low byte   */
     UINT8              uOSVersion;             /* 0Bh  Machine/OS id where written, high byte  */
     UINT64             uDisplayableSize;       /* 0Ch  Displayable data size                   */
     UINT64             uFormatLogicalAddress;  /* 14h  Logical blk address relative to SSET    */
     UINT16             uReservedForMBC;        /* 1Ch  Reserved for Media Based Catalog        */
     UINT16             uSoftwareCompression;   /* 1Eh  Software Compression Algorithm        ***/
     UINT8              acReserved1[4];         /* 20h  reserved                                */
     UINT32             uControlBlockId;        /* 24h  Used for error recovery                 */
     UINT8              acReserved2[4];         /* 28h  reserved                                */
     MTF_TAPE_ADDRESS   sOSSpecificData;        /* 2Ch  Size and offset of OS specific stuff    */
     UINT8              uStringType;            /* 30h  ASCII, Unicode, etc.                    */
     UINT8              uReserved3;             /* 31h  for alignment purposes                  */
     UINT16             uHeaderCheckSum;        /* 32h  Checksum of the block header.  The      */
                                                /*      algorithm is: XOR each word preceeding  */
                                                /*      this one and store the result here.     */
                                                /*      (When the checksum is verified the      */
                                                /*      'block_type' is also checked for a      */
                                                /*      non-zero value.                         */
} MTF_DBLK_HDR;



/* ==================================================================================
     DBLK TAPE Header
     - The TAPE DBLK, exactly as it appears on tape, including the common DBLK header (MTF_DBLK_HDR)
================================================================================== */
typedef struct {    /* MTF_DBLK_TAPE */

     MTF_DBLK_HDR        sBlockHeader;
     UINT32              uTapeFamilyId;
     UINT32              uTapeAttributes;
     UINT16              uTapeSequenceNumber;
     UINT16              uPasswordEncryptionAlgorithm;
     UINT16              uSoftFilemarkBlockSize;         /* Or ECC Algorithm */
     UINT16              uTapeCatalogType;
     MTF_TAPE_ADDRESS    sTapeName;
     MTF_TAPE_ADDRESS    sTapeDescription;
     MTF_TAPE_ADDRESS    sTapePassword;
     MTF_TAPE_ADDRESS    sSoftware_name;
     UINT16              uAlignmentFactor;
     UINT16              uSoftwareVendorId;
     MTF_DATE_TIME       sTapeDate;
     UINT8               uMTFMajorVersion;

} MTF_DBLK_TAPE;



/* ==================================================================================
     Start of Set DBLK (SSET)
     - The SSET DBLK, exactly as it appears on tape, including the common DBLK header (MTF_DBLK_HDR)
================================================================================== */
typedef struct {
     MTF_DBLK_HDR        sBlockHeader;
     UINT32              uSSETAttributes;
     UINT16              uPasswordEncryptionAlgorithm;
     UINT16              uDataEncryptionAlgorithm;  /* Or Software Compression Algorithm      ***/
     UINT16              uSoftwareVendorId;
     UINT16              uDataSetNumber;
     MTF_TAPE_ADDRESS    sDataSetName;
     MTF_TAPE_ADDRESS    sDataSetDescription;
     MTF_TAPE_ADDRESS    sDataSetPassword;
     MTF_TAPE_ADDRESS    sUserName;
     UINT64              uPhysicalBlockAddress;
     MTF_DATE_TIME       sMediaWriteDate;
     UINT8               uSoftwareVerMjr;
     UINT8               uSoftwareVerMnr;
     UINT8               uTimeZone;
     UINT8               uMTFMinorVer;
     UINT8               uTapeCatalogVersion;
} MTF_DBLK_SSET;



/* ==================================================================================
     Volume DBLK (VOLB)
     - The VOLB DBLK, exactly as it appears on tape, including the common DBLK header (MTF_DBLK_HDR)
================================================================================== */
typedef struct {
     MTF_DBLK_HDR        sBlockHeader;
     UINT32              uVolumeAttributes;
     MTF_TAPE_ADDRESS    sDeviceName;
     MTF_TAPE_ADDRESS    sVolumeName;
     MTF_TAPE_ADDRESS    sMachineName;
     MTF_DATE_TIME       sMediaWriteDate;
} MTF_DBLK_VOLB;



/* ==================================================================================
     Directory DBLK (DIRB)
     - The DIRB DBLK, exactly as it appears on tape, including the common DBLK header (MTF_DBLK_HDR)
================================================================================== */
typedef struct {
     MTF_DBLK_HDR        sBlockHeader;
     UINT32              uDirectoryAttributes;
     MTF_DATE_TIME       sLastModificationDate;
     MTF_DATE_TIME       sCreationDate;
     MTF_DATE_TIME       sBackupDate;
     MTF_DATE_TIME       sLastAccessDate;
     UINT32              uDirectoryId;
     MTF_TAPE_ADDRESS    sDirectoryName;
} MTF_DBLK_DIRB;



/* ==================================================================================
     Directory DBLK (FILE)
     - The FILE DBLK, exactly as it appears on tape, including the common DBLK header (MTF_DBLK_HDR)
================================================================================== */
typedef struct {
     MTF_DBLK_HDR        sBlockHeader;
     UINT32              uFileAttributes;
     MTF_DATE_TIME       sLastModificationDate;
     MTF_DATE_TIME       sCreationDate;
     MTF_DATE_TIME       sBackupDate;
     MTF_DATE_TIME       sLastAccessDate;
     UINT32              uDirectoryId;
     UINT32              uFileId;
     MTF_TAPE_ADDRESS    sFileName;
} MTF_DBLK_FILE;


#pragma pack()

/* ==================================================================================
     Corrupt File DBLK (CFIL)
     - use MTF_DBLK_CFIL_INFO -- same structure
================================================================================== */
typedef MTF_DBLK_CFIL_INFO MTF_DBLK_CFIL;

/* ==================================================================================
     End of Set Pad Block (ESPB)
================================================================================== */
// consists only of header

/* ==================================================================================
     End of Set Block (ESET)
     - use MTF_DBLK_ESET_INFO -- same structure
================================================================================== */
typedef MTF_DBLK_ESET_INFO MTF_DBLK_ESET;

/* ==================================================================================
     End of Set Block (EOTM)
     - use MTF_DBLK_EOTM_INFO -- same structure
================================================================================== */
typedef MTF_DBLK_EOTM_INFO MTF_DBLK_EOTM;

/* ==================================================================================
     Soft Filemark (SFMB)
     - use MTF_DBLK_SFMB_INFO -- same structure
================================================================================== */
typedef MTF_DBLK_SFMB_INFO MTF_DBLK_SFMB;

/* ==================================================================================
     StreamHeader
     - use MTF_STREAM_INFO -- same structure
================================================================================== */
typedef MTF_STREAM_INFO MTF_STREAM;


/***********************************************************************************
************************************************************************************
************************************************************************************
****  MTF Misc Data Types
************************************************************************************
************************************************************************************
***********************************************************************************/
/* ==================================================================================
     Alignment Factor
================================================================================== */

/***********************************************************************************
* MTF_SetAlignmentFactor()                                 
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetAlignmentFactor(UINT16 uAF)
{
    // store the user's alignment factor in a private member
    m_uAlignmentFactor = uAF;
}




/***********************************************************************************
* MTF_GetAlignmentFactor()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
UINT16 CMTFApi::MTF_GetAlignmentFactor()
{
    return m_uAlignmentFactor;
}




/***********************************************************************************
* MTF_PadToNextAlignmentFactor()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_PadToNextAlignmentFactor(
    BYTE     *pBuffer,    
    size_t    nBufUsed,
    size_t    nBufferSize, 
    size_t   *pnSizeUsed)
{
    size_t i;
    size_t nAlignment;
    MTF_STREAM_INFO sStream;
    
    // figure out what the next alignment value is and then pad out the user's buffer
    // with an SPAD, making sure the buffer is big enough

    nAlignment = Align(nBufUsed + sizeof(MTF_STREAM_INFO), MTF_GetAlignmentFactor());
    *pnSizeUsed = nAlignment;
    if (nBufferSize < nAlignment)
        return MTF_ERROR_BUFFER_TOO_SMALL;

    MTF_SetSTREAMDefaults(&sStream, "SPAD");
    
    sStream.uStreamLength = MTF_CreateUINT64(nAlignment - nBufUsed - sizeof(MTF_STREAM_INFO), 0);

    MTF_WriteStreamHeader(&sStream,
                          pBuffer + nBufUsed,
                          nBufferSize - nBufUsed,
                          0);

    for (i = nBufUsed + sizeof(MTF_STREAM_INFO); i < nAlignment; ++i)
        pBuffer[i] = 0;    

    return MTF_ERROR_NONE;
}     


/***********************************************************************************
* MTF_PadToNextPhysicalBlockBoundary() - (bmd)
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_PadToNextPhysicalBlockBoundary(
    BYTE *pBuffer,
    size_t nBlockSize,
    size_t nBufUsed,
    size_t nBufferSize,
    size_t *pnSizeUsed)
{
    size_t i;
    size_t nAlignment;
    MTF_STREAM_INFO sStream;

    // figure out what the next alignment value is and then pad out the user's buffer
    // with an SPAD, making sure the buffer is big enough

    nAlignment = Align(nBufUsed + sizeof(MTF_STREAM_INFO), nBlockSize);
    *pnSizeUsed = nAlignment;
    if (nBufferSize < nAlignment)
        return MTF_ERROR_BUFFER_TOO_SMALL;

    MTF_SetSTREAMDefaults(&sStream, "SPAD");

    sStream.uStreamLength = MTF_CreateUINT64(nAlignment - nBufUsed - sizeof(MTF_STREAM_INFO), 0);

    MTF_WriteStreamHeader(&sStream, pBuffer + nBufUsed, nBufferSize - nBufUsed, 0);

    for (i = nBufUsed + sizeof(MTF_STREAM_INFO); i < nAlignment; ++i)
        pBuffer[i] = 0;

    return MTF_ERROR_NONE;
}


/***********************************************************************************
* MTF_CreateUINT64()
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
UINT64 CMTFApi::MTF_CreateUINT64(UINT32 uLSB, UINT32 uMSB)
{
    UINT64 uRet;

    uRet = (UINT64) uMSB << 32;
    uRet += uLSB;
    return uRet;
}


/* ==================================================================================
     Compressed date structure for storing dates in minimal space on tape:

     BYTE 0    BYTE 1    BYTE 2    BYTE 3    BYTE 4
    76543210  76543210  76543210  76543210  76543210
    yyyyyyyy  yyyyyymm  mmdddddh  hhhhmmmm  mmssssss
    33333333  33222222  22221111  11111100  00000000
    98765432  10987654  32109876  54321098  76543210
================================================================================== */

/***********************************************************************************
* MTF_CreateDateTime()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
MTF_DATE_TIME CMTFApi::MTF_CreateDateTime(
    int iYear, 
    int iMonth, 
    int iDay, 
    int iHour, 
    int iMinute,
    int iSecond
    )
{
    MTF_DATE_TIME sDateTime = {0};

     UINT16    temp ;


    // pack the date time structure with the arguments as per the diagram above
      temp = (UINT16)iYear << 2 ;
      sDateTime.dt_field[0] = ((UINT8 *)&temp)[1] ;
      sDateTime.dt_field[1] = ((UINT8 *)&temp)[0] ;
      
      temp = (UINT16)iMonth << 6 ;
      sDateTime.dt_field[1] |= ((UINT8 *)&temp)[1] ;
      sDateTime.dt_field[2] = ((UINT8 *)&temp)[0] ;
      
      temp = (UINT16)iDay << 1 ;
      sDateTime.dt_field[2] |= ((UINT8 *)&temp)[0] ;
      
      temp = (UINT16)iHour << 4 ;
      sDateTime.dt_field[2] |= ((UINT8 *)&temp)[1] ;
      sDateTime.dt_field[3] = ((UINT8 *)&temp)[0] ;
      
      temp = (UINT16)iMinute << 6 ;
      sDateTime.dt_field[3] |= ((UINT8 *)&temp)[1] ;
      sDateTime.dt_field[4] = ((UINT8 *)&temp)[0] ;
      
      temp = (UINT16)iSecond ;
      sDateTime.dt_field[4] |= ((UINT8 *)&temp)[0] ;

    return sDateTime;    
}





/***********************************************************************************
* MTF_CreateDateTimeFromTM()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
MTF_DATE_TIME CMTFApi::MTF_CreateDateTimeFromTM(
    struct tm *pT
    )
{
    // translate call to MTF_CreateDateTime
    return MTF_CreateDateTime(pT->tm_year + 1900, pT->tm_mon + 1, pT->tm_mday, pT->tm_hour, pT->tm_min, pT->tm_sec);
}





/***********************************************************************************
* MTF_CreateDateTimeToTM()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_CreateDateTimeToTM(
    MTF_DATE_TIME *pDT, 
    struct tm     *pT
    )
{
     UINT8     temp[2] ;

    // unpack the MTF_DATE_TIME structure and store the results
     temp[0] = pDT->dt_field[1] ;
     temp[1] = pDT->dt_field[0] ;
     pT->tm_year = *((UINT16 *)temp) >> 2 ;

     temp[0] = pDT->dt_field[2] ;
     temp[1] = pDT->dt_field[1] ;
     pT->tm_mon = (*((UINT16 *)temp) >> 6) & 0x000F ;

     pT->tm_mday = (*((UINT16 *)temp) >> 1) & 0x001F ;

     temp[0] = pDT->dt_field[3] ;
     temp[1] = pDT->dt_field[2] ;
     pT->tm_hour = (*((UINT16 *)temp) >> 4) & 0x001F ;

     temp[0] = pDT->dt_field[4] ;
     temp[1] = pDT->dt_field[3] ;
     pT->tm_min = (*((UINT16 *)temp) >> 6) & 0x003F ;

     pT->tm_sec = *((UINT16 *)temp) & 0x003F ;
}




/***********************************************************************************
* MTF_CreateDateNull()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
MTF_DATE_TIME CMTFApi::MTF_CreateDateNull()
{
    MTF_DATE_TIME sDateTime = {0};
    
    return sDateTime;    
}




/***********************************************************************************
* MTF_CreateDateTimeFromFileTime()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
MTF_DATE_TIME CMTFApi::MTF_CreateDateTimeFromFileTime(
    FILETIME sFileTime
    )
{
    SYSTEMTIME sSystemTime;
    FileTimeToSystemTime(&sFileTime, &sSystemTime);

    return MTF_CreateDateTime(sSystemTime.wYear, 
                              sSystemTime.wMonth, 
                              sSystemTime.wDay, 
                              sSystemTime.wHour, 
                              sSystemTime.wMinute, 
                              sSystemTime.wSecond);
}





/***********************************************************************************
************************************************************************************
****  MTF internal HELPER FUNCITONS
************************************************************************************
***********************************************************************************/

/***********************************************************************************
* StringToTapeAddress()
*
* Description:  Used by the MTF_Write#### functions below.  Given a Buffer, an 
*               MTF_TAPE_ADDRESS struct and the current end of the string storage 
*               area in the buffer, this function appends the string to the string
*               storage area, fills in the MTF_TAPE_ADDRESS struct indicating where
*               the string was stored and returns the new end of the string storage
*               area accounting for the added string.
***********************************************************************************/
size_t CMTFApi::StringToTapeAddress(
    MTF_TAPE_ADDRESS *pAd,                  // the mtf tape address structure to fill
    BYTE             *pBuffer,              // the buffer that is being filled
    wchar_t          *str,                  // the string to store MTF style in the buffer
    size_t           uCurrentStorageOffset  // the next available point in the buffer for string storage
    )
{
    // if we have a string, 
    //      - put the size and offset in the MTF_TAPE_ADDRESS structure and then copy 
    //        the string to the pBuffer at the uCurrentStorageOffset'th byte
    // otherwise
    //      - put a zero size and offset in the MTF_TAPE_ADDRESS struct.
    // return the new end of the string storage area
    
    if (str)
    {
        pAd->uSize   = (UINT16)wstrsize(str);
        pAd->uOffset = (UINT16)uCurrentStorageOffset;
        memcpy(pBuffer + uCurrentStorageOffset, str, pAd->uSize);
        uCurrentStorageOffset += pAd->uSize;
    }
    else
    {
        pAd->uSize   = 0;
        pAd->uOffset = 0;
    }
    
    return uCurrentStorageOffset;
}



/***********************************************************************************
* Align()
*
* Description:  Given uSize and an alignment factor, retuns the value
*               of the uSize+ pad, where pad is the value necesary to 
*               get to the next alignment factor.
*               
* Returns       uSize + pad -- not just pad!
***********************************************************************************/
size_t CMTFApi::Align(
    size_t uSize, 
    size_t uAlignment)
{
    if (uSize % uAlignment)    
        return uSize - (uSize  % uAlignment) + uAlignment;
    else
        return uSize;
}




/***********************************************************************************
* CalcChecksum()
*
* Description:  returns the 16bit XOR sum of the nNum bytes starting at the UINT16
*               pointed to by pStartPtr
*               
***********************************************************************************/
UINT16 CMTFApi::CalcChecksum(
     BYTE *      pStartPtr,
     int         nNum )
{
     UINT16 resultSoFar = 0;
     UINT16 UNALIGNED *pCur = (UINT16 *) pStartPtr;
     
     while( nNum-- ) 
          resultSoFar ^= *pCur++ ;

     return( resultSoFar ) ;
}




/***********************************************************************************
* CalcChecksumOfStreamData() - (bmd)
*
* Description:  returns the 32bit XOR sum of the nNum bytes starting at the UINT64
*               pointed to by pStartPtr
*               
***********************************************************************************/
UINT32 CMTFApi::CalcChecksumOfStreamData(
     BYTE *      pStartPtr,
     int         nNum )
{
     UINT32 resultSoFar = 0;
     UINT32 UNALIGNED *pCur = (UINT32 *) pStartPtr;
     
     while( nNum-- ) 
          resultSoFar ^= *pCur++ ;

     return( resultSoFar ) ;
}


     
/***********************************************************************************
************************************************************************************
************************************************************************************
****  MTF API STRUCTURE FUNCTIONS
************************************************************************************
************************************************************************************
***********************************************************************************/

/* ==================================================================================
=====================================================================================
     Common DBLK: MTF_DBLK_HDR_INFO
=====================================================================================
================================================================================== */

// Calculates the room that will be taken up in the DBLK by strings and OS specific data
size_t CMTFApi::MTF_DBLK_HDR_INFO_CalcAddDataSize(
    MTF_DBLK_HDR_INFO *pSTDInfo
    )
{
    return pSTDInfo->uOSDataSize;
}




/***********************************************************************************
* MTF_SetDblkHdrDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetDblkHdrDefaults(
    MTF_DBLK_HDR_INFO * pStdInfo
    )
{
    int i;
    for (i = 0; i < 5; ++i)
        pStdInfo->acBlockType[i] = 0;

    pStdInfo->uBlockAttributes      = 0;
    pStdInfo->uOSID                 = 0;
    pStdInfo->uOSVersion            = 0;
    pStdInfo->uDisplayableSize      = 0;
    pStdInfo->uFormatLogicalAddress = 0;
    pStdInfo->uReservedForMBC       = 0;
    pStdInfo->uSoftwareCompression  = MTF_COMPRESS_NONE;
    pStdInfo->uControlBlockId       = 0;
    pStdInfo->pvOSData              = 0;
    pStdInfo->uOSDataSize           = 0;
    pStdInfo->uStringType           = MTF_STRING_UNICODE_STR; 
}




/***********************************************************************************
* MTF_WriteDblkHdrToBuffer()
*
* Description:  called by the MTF_Write#####() functions to format the common block 
*               header to the buffer
*               - this also calculates the header check sum and fills it in
*
* Pre:  - *puCurrentStorageOffset is the offset at where string and OS Data storage will 
*         begin in the buffer
*       - the size of the buffer has been checked and can hold any info written to it
*
* Post: - *puCurrentStorageOffset is updated to reflect any added strings or storage
*               
***********************************************************************************/
void CMTFApi::MTF_WriteDblkHdrToBuffer(
    UINT8              acID[4],                 // four byte header id to write
    UINT16             uOffsetToFirstStream,    // the size of the DBLK for which this will be a header
    MTF_DBLK_HDR_INFO *psHdrInfo,               // the header info struct to use (filled in by client)
    BYTE              *pBuffer,                 // the buffer to format to
    size_t            *puCurrentStorage)        // the point in the buffer where string and os data stroage begins
                                                // (this will be updated upon return to reflect added data to storage)
{
    MTF_DBLK_HDR *pHDR = 0;
    UINT16 uCurrentStorageOffset = 0;
    int i;

    // - if no *puCurrentStorage, we assume storage starts at 
    //   the end of the on tape MTF_DBLK_HDR structure
    if (puCurrentStorage)
        uCurrentStorageOffset = (UINT16)*puCurrentStorage;
    else
        uCurrentStorageOffset = (UINT16)sizeof(MTF_DBLK_HDR);

    pHDR = (MTF_DBLK_HDR *) pBuffer;
    
    // write in the four byte DBLK ID
    for (i = 0; i < 4; ++i)
        pHDR->acBlockType[i] = acID[i];

    pHDR->uBlockAttributes      = psHdrInfo->uBlockAttributes;
    pHDR->uOffsetToFirstStream  = uOffsetToFirstStream;
    pHDR->uOSID                 = psHdrInfo->uOSID;
    pHDR->uOSVersion            = psHdrInfo->uOSVersion;
    pHDR->uDisplayableSize      = psHdrInfo->uDisplayableSize;
    pHDR->uFormatLogicalAddress = psHdrInfo->uFormatLogicalAddress;
    pHDR->uReservedForMBC       = 0; // must be zero in backup set
    pHDR->uSoftwareCompression  = psHdrInfo->uSoftwareCompression;
    pHDR->uControlBlockId       = psHdrInfo->uControlBlockId;
    pHDR->sOSSpecificData.uSize = psHdrInfo->uOSDataSize;

    // write out the os specific data at the current storage offset and update it
    if (psHdrInfo->uOSDataSize)
    {
        pHDR->sOSSpecificData.uOffset = uCurrentStorageOffset;
        memcpy(pBuffer + uCurrentStorageOffset, psHdrInfo->pvOSData, psHdrInfo->uOSDataSize);
        uCurrentStorageOffset = uCurrentStorageOffset + psHdrInfo->uOSDataSize;
    }
    else
    {
        pHDR->sOSSpecificData.uOffset = 0;
        pHDR->sOSSpecificData.uSize   = 0;
    }

    pHDR->uStringType = psHdrInfo->uStringType;
    
    pHDR->uHeaderCheckSum = CalcChecksum(pBuffer, sizeof(MTF_DBLK_HDR) / sizeof(UINT16) - 1);
    
    if (puCurrentStorage)
        *puCurrentStorage = uCurrentStorageOffset;
}




void CMTFApi::MTF_DBLK_HDR_INFO_ReadFromBuffer(
    MTF_DBLK_HDR_INFO *psHdrInfo, 
    BYTE              *pBuffer)
{
    MTF_DBLK_HDR *pHDR = 0;
    size_t uCurrentStorageOffset = 0;
    int i;

    pHDR = (MTF_DBLK_HDR *) pBuffer;
    
    for (i = 0; i < 4; ++i)
        psHdrInfo->acBlockType[i] = pHDR->acBlockType[i];
    
    psHdrInfo->acBlockType[4] = 0;

    psHdrInfo->uOffsetToFirstStream = pHDR->uOffsetToFirstStream;
    psHdrInfo->uBlockAttributes     = pHDR->uBlockAttributes ;
    psHdrInfo->uOSID                = pHDR->uOSID;
    psHdrInfo->uOSVersion           = pHDR->uOSVersion;
    psHdrInfo->uDisplayableSize     = pHDR->uDisplayableSize;
    psHdrInfo->uFormatLogicalAddress= pHDR->uFormatLogicalAddress;
    psHdrInfo->uSoftwareCompression = pHDR->uSoftwareCompression;
    psHdrInfo->uControlBlockId      = pHDR->uControlBlockId;
    psHdrInfo->uOSDataSize          = pHDR->sOSSpecificData.uSize;
    psHdrInfo->pvOSData             = (pBuffer + pHDR->sOSSpecificData.uOffset);
    psHdrInfo->uStringType          = pHDR->uStringType;
    psHdrInfo->uHeaderCheckSum      = pHDR->uHeaderCheckSum;
}




/* ==================================================================================
=====================================================================================
     TAPE DBLK: MTF_DBLK_TAPE_INFO
=====================================================================================
================================================================================== */
// Calculates the room that will be taken up in the DBLK by strings and OS specific data
// **NOT INCLUDING THE COMMON DBLK HEADER additional info **
size_t CMTFApi::MTF_DBLK_TAPE_INFO_CalcAddDataSize(
    MTF_DBLK_TAPE_INFO *pTapeInfo
    )
{
    return wstrsize(pTapeInfo->szTapeName) +
           wstrsize(pTapeInfo->szTapeDescription) +
           wstrsize(pTapeInfo->szTapePassword) +
           wstrsize(pTapeInfo->szSoftwareName);
}



/***********************************************************************************
* MTF_SetTAPEDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetTAPEDefaults(
    MTF_DBLK_TAPE_INFO *pTapeInfo
    )
{
    time_t tTime;
    time(&tTime);

    pTapeInfo->uTapeFamilyId                = 0;
    pTapeInfo->uTapeAttributes              = 0;
    pTapeInfo->uTapeSequenceNumber          = 0;
    pTapeInfo->uPasswordEncryptionAlgorithm = MTF_PW_ENCRYPT_NONE;
    pTapeInfo->uSoftFilemarkBlockSize       = 0;
    pTapeInfo->uTapeCatalogType             = MTF_OTC_NONE; // MTF_OTC_TYPE
    pTapeInfo->szTapeName                   = 0 ;
    pTapeInfo->szTapeDescription            = 0 ;
    pTapeInfo->szTapePassword               = 0;
    pTapeInfo->szSoftwareName               = 0;
    pTapeInfo->uAlignmentFactor             = MTF_GetAlignmentFactor();
    pTapeInfo->uSoftwareVendorId            = 0;
    pTapeInfo->sTapeDate                    = MTF_CreateDateTimeFromTM(gmtime(&tTime));
    pTapeInfo->uMTFMajorVersion             = MTF_FORMAT_VER_MAJOR;
}



/***********************************************************************************
* MTF_WriteTAPEDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteTAPEDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_TAPE_INFO *psTapeInfo,  
                         BYTE               *pBuffer,     
                         size_t              nBufferSize, 
                         size_t             *pnSizeUsed)  
{
    UINT16 uOffsetToFirstStream;
    
    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_TAPE) + 
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo) + 
                           MTF_DBLK_TAPE_INFO_CalcAddDataSize(psTapeInfo));

    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream)
    {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
        
        return MTF_ERROR_BUFFER_TOO_SMALL;                        
    }    

    memset(pBuffer, 0, uOffsetToFirstStream);
    
    
    // 
    // write the header and then fill in the stuff from this info struct
    //
    {
        MTF_DBLK_TAPE *pTape = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_TAPE);

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_TAPE, 
            uOffsetToFirstStream,
            psHdrInfo, 
            pBuffer, 
            &uCurrentStorageOffset);
        
        pTape = (MTF_DBLK_TAPE *) pBuffer;
    
        pTape->uTapeFamilyId                = psTapeInfo->uTapeFamilyId;
        pTape->uTapeAttributes              = psTapeInfo->uTapeAttributes;
        pTape->uTapeSequenceNumber          = psTapeInfo->uTapeSequenceNumber;
        pTape->uPasswordEncryptionAlgorithm = psTapeInfo->uPasswordEncryptionAlgorithm;
        pTape->uSoftFilemarkBlockSize       = psTapeInfo->uSoftFilemarkBlockSize;
        pTape->uTapeCatalogType             = psTapeInfo->uTapeCatalogType;

        uCurrentStorageOffset = StringToTapeAddress(&pTape->sTapeName, pBuffer, psTapeInfo->szTapeName, uCurrentStorageOffset);
        uCurrentStorageOffset = StringToTapeAddress(&pTape->sTapeDescription, pBuffer, psTapeInfo->szTapeDescription, uCurrentStorageOffset);
        uCurrentStorageOffset = StringToTapeAddress(&pTape->sTapePassword, pBuffer, psTapeInfo->szTapePassword, uCurrentStorageOffset);
        uCurrentStorageOffset = StringToTapeAddress(&pTape->sSoftware_name, pBuffer, psTapeInfo->szSoftwareName, uCurrentStorageOffset);

        pTape->uAlignmentFactor  = psTapeInfo->uAlignmentFactor;
        pTape->uSoftwareVendorId = psTapeInfo->uSoftwareVendorId;
        pTape->sTapeDate         = psTapeInfo->sTapeDate;
        pTape->uMTFMajorVersion  = psTapeInfo->uMTFMajorVersion;
      
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
    }

    return MTF_ERROR_NONE;    
}






/***********************************************************************************
* MTF_ReadTAPEDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadTAPEDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_TAPE_INFO *psTapeInfo,  
                         BYTE               *pBuffer)     
{
    MTF_DBLK_TAPE *pTape = 0;

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    pTape = (MTF_DBLK_TAPE *) pBuffer;

    psTapeInfo->uTapeFamilyId                = pTape->uTapeFamilyId;
    psTapeInfo->uTapeAttributes              = pTape->uTapeAttributes;
    psTapeInfo->uTapeSequenceNumber          = pTape->uTapeSequenceNumber;
    psTapeInfo->uPasswordEncryptionAlgorithm = pTape->uPasswordEncryptionAlgorithm;
    psTapeInfo->uSoftFilemarkBlockSize       = pTape->uSoftFilemarkBlockSize;
    psTapeInfo->uTapeCatalogType             = pTape->uTapeCatalogType;

    psTapeInfo->uAlignmentFactor  = pTape->uAlignmentFactor;
    psTapeInfo->uSoftwareVendorId = pTape->uSoftwareVendorId;
    psTapeInfo->sTapeDate         = pTape->sTapeDate;
    psTapeInfo->uMTFMajorVersion  = pTape->uMTFMajorVersion;

    psTapeInfo->szTapeName        = MakeString((wchar_t UNALIGNED *) (pBuffer + pTape->sTapeName.uOffset), pTape->sTapeName.uSize);
    psTapeInfo->szTapeDescription = MakeString((wchar_t UNALIGNED *) (pBuffer + pTape->sTapeDescription.uOffset), pTape->sTapeDescription.uSize);
    psTapeInfo->szTapePassword    = MakeString((wchar_t UNALIGNED *) (pBuffer + pTape->sTapePassword.uOffset), pTape->sTapePassword.uSize);
    psTapeInfo->szSoftwareName    = MakeString((wchar_t UNALIGNED *) (pBuffer + pTape->sSoftware_name.uOffset), pTape->sSoftware_name.uSize);

    if ( !psTapeInfo->szTapeName || !psTapeInfo->szTapeDescription || !psTapeInfo->szTapePassword || !psTapeInfo->szSoftwareName)
        return MTF_OUT_OF_MEMORY;

    return MTF_ERROR_NONE;    
}



    
/* ==================================================================================
=====================================================================================
     SSET DBLK: MTF_DBLK_SSET_INFO
=====================================================================================
================================================================================== */

// Calculates the room that will be taken up in the DBLK by strings and OS specific data
// **NOT INCLUDING THE COMMON DBLK HEADER additional info **
size_t CMTFApi::MTF_DBLK_SSET_INFO_CalcAddDataSize(
    MTF_DBLK_SSET_INFO *pSSETInfo
    )
{
    return wstrsize(pSSETInfo->szDataSetName)         
           + wstrsize(pSSETInfo->szDataSetDescription)  
           + wstrsize(pSSETInfo->szDataSetPassword)     
           + wstrsize(pSSETInfo->szUserName);
}




/***********************************************************************************
* MTF_SetSSETDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetSSETDefaults(
    MTF_DBLK_SSET_INFO *pSSETInfo
    )
{
    time_t tTime;
    time(&tTime);

    pSSETInfo->uSSETAttributes              = 0;
    pSSETInfo->uPasswordEncryptionAlgorithm = MTF_PW_ENCRYPT_NONE;
    pSSETInfo->uDataEncryptionAlgorithm     = MTF_DATA_ENCRYPT_NONE;
    pSSETInfo->uSoftwareVendorId            = 0;
    pSSETInfo->uDataSetNumber               = 0;
    pSSETInfo->szDataSetName                = 0 ;
    pSSETInfo->szDataSetDescription         = 0 ;
    pSSETInfo->szDataSetPassword            = 0 ;
    pSSETInfo->szUserName                   = 0 ;
    pSSETInfo->uPhysicalBlockAddress        = 0;
    pSSETInfo->sMediaWriteDate              = MTF_CreateDateTimeFromTM(gmtime(&tTime));
    pSSETInfo->uSoftwareVerMjr              = 0;
    pSSETInfo->uSoftwareVerMnr              = 0;
    pSSETInfo->uTimeZone                    = MTF_LOCAL_TZ;
    pSSETInfo->uMTFMinorVer                 = MTF_FORMAT_VER_MINOR;
    pSSETInfo->uTapeCatalogVersion          = MTF_OTC_NONE;  // MTF_OTC_VERSION
}




/***********************************************************************************
* MTF_WriteSSETDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteSSETDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_SSET_INFO *psSSETInfo,  
                         BYTE               *pBuffer,     
                         size_t              nBufferSize, 
                         size_t             *pnSizeUsed)  
{
    UINT16 uOffsetToFirstStream;
    
    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_SSET) +
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo) +
                           MTF_DBLK_SSET_INFO_CalcAddDataSize(psSSETInfo));

    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream)
    {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
        
        return MTF_ERROR_BUFFER_TOO_SMALL;                        
    }    

    memset(pBuffer, 0, uOffsetToFirstStream);
    
    {
        MTF_DBLK_SSET *psSSET = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_SSET);

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_SSET, 
            uOffsetToFirstStream,
            psHdrInfo, 
            pBuffer, 
            &uCurrentStorageOffset);
        
        psSSET = (MTF_DBLK_SSET *) pBuffer;

        psSSET->uSSETAttributes              = psSSETInfo->uSSETAttributes;
        psSSET->uPasswordEncryptionAlgorithm = psSSETInfo->uPasswordEncryptionAlgorithm;
        psSSET->uDataEncryptionAlgorithm     = psSSETInfo->uDataEncryptionAlgorithm;
        psSSET->uSoftwareVendorId            = psSSETInfo->uSoftwareVendorId;
        psSSET->uDataSetNumber               = psSSETInfo->uDataSetNumber;

        uCurrentStorageOffset = StringToTapeAddress(&psSSET->sDataSetName, pBuffer, psSSETInfo->szDataSetName, uCurrentStorageOffset);
        uCurrentStorageOffset = StringToTapeAddress(&psSSET->sDataSetDescription, pBuffer, psSSETInfo->szDataSetDescription, uCurrentStorageOffset);
        uCurrentStorageOffset = StringToTapeAddress(&psSSET->sDataSetPassword, pBuffer, psSSETInfo->szDataSetPassword, uCurrentStorageOffset);
        uCurrentStorageOffset = StringToTapeAddress(&psSSET->sUserName, pBuffer, psSSETInfo->szUserName, uCurrentStorageOffset);

        psSSET->uPhysicalBlockAddress = psSSETInfo->uPhysicalBlockAddress;
        psSSET->sMediaWriteDate       = psSSETInfo->sMediaWriteDate;
        psSSET->uSoftwareVerMjr       = psSSETInfo->uSoftwareVerMjr;
        psSSET->uSoftwareVerMnr       = psSSETInfo->uSoftwareVerMnr;
        psSSET->uTimeZone             = psSSETInfo->uTimeZone;
        psSSET->uMTFMinorVer          = psSSETInfo->uMTFMinorVer;
        psSSET->uTapeCatalogVersion   = psSSETInfo->uTapeCatalogVersion;

        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
    }

    return MTF_ERROR_NONE;    
}




/***********************************************************************************
* MTF_ReadSSETDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadSSETDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_SSET_INFO *psSSETInfo,  
                         BYTE               *pBuffer)     
{
    MTF_DBLK_SSET *psSSET = 0;

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    psSSET = (MTF_DBLK_SSET *) pBuffer;

    psSSETInfo->uSSETAttributes              = psSSET->uSSETAttributes;
    psSSETInfo->uPasswordEncryptionAlgorithm = psSSET->uPasswordEncryptionAlgorithm;
    psSSETInfo->uDataEncryptionAlgorithm     = psSSET->uDataEncryptionAlgorithm;
    psSSETInfo->uSoftwareVendorId            = psSSET->uSoftwareVendorId;
    psSSETInfo->uDataSetNumber               = psSSET->uDataSetNumber;

    psSSETInfo->uPhysicalBlockAddress   = psSSET->uPhysicalBlockAddress;
    psSSETInfo->sMediaWriteDate         = psSSET->sMediaWriteDate;
    psSSETInfo->uSoftwareVerMjr         = psSSET->uSoftwareVerMjr;
    psSSETInfo->uSoftwareVerMnr         = psSSET->uSoftwareVerMnr;
    psSSETInfo->uTimeZone               = psSSET->uTimeZone;
    psSSETInfo->uMTFMinorVer            = psSSET->uMTFMinorVer;
    psSSETInfo->uTapeCatalogVersion     = psSSET->uTapeCatalogVersion;

    psSSETInfo->szDataSetName = MakeString((wchar_t UNALIGNED *) (pBuffer + psSSET->sDataSetName.uOffset), psSSET->sDataSetName.uSize);
    psSSETInfo->szDataSetDescription = MakeString((wchar_t UNALIGNED *) (pBuffer + psSSET->sDataSetDescription.uOffset), psSSET->sDataSetDescription.uSize);
    psSSETInfo->szDataSetPassword = MakeString((wchar_t UNALIGNED *) (pBuffer + psSSET->sDataSetPassword.uOffset), psSSET->sDataSetPassword.uSize);
    psSSETInfo->szUserName = MakeString((wchar_t UNALIGNED *) (pBuffer + psSSET->sUserName.uOffset), psSSET->sUserName.uSize);

    if ( !psSSETInfo->szDataSetName || !psSSETInfo->szDataSetDescription || !psSSETInfo->szDataSetPassword || !psSSETInfo->szUserName )
        return MTF_OUT_OF_MEMORY;

    return MTF_ERROR_NONE;    
}




/* ==================================================================================
=====================================================================================
     VOLB DBLK: MTF_DBLK_VOLB_INFO
=====================================================================================
================================================================================== */

// Calculates the room that will be taken up in the DBLK by strings and OS specific data
// **NOT INCLUDING THE COMMON DBLK HEADER additional info **
size_t CMTFApi::MTF_DBLK_VOLB_INFO_CalcAddDataSize(
    MTF_DBLK_VOLB_INFO *pVOLBInfo
    )
{
    return wstrsize(pVOLBInfo->szDeviceName) +
           wstrsize(pVOLBInfo->szVolumeName) +
           wstrsize(pVOLBInfo->szMachineName);
}




/***********************************************************************************
* MTF_SetVOLBDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetVOLBDefaults(MTF_DBLK_VOLB_INFO *pVOLBInfo)
{
    time_t tTime;
    time(&tTime);

    pVOLBInfo->uVolumeAttributes = 0;
    pVOLBInfo->szDeviceName      = 0 ;
    pVOLBInfo->szVolumeName      = 0 ;
    pVOLBInfo->szMachineName     = 0 ;
    pVOLBInfo->sMediaWriteDate   = MTF_CreateDateTimeFromTM(gmtime(&tTime));;
}




/***********************************************************************************
* MTF_SetVOLBForDevice()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetVOLBForDevice(MTF_DBLK_VOLB_INFO *pVOLBInfo, wchar_t *szDevice)
{
    DWORD dwBufSize = MAX_COMPUTERNAME_LENGTH + 1;
    wchar_t tempDeviceName[MTF_STRLEN+4];

    wcscpy(m_szDeviceName, szDevice);
    MTF_SetVOLBDefaults(pVOLBInfo);  // initialize

    // Determine the format and set the appropriate bit in the VOLB attributes.
    if (*(m_szDeviceName+1) == L':') {
        // drive letter w/colon format
        pVOLBInfo->uVolumeAttributes |= MTF_VOLB_DEV_DRIVE;
    }
    else if (0 == wcsncmp( m_szDeviceName, L"UNC", 3 )) {
        // UNC format
        pVOLBInfo->uVolumeAttributes |= MTF_VOLB_DEV_UNC;
    }
    else {
        // operating system specific format
        pVOLBInfo->uVolumeAttributes |= MTF_VOLB_DEV_OS_SPEC;
    }

    // need to prepend \\?\ for the GetVolumeInformation call
    wcscpy(tempDeviceName, L"\\\\?\\");
    wcscat(tempDeviceName, m_szDeviceName);

    GetVolumeInformationW(tempDeviceName, m_szVolumeName, MTF_STRLEN, 0, 0, 0, 0, 0);
    GetComputerNameW(m_szMachineName, &dwBufSize);
    
    pVOLBInfo->szDeviceName         = m_szDeviceName;
    pVOLBInfo->szVolumeName         = m_szVolumeName;
    pVOLBInfo->szMachineName        = m_szMachineName;
}




/***********************************************************************************
* MTF_WriteVOLBDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteVOLBDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_VOLB_INFO *psVOLBInfo,  
                         BYTE               *pBuffer,     
                         size_t              nBufferSize, 
                         size_t             *pnSizeUsed)  
{
    UINT16 uOffsetToFirstStream;
    
    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_VOLB) + 
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo) + 
                           MTF_DBLK_VOLB_INFO_CalcAddDataSize(psVOLBInfo));


    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream)
    {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
        
        return MTF_ERROR_BUFFER_TOO_SMALL;
    }

    memset(pBuffer, 0, uOffsetToFirstStream);
    
    {
        MTF_DBLK_VOLB *psVOLB = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_VOLB);

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_VOLB, 
            uOffsetToFirstStream,
            psHdrInfo, 
            pBuffer, 
            &uCurrentStorageOffset);
        
        psVOLB = (MTF_DBLK_VOLB *) pBuffer;

        psVOLB->uVolumeAttributes = psVOLBInfo->uVolumeAttributes;

        uCurrentStorageOffset = StringToTapeAddress(&psVOLB->sDeviceName, pBuffer, psVOLBInfo->szDeviceName, uCurrentStorageOffset);
        uCurrentStorageOffset = StringToTapeAddress(&psVOLB->sVolumeName, pBuffer, psVOLBInfo->szVolumeName, uCurrentStorageOffset);
        uCurrentStorageOffset = StringToTapeAddress(&psVOLB->sMachineName, pBuffer, psVOLBInfo->szMachineName, uCurrentStorageOffset);

        psVOLB->sMediaWriteDate = psVOLBInfo->sMediaWriteDate;

        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
    }

    return MTF_ERROR_NONE;    
}





/***********************************************************************************
* MTF_ReadVOLBDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadVOLBDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_VOLB_INFO *psVOLBInfo,  
                         BYTE               *pBuffer)     
{
    MTF_DBLK_VOLB *psVOLB = 0;

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    psVOLB = (MTF_DBLK_VOLB *) pBuffer;

    psVOLBInfo->uVolumeAttributes = psVOLB->uVolumeAttributes;

    psVOLBInfo->sMediaWriteDate = psVOLB->sMediaWriteDate;

    psVOLBInfo->szDeviceName  = MakeString((wchar_t UNALIGNED *) (pBuffer + psVOLB->sDeviceName.uOffset), psVOLB->sDeviceName.uSize);
    psVOLBInfo->szVolumeName  = MakeString((wchar_t UNALIGNED *) (pBuffer + psVOLB->sVolumeName.uOffset), psVOLB->sVolumeName.uSize);
    psVOLBInfo->szMachineName = MakeString((wchar_t UNALIGNED *) (pBuffer + psVOLB->sMachineName.uOffset), psVOLB->sMachineName.uSize);

    if ( !psVOLBInfo->szDeviceName || !psVOLBInfo->szVolumeName || !psVOLBInfo->szMachineName )
        return MTF_OUT_OF_MEMORY;

    return MTF_ERROR_NONE;    
}



/* ==================================================================================
=====================================================================================
     DIRB DBLK: MTF_DBLK_DIRB_INFO
=====================================================================================
================================================================================== */

// Calculates the room that will be taken up in the DBLK by strings and OS specific data
// **NOT INCLUDING THE COMMON DBLK HEADER additional info **
size_t CMTFApi::MTF_DBLK_DIRB_INFO_CalcAddDataSize(MTF_DBLK_DIRB_INFO *pDIRBInfo)
{
    return wstrsize(pDIRBInfo->szDirectoryName);
}




/***********************************************************************************
* MTF_SetDIRBDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetDIRBDefaults(
    MTF_DBLK_DIRB_INFO *pDIRBInfo
    )
{
    pDIRBInfo->uDirectoryAttributes  = 0;
    pDIRBInfo->sLastModificationDate = MTF_CreateDateNull();
    pDIRBInfo->sCreationDate         = MTF_CreateDateNull();
    pDIRBInfo->sBackupDate           = MTF_CreateDateNull();
    pDIRBInfo->sLastAccessDate       = MTF_CreateDateNull();
    pDIRBInfo->uDirectoryId          = 0;
    pDIRBInfo->szDirectoryName       = 0 ;
}




/***********************************************************************************
* MTF_SetDIRBFromFindData()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetDIRBFromFindData(
    MTF_DBLK_DIRB_INFO *pDIRBInfo, 
    wchar_t            *szDirectoryName, 
    WIN32_FIND_DATAW   *pFindData
    )
{
    MTF_SetDIRBDefaults(pDIRBInfo); // initialize

    if ( wcslen( szDirectoryName ) < MTF_STRLEN ) {
        wcscpy(m_szDirectoryName, szDirectoryName);
        pDIRBInfo->szDirectoryName  = m_szDirectoryName;
    }
    else {
        pDIRBInfo->uDirectoryAttributes |= MTF_DIRB_PATH_IN_STREAM;
        pDIRBInfo->szDirectoryName  = 0;
    }

    if (pFindData)
    {
        pDIRBInfo->uDirectoryAttributes |= 
            pFindData->dwFileAttributes & FILE_ATTRIBUTE_READONLY ? MTF_DIRB_READ_ONLY : 0 
            | pFindData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN  ? MTF_DIRB_HIDDEN : 0 
            | pFindData->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM  ? MTF_DIRB_SYSTEM : 0 
            | pFindData->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE ? MTF_DIRB_MODIFIED : 0; 
    
        pDIRBInfo->sLastModificationDate = MTF_CreateDateTimeFromFileTime(pFindData->ftLastWriteTime);
        pDIRBInfo->sCreationDate         = MTF_CreateDateTimeFromFileTime(pFindData->ftCreationTime);
        pDIRBInfo->sLastAccessDate       = MTF_CreateDateTimeFromFileTime(pFindData->ftLastAccessTime);
    }

    pDIRBInfo->uDirectoryId     = 0;
}


/***********************************************************************************
* MTF_WriteDIRBDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteDIRBDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_DIRB_INFO *psDIRBInfo,  
                         BYTE               *pBuffer,     
                         size_t              nBufferSize, 
                         size_t             *pnSizeUsed)  
{
    UINT16 uOffsetToFirstStream;

    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_DIRB) + 
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo) + 
                           MTF_DBLK_DIRB_INFO_CalcAddDataSize(psDIRBInfo));

    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream)
    {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
        
        return MTF_ERROR_BUFFER_TOO_SMALL;                        
    }    

    memset(pBuffer, 0, uOffsetToFirstStream);
    
    {
        MTF_DBLK_DIRB *psDIRB = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_DIRB);

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_DIRB, 
            uOffsetToFirstStream,
            psHdrInfo, 
            pBuffer, 
            &uCurrentStorageOffset);
        
        psDIRB = (MTF_DBLK_DIRB *) pBuffer;

        psDIRB->uDirectoryAttributes  = psDIRBInfo->uDirectoryAttributes;
        psDIRB->sLastModificationDate = psDIRBInfo->sLastModificationDate;
        psDIRB->sCreationDate         = psDIRBInfo->sCreationDate;
        psDIRB->sBackupDate           = psDIRBInfo->sBackupDate;
        psDIRB->sLastAccessDate       = psDIRBInfo->sLastAccessDate;
        psDIRB->uDirectoryId          = psDIRBInfo->uDirectoryId;
                              
        //
        // here, we need to turn the slashes (L'\\') to zeros (L'\0')in the directory name string... 
        // 
        {
            int i, iLen;
            wchar_t UNALIGNED *szDirectoryName = (wchar_t UNALIGNED *) (pBuffer + uCurrentStorageOffset);

            uCurrentStorageOffset = StringToTapeAddress(&psDIRB->sDirectoryName, pBuffer, psDIRBInfo->szDirectoryName, uCurrentStorageOffset);
            iLen = wstrsize(psDIRBInfo->szDirectoryName);
            for (i = 0; i < iLen; ++i)
                if (szDirectoryName[i] == L'\\')
                    szDirectoryName[i] = L'\0';
        }
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
    }

    return MTF_ERROR_NONE;    
}





/***********************************************************************************
* MTF_ReadDIRBDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadDIRBDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_DIRB_INFO *psDIRBInfo,  
                         BYTE               *pBuffer)     
{
    MTF_DBLK_DIRB *psDIRB = 0;

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    psDIRB = (MTF_DBLK_DIRB *) pBuffer;

    psDIRBInfo->uDirectoryAttributes  = psDIRB->uDirectoryAttributes;
    psDIRBInfo->sLastModificationDate = psDIRB->sLastModificationDate;
    psDIRBInfo->sCreationDate         = psDIRB->sCreationDate;
    psDIRBInfo->sBackupDate           = psDIRB->sBackupDate;
    psDIRBInfo->sLastAccessDate       = psDIRB->sLastAccessDate;
    psDIRBInfo->uDirectoryId          = psDIRB->uDirectoryId;

    psDIRBInfo->szDirectoryName = NULL;

    // 
    // we need to turn the zeros in the directory name back to slashes
    // (there are no terminating \0's in the string -- all \0's are really \\'s
    // 
    {
        wchar_t *pTmpBuffer;   
        int i;
        pTmpBuffer = (wchar_t *) malloc(psDIRB->sDirectoryName.uSize);

        if (pTmpBuffer) {

            memmove(pTmpBuffer, pBuffer + psDIRB->sDirectoryName.uOffset, psDIRB->sDirectoryName.uSize);
            for (i = 0; i < psDIRB->sDirectoryName.uSize; ++i)
                if (pTmpBuffer[i] == L'\0')
                    pTmpBuffer[i] = L'\\';
    
            psDIRBInfo->szDirectoryName = MakeString(pTmpBuffer, psDIRB->sDirectoryName.uSize);
            free(pTmpBuffer);

        }

    }

    if ( !psDIRBInfo->szDirectoryName )
        return MTF_OUT_OF_MEMORY;

    return MTF_ERROR_NONE;    
}





/* ==================================================================================
=====================================================================================
     FILE DBLK: MTF_DBLK_FILE_INFO
=====================================================================================
================================================================================== */

// Calculates the room that will be taken up in the DBLK by strings and OS specific data
// **NOT INCLUDING THE COMMON DBLK HEADER additional info **
size_t CMTFApi::MTF_DBLK_FILE_INFO_CalcAddDataSize(MTF_DBLK_FILE_INFO *pFILEInfo)
{
    return wstrsize(pFILEInfo->szFileName);
}




/***********************************************************************************
* MTF_SetFILEDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetFILEDefaults(MTF_DBLK_FILE_INFO *pFILEInfo)
{
    pFILEInfo->uFileAttributes       = 0;
    pFILEInfo->sLastModificationDate = MTF_CreateDateNull();
    pFILEInfo->sCreationDate         = MTF_CreateDateNull();
    pFILEInfo->sBackupDate           = MTF_CreateDateNull();
    pFILEInfo->sLastAccessDate       = MTF_CreateDateNull();
    pFILEInfo->uDirectoryId          = 0;
    pFILEInfo->uFileId               = 0;
    pFILEInfo->szFileName            = 0;
}





/***********************************************************************************
* MTF_SetFILEFromFindData()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetFILEFromFindData(MTF_DBLK_FILE_INFO *pFILEInfo, WIN32_FIND_DATAW *pFindData)
{
    time_t tTime;
    time(&tTime);

    MTF_SetFILEDefaults(pFILEInfo);  // initialize

    wcscpy(m_szFileName, pFindData->cFileName);

    pFILEInfo->uFileAttributes = 
        (pFindData->dwFileAttributes & FILE_ATTRIBUTE_READONLY ? MTF_FILE_READ_ONLY : 0) 
      | (pFindData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN  ? MTF_FILE_HIDDEN : 0) 
      | (pFindData->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM  ? MTF_FILE_SYSTEM : 0)
      | (pFindData->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE ? MTF_FILE_MODIFIED : 0) ;
    
    pFILEInfo->sLastModificationDate = MTF_CreateDateTimeFromFileTime(pFindData->ftLastWriteTime);
    pFILEInfo->sCreationDate         = MTF_CreateDateTimeFromFileTime(pFindData->ftCreationTime);
    pFILEInfo->sLastAccessDate       = MTF_CreateDateTimeFromFileTime(pFindData->ftLastAccessTime);
    pFILEInfo->uDirectoryId          = 0;
    pFILEInfo->uFileId               = 0;
    pFILEInfo->szFileName            = m_szFileName;

    pFILEInfo->uDisplaySize          = MTF_CreateUINT64(pFindData->nFileSizeLow, pFindData->nFileSizeHigh);

}





/***********************************************************************************
* MTF_WriteFILEDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteFILEDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_FILE_INFO *psFILEInfo,  
                         BYTE               *pBuffer,     
                         size_t              nBufferSize, 
                         size_t             *pnSizeUsed)  
{
    UINT16 uOffsetToFirstStream;
    
    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_FILE) + 
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo) + 
                           MTF_DBLK_FILE_INFO_CalcAddDataSize(psFILEInfo));

    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);
    if (nBufferSize < uOffsetToFirstStream)
    {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
        
        return MTF_ERROR_BUFFER_TOO_SMALL;                        
    }    

    memset(pBuffer, 0, uOffsetToFirstStream);
    
    {
        MTF_DBLK_FILE *psFILE = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_FILE);
        psHdrInfo->uDisplayableSize = psFILEInfo->uDisplaySize;

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_FILE, 
            uOffsetToFirstStream,
            psHdrInfo, 
            pBuffer, 
            &uCurrentStorageOffset);
        
        psFILE = (MTF_DBLK_FILE *) pBuffer;

        psFILE->uFileAttributes         = psFILEInfo->uFileAttributes;
        psFILE->sLastModificationDate   = psFILEInfo->sLastModificationDate;
        psFILE->sCreationDate           = psFILEInfo->sCreationDate;
        psFILE->sBackupDate             = psFILEInfo->sBackupDate;
        psFILE->sLastAccessDate         = psFILEInfo->sLastAccessDate;
        psFILE->uDirectoryId            = psFILEInfo->uDirectoryId;
        psFILE->uFileId                 = psFILEInfo->uFileId;

        uCurrentStorageOffset = StringToTapeAddress(&psFILE->sFileName, pBuffer, psFILEInfo->szFileName, uCurrentStorageOffset);

        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
    }

    return MTF_ERROR_NONE;    
}





/***********************************************************************************
* MTF_ReadFILEDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadFILEDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_FILE_INFO *psFILEInfo,  
                         BYTE               *pBuffer)     
{
    MTF_DBLK_FILE *psFILE = 0;

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    psFILE = (MTF_DBLK_FILE *) pBuffer;

    psFILEInfo->uFileAttributes         = psFILE->uFileAttributes;
    psFILEInfo->sLastModificationDate   = psFILE->sLastModificationDate;
    psFILEInfo->sCreationDate           = psFILE->sCreationDate;
    psFILEInfo->sBackupDate             = psFILE->sBackupDate;
    psFILEInfo->sLastAccessDate         = psFILE->sLastAccessDate;
    psFILEInfo->uDirectoryId            = psFILE->uDirectoryId;
    psFILEInfo->uFileId                 = psFILE->uFileId;

    psFILEInfo->szFileName              = MakeString((wchar_t UNALIGNED *) (pBuffer + psFILE->sFileName.uOffset), psFILE->sFileName.uSize);

    if ( !psFILEInfo->szFileName )
        return MTF_OUT_OF_MEMORY;

    return MTF_ERROR_NONE;    
}




/* ==================================================================================
=====================================================================================
     CFIL DBLK: MTF_DBLK_CFIL_INFO
=====================================================================================
================================================================================== */

/***********************************************************************************
* MTF_SetCFILDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetCFILDefaults(
    MTF_DBLK_CFIL_INFO *pCFILInfo
    )
{
    pCFILInfo->uCFileAttributes     = MTF_CFIL_UNREADABLE_BLK;
    pCFILInfo->uDirectoryId         = 0;
    pCFILInfo->uFileId              = 0;
    pCFILInfo->uStreamOffset        = 0;
    pCFILInfo->uCorruptStreamNumber = 0;
}




/***********************************************************************************
* MTF_WriteCFILDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteCFILDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_CFIL_INFO *psCFILInfo,  
                         BYTE               *pBuffer,     
                         size_t              nBufferSize, 
                         size_t             *pnSizeUsed)  
{
    UINT16 uOffsetToFirstStream;


    
    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_HDR) + 
                           sizeof(MTF_DBLK_CFIL) +
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo));

    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream)
    {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
        
        return MTF_ERROR_BUFFER_TOO_SMALL;                        
    }    

    memset(pBuffer, 0, uOffsetToFirstStream);
    
    {
        MTF_DBLK_CFIL_INFO *psCFIL = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_HDR) + sizeof(MTF_DBLK_CFIL);

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_CFIL, 
            uOffsetToFirstStream,
            psHdrInfo, 
            pBuffer, 
            &uCurrentStorageOffset);
        
        psCFIL = (MTF_DBLK_CFIL_INFO *)  (pBuffer + sizeof(MTF_DBLK_HDR));

        *psCFIL = *psCFILInfo;

        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
    }

    return MTF_ERROR_NONE;    
}




/***********************************************************************************
* MTF_ReadCFILDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadCFILDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_CFIL_INFO *psCFILInfo,  
                         BYTE               *pBuffer)     
{
    MTF_DBLK_CFIL *psCFIL = 0;

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    psCFIL = (MTF_DBLK_CFIL_INFO *)  (pBuffer + sizeof(MTF_DBLK_HDR));

    *psCFILInfo = *psCFIL;

    return MTF_ERROR_NONE;    
}


/* ==================================================================================
=====================================================================================
     ESPB DBLK
=====================================================================================
================================================================================== */

/***********************************************************************************
* MTF_WriteESPBDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteESPBDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         BYTE               *pBuffer,
                         size_t              nBufferSize,
                         size_t             *pnSizeUsed)

{
    UINT16 uOffsetToFirstStream;

    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_HDR) + 
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo));

    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream) {
        if (pnSizeUsed) {
            *pnSizeUsed = uOffsetToFirstStream;
        }

        return MTF_ERROR_BUFFER_TOO_SMALL;                
    }

    memset(pBuffer, 0, uOffsetToFirstStream);

    MTF_WriteDblkHdrToBuffer(
        (UINT8 *)(char *)MTF_ID_ESPB,
        uOffsetToFirstStream,
        psHdrInfo,
        pBuffer,
        0);

    if (pnSizeUsed)
        *pnSizeUsed = uOffsetToFirstStream;

    return MTF_ERROR_NONE;    
}                                             




/***********************************************************************************
* MTF_ReadESPBDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadESPBDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         BYTE               *pBuffer)     
{
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    return MTF_ERROR_NONE;    
}                            




/* ==================================================================================
=====================================================================================
     End of Set DBLK (ESET)
=====================================================================================
================================================================================== */

/***********************************************************************************
* MTF_SetESETDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetESETDefaults(MTF_DBLK_ESET_INFO *pESETInfo)
{
    time_t tTime;
    time(&tTime);

    pESETInfo->uESETAttributes          = 0;
    pESETInfo->uNumberOfCorrupFiles     = 0;
    pESETInfo->uSetMapPBA               = 0;
    pESETInfo->uFileDetailPBA           = 0;
    pESETInfo->uFDDTapeSequenceNumber   = 0;
    pESETInfo->uDataSetNumber           = 0;
    pESETInfo->sMediaWriteDate          = MTF_CreateDateTimeFromTM(gmtime(&tTime));
}





/***********************************************************************************
* MTF_WriteESETDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteESETDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_ESET_INFO *psESETInfo,  
                         BYTE               *pBuffer,     
                         size_t              nBufferSize, 
                         size_t             *pnSizeUsed)  
{
    UINT16 uOffsetToFirstStream;
    
    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_ESET) +
                           sizeof(MTF_DBLK_HDR) +  
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo));
                        
    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream)
    {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
        
        return MTF_ERROR_BUFFER_TOO_SMALL;                        
    }    

    memset(pBuffer, 0, uOffsetToFirstStream);
    
    {
        MTF_DBLK_ESET_INFO *psESET = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_ESET) + sizeof(MTF_DBLK_HDR);

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_ESET, 
            uOffsetToFirstStream,
            psHdrInfo, 
            pBuffer, 
            &uCurrentStorageOffset);
        
        psESET = (MTF_DBLK_ESET_INFO *) (pBuffer + sizeof(MTF_DBLK_HDR));

        *psESET = *psESETInfo;

        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
    }

    return MTF_ERROR_NONE;    
}





/***********************************************************************************
* MTF_ReadESETDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadESETDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_ESET_INFO *psESETInfo,  
                         BYTE               *pBuffer)     
{
    MTF_DBLK_ESET *psESET = 0;

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    psESET = (MTF_DBLK_ESET_INFO *) (pBuffer + sizeof(MTF_DBLK_HDR));

    *psESETInfo = *psESET;

    return MTF_ERROR_NONE;    
}




/* ==================================================================================
=====================================================================================
     End of Set DBLK (EOTM)
=====================================================================================
================================================================================== */
/***********************************************************************************
* MTF_SetEOTMDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetEOTMDefaults(MTF_DBLK_EOTM_INFO *pEOTMInfo)
{
    pEOTMInfo->uLastESETPBA = 0;
}





/***********************************************************************************
* MTF_WriteEOTMDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteEOTMDblk( MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_EOTM_INFO *psEOTMInfo,  
                         BYTE               *pBuffer,     
                         size_t              nBufferSize, 
                         size_t             *pnSizeUsed)  
{
    UINT16 uOffsetToFirstStream;
    
    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    uOffsetToFirstStream = (UINT16) (sizeof(MTF_DBLK_EOTM_INFO) + 
                           sizeof(MTF_DBLK_HDR) + 
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo));

    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream)
        {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
        
        return MTF_ERROR_BUFFER_TOO_SMALL;                        
        }    

    memset(pBuffer, 0, uOffsetToFirstStream);
    
    {
        MTF_DBLK_EOTM_INFO *psEOTM = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_HDR) + sizeof(MTF_DBLK_EOTM);

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_EOTM, 
            uOffsetToFirstStream,
            psHdrInfo, 
            pBuffer, 
            &uCurrentStorageOffset);
        
        psEOTM = (MTF_DBLK_EOTM_INFO *) (pBuffer + sizeof(MTF_DBLK_HDR));

        *psEOTM = *psEOTMInfo;

        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;
    }

    return MTF_ERROR_NONE;    
}




/***********************************************************************************
* MTF_ReadEOTMDblk()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadEOTMDblk(  MTF_DBLK_HDR_INFO  *psHdrInfo,
                         MTF_DBLK_EOTM_INFO *psEOTMInfo,  
                         BYTE               *pBuffer)     
{
    MTF_DBLK_EOTM *psEOTM = 0;

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    psEOTM = (MTF_DBLK_EOTM_INFO *) (pBuffer + sizeof(MTF_DBLK_HDR));

    *psEOTMInfo = *psEOTM;

    return MTF_ERROR_NONE;    
}


/* ==================================================================================
=====================================================================================
     Soft Filemark (SFMB)
=====================================================================================
================================================================================== */
/***********************************************************************************
* MTF_CreateSFMB() - (bmd)
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
size_t CMTFApi::MTF_GetMaxSoftFilemarkEntries(size_t nBlockSize)
{
    size_t n;

    if (0 == nBlockSize || nBlockSize % 512) {
        return 0;
    }

    // The SFMB fills the entire block.
    // Calculate the total number of entries that fit within a block
    // such that MTF_DBLK_HDR + MTF_DBLK_SFMB + (n-1 elements) < nBlockSize
    n = (nBlockSize - sizeof(MTF_DBLK_HDR) - sizeof(MTF_DBLK_SFMB) + sizeof(UINT32))/sizeof(UINT32);

    return n;
}

/***********************************************************************************
* MTF_InsertSoftFilemark() - (bmd)
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_InsertSoftFilemark(MTF_DBLK_SFMB_INFO *psSoftInfo,
                            UINT32 pba)
{
    size_t n;
    size_t bytesToShift;

    // We insert a filemark entry by shifting all the entries down.  The one closest BOM
    // eventually drop out of the array.

    if (psSoftInfo) {
        n = psSoftInfo->uNumberOfFilemarkEntries;

        bytesToShift = psSoftInfo->uFilemarkEntriesUsed * sizeof(UINT32);

        // So we don't overwrite memory.
        bytesToShift -= (psSoftInfo->uFilemarkEntriesUsed < psSoftInfo->uNumberOfFilemarkEntries) ? 0 : sizeof(UINT32);
    
        memmove(&psSoftInfo->uFilemarkArray[1], &psSoftInfo->uFilemarkArray[0], bytesToShift);

        psSoftInfo->uFilemarkArray[0] = pba;

        if (psSoftInfo->uFilemarkEntriesUsed < psSoftInfo->uNumberOfFilemarkEntries) {
            psSoftInfo->uFilemarkEntriesUsed++;
        }
    }
}


/***********************************************************************************
* MTF_WriteSFMBDblk() - (bmd)
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteSFMBDblk(MTF_DBLK_HDR_INFO *psHdrInfo,
                        MTF_DBLK_SFMB_INFO *psSoftInfo,
                        BYTE *pBuffer,
                        size_t nBufferSize,
                        size_t *pnSizeUsed)
{
    UINT16 uOffsetToFirstStream;
    size_t sizeOfSFMB;

    if (NULL == psHdrInfo || NULL == psSoftInfo || NULL == pBuffer || NULL == pnSizeUsed || 0 == nBufferSize) {
        return ERROR_INVALID_PARAMETER;
    }
    // Code assumes sizeof(MTF_DBLK_SFMB_INFO) == sizeof(MTF_DBLK_SFMB)
    if (sizeof(MTF_DBLK_SFMB_INFO) != sizeof(MTF_DBLK_SFMB)) {
        return ERROR_INVALID_FUNCTION;
    }

    //
    // Figure the size of the entire DBLK & make sure we have room
    //
    sizeOfSFMB = sizeof(MTF_DBLK_SFMB) + (psSoftInfo->uNumberOfFilemarkEntries-1)*sizeof(UINT32);

    uOffsetToFirstStream = (UINT16) (sizeOfSFMB +
                           sizeof(MTF_DBLK_HDR) +
                           MTF_DBLK_HDR_INFO_CalcAddDataSize(psHdrInfo));

    uOffsetToFirstStream = (UINT16)Align(uOffsetToFirstStream, 4);

    if (nBufferSize < uOffsetToFirstStream)
        {
        if (pnSizeUsed)
            *pnSizeUsed = uOffsetToFirstStream;

        return MTF_ERROR_BUFFER_TOO_SMALL;                        
        }    

    memset(pBuffer, 0, uOffsetToFirstStream);

    {
        MTF_DBLK_SFMB_INFO *psSFMB = 0;
        size_t uCurrentStorageOffset = 0;

        uCurrentStorageOffset = sizeof(MTF_DBLK_HDR) + sizeOfSFMB;

        MTF_WriteDblkHdrToBuffer(
            (UINT8 *)(char *)MTF_ID_SFMB,
            uOffsetToFirstStream,
            psHdrInfo,
            pBuffer,
            &uCurrentStorageOffset);

        psSFMB = (MTF_DBLK_SFMB *) (pBuffer + sizeof(MTF_DBLK_HDR));

        // Need a deep copy since MTF_DBLK_SFMB_INFO holds a placeholder for the array.
        memcpy(psSFMB, psSoftInfo, sizeOfSFMB);

        if (pnSizeUsed) {
            *pnSizeUsed = uOffsetToFirstStream;
        }
    }

    return MTF_ERROR_NONE;
}

/***********************************************************************************
* MTF_ReadSFMBDblk() - (bmd)
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadSFMBDblk(MTF_DBLK_HDR_INFO *psHdrInfo,
                       MTF_DBLK_SFMB_INFO *psSoftInfo,
                       BYTE *pBuffer)
{
    MTF_DBLK_SFMB *psSFMB = 0;
    size_t sizeOfSFMB;

    if (NULL == psHdrInfo || NULL == psSoftInfo || NULL == pBuffer) {
        return ERROR_INVALID_PARAMETER;
    }
    // Code assumes sizeof(MTF_DBLK_SFMB_INFO) == sizeof(MTF_DBLK_SFMB)
    if (sizeof(MTF_DBLK_SFMB_INFO) != sizeof(MTF_DBLK_SFMB)) {
        return ERROR_INVALID_FUNCTION;
    }

    ClearStrings();
    MTF_DBLK_HDR_INFO_ReadFromBuffer(psHdrInfo, pBuffer);

    psSFMB = (MTF_DBLK_SFMB *) (pBuffer + sizeof(MTF_DBLK_HDR));

    // Need a deep copy since MTF_DBLK_SFMB_INFO holds a placeholder for the array.
    sizeOfSFMB = sizeof(MTF_DBLK_SFMB) + (psSFMB->uNumberOfFilemarkEntries-1)*sizeof(UINT32);
    memcpy(psSoftInfo, psSFMB, sizeOfSFMB);

    return MTF_ERROR_NONE;
}

/* ==================================================================================
=====================================================================================
     STREAM HEADER
=====================================================================================
================================================================================== */

/***********************************************************************************
* MTF_SetSTREAMDefaults()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetSTREAMDefaults(MTF_STREAM_INFO *pSTREAMInfo, char *szId)
{
    memcpy(pSTREAMInfo->acStreamId, szId, 4);
    pSTREAMInfo->uStreamFileSystemAttributes = 0;
    pSTREAMInfo->uStreamTapeFormatAttributes = 0;
    pSTREAMInfo->uStreamLength               = 0;
    pSTREAMInfo->uDataEncryptionAlgorithm    = 0;
    pSTREAMInfo->uDataCompressionAlgorithm   = 0;
    pSTREAMInfo->uCheckSum                   = 0;
}




/***********************************************************************************
* MTF_SetSTREAMFromStreamId()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetSTREAMFromStreamId(
    MTF_STREAM_INFO *pSTREAMInfo, 
    WIN32_STREAM_ID *pStreamId, 
    size_t           nIDHeaderSize
    )
{

// From Steve DeVos, Seagate:
//   > BACKUP_INVALID and BACKUP_LINK will never be returned from BackupRead.
//   >
//   > -Steve
//
// TODO:  MTF_NT_ENCRYPTED_STREAM     "NTED"; These retrieved by NT Encyption APIs
// TODO:  MTF_NT_QUOTA_STREAM         "NTQU"; These retrieved by NT Quota APIs

    MTF_SetSTREAMDefaults(pSTREAMInfo, "UNKN");

    if (pStreamId->dwStreamId == BACKUP_DATA)
        memcpy(pSTREAMInfo->acStreamId, "STAN", 4);
    else if (pStreamId->dwStreamId == BACKUP_EA_DATA)
        memcpy(pSTREAMInfo->acStreamId, "NTEA", 4);
    else if (pStreamId->dwStreamId == BACKUP_SECURITY_DATA)
        memcpy(pSTREAMInfo->acStreamId, "NACL", 4);
    else if (pStreamId->dwStreamId == BACKUP_ALTERNATE_DATA)
        memcpy(pSTREAMInfo->acStreamId, "ADAT", 4);
    else if (pStreamId->dwStreamId == BACKUP_OBJECT_ID)
        memcpy(pSTREAMInfo->acStreamId, "NTOI", 4);
    else if (pStreamId->dwStreamId == BACKUP_REPARSE_DATA)
        memcpy(pSTREAMInfo->acStreamId, "NTRP", 4);
    else if (pStreamId->dwStreamId == BACKUP_SPARSE_BLOCK)
        memcpy(pSTREAMInfo->acStreamId, "SPAR", 4);
    else {
        pSTREAMInfo->uStreamFileSystemAttributes |= MTF_STREAM_IS_NON_PORTABLE;
    }

    if (pStreamId->dwStreamAttributes & STREAM_MODIFIED_WHEN_READ)
        pSTREAMInfo->uStreamFileSystemAttributes |= MTF_STREAM_MODIFIED_BY_READ;
    if (pStreamId->dwStreamAttributes & STREAM_CONTAINS_SECURITY)
        pSTREAMInfo->uStreamFileSystemAttributes |= MTF_STREAM_CONTAINS_SECURITY;
    if (pStreamId->dwStreamAttributes & STREAM_SPARSE_ATTRIBUTE)
        pSTREAMInfo->uStreamFileSystemAttributes |= MTF_STREAM_IS_SPARSE;

    pSTREAMInfo->uStreamTapeFormatAttributes = 0;
    pSTREAMInfo->uStreamLength               = MTF_CreateUINT64(pStreamId->Size.LowPart, pStreamId->Size.HighPart) + nIDHeaderSize;
    pSTREAMInfo->uDataEncryptionAlgorithm    = 0;
    pSTREAMInfo->uDataCompressionAlgorithm   = 0;
    pSTREAMInfo->uCheckSum                   = 0;
}




/***********************************************************************************
* MTF_SetStreamIdFromSTREAM() - (bmd)                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
void CMTFApi::MTF_SetStreamIdFromSTREAM(
    WIN32_STREAM_ID *pStreamId, 
    MTF_STREAM_INFO *pSTREAMInfo, 
    size_t           nIDHeaderSize
    )
{
    UNREFERENCED_PARAMETER(nIDHeaderSize);

    memset( pStreamId, 0, sizeof( WIN32_STREAM_ID ) );

    if (0 == memcmp(pSTREAMInfo->acStreamId, "STAN", 4))
        pStreamId->dwStreamId = BACKUP_DATA;
    else if (0 == memcmp(pSTREAMInfo->acStreamId, "NTEA", 4))
        pStreamId->dwStreamId = BACKUP_EA_DATA;
    else if (0 == memcmp(pSTREAMInfo->acStreamId, "NACL", 4))
        pStreamId->dwStreamId = BACKUP_SECURITY_DATA;
    else if (0 == memcmp(pSTREAMInfo->acStreamId, "ADAT", 4))
        pStreamId->dwStreamId = BACKUP_ALTERNATE_DATA;
    else if (0 == memcmp(pSTREAMInfo->acStreamId, "NTOI", 4))
        pStreamId->dwStreamId = BACKUP_OBJECT_ID;
    else if (0 == memcmp(pSTREAMInfo->acStreamId, "NTRP", 4))
        pStreamId->dwStreamId = BACKUP_REPARSE_DATA;
    else if (0 == memcmp(pSTREAMInfo->acStreamId, "SPAR", 4))
        pStreamId->dwStreamId = BACKUP_SPARSE_BLOCK;
    else {
        pStreamId->dwStreamId = BACKUP_INVALID;
    }

    pStreamId->dwStreamAttributes = STREAM_NORMAL_ATTRIBUTE;
    if (pSTREAMInfo->uStreamFileSystemAttributes & MTF_STREAM_MODIFIED_BY_READ)
        pStreamId->dwStreamAttributes |= STREAM_MODIFIED_WHEN_READ;
    if (pSTREAMInfo->uStreamFileSystemAttributes & MTF_STREAM_CONTAINS_SECURITY)
        pStreamId->dwStreamAttributes |= STREAM_CONTAINS_SECURITY;
    if (pSTREAMInfo->uStreamFileSystemAttributes & MTF_STREAM_IS_SPARSE)
        pStreamId->dwStreamAttributes |= STREAM_SPARSE_ATTRIBUTE;

    // TODO: Handle named data streams (size of name and in MTF stream)
    //       ? How do I know ?

    pStreamId->Size.LowPart  = (DWORD)((pSTREAMInfo->uStreamLength << 32) >>32);
    pStreamId->Size.HighPart = (DWORD)(pSTREAMInfo->uStreamLength >> 32);

}





/***********************************************************************************
* MTF_WriteStreamHeader()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteStreamHeader(MTF_STREAM_INFO *psStreamInfo,  
                            BYTE            *pBuffer,     
                            size_t           nBufferSize, 
                            size_t          *pnSizeUsed) 

{

    psStreamInfo->uCheckSum = CalcChecksum((BYTE *) psStreamInfo, sizeof(MTF_STREAM_INFO) / sizeof(UINT16) - 1);

    if (nBufferSize < sizeof(MTF_STREAM_INFO))
    {
        if (pnSizeUsed)
            *pnSizeUsed = sizeof(MTF_STREAM_INFO);
        
        return MTF_ERROR_BUFFER_TOO_SMALL;                        
    }    

    memset(pBuffer, 0, sizeof(MTF_STREAM_INFO));
    
    
    *((MTF_STREAM_INFO *) pBuffer) = *psStreamInfo;

    if (pnSizeUsed)
        *pnSizeUsed = sizeof(MTF_STREAM_INFO);


    return MTF_ERROR_NONE;    
}




/***********************************************************************************
* MTF_WriteNameStream() - (bmd)
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_WriteNameStream(
    char *szType,
    wchar_t *szName,
    BYTE *pBuffer,
    size_t nBufferSize,
    size_t *pnSizeUsed)
{
    MTF_STREAM_INFO sStream;
    UINT16 uOffsetToCSUMStream;
    UINT16 uOffsetToNextStream;
    size_t nBufUsed;
    UINT16 nameSize;
    UINT32 nameChecksum;

    //
    // Figure the size of the entire Name stream including trailing CSUM and make sure we have room.
    //
    nameSize = (UINT16)wstrsize(szName);  // including terminating '\0'

    uOffsetToCSUMStream = sizeof(MTF_STREAM_INFO) + nameSize;
    uOffsetToCSUMStream = (UINT16)Align(uOffsetToCSUMStream, 4);

    uOffsetToNextStream = uOffsetToCSUMStream;

    uOffsetToNextStream += sizeof(MTF_STREAM_INFO) + 4; // includes 4 byte CSUM data
    uOffsetToNextStream = (UINT16)Align(uOffsetToNextStream, 4);

    if (nBufferSize < uOffsetToNextStream) {
        return MTF_ERROR_BUFFER_TOO_SMALL;
    }

    memset(pBuffer, 0, uOffsetToNextStream);

    MTF_SetSTREAMDefaults(&sStream, szType);
    sStream.uStreamLength = nameSize;
    sStream.uStreamTapeFormatAttributes |= MTF_STREAM_CHECKSUMED;
    MTF_WriteStreamHeader(&sStream, pBuffer, nBufferSize, &nBufUsed);

    memcpy(pBuffer + nBufUsed, szName, nameSize);

    if ( 0 == memcmp(sStream.acStreamId, "PNAM", 4) ) {
        //
        // here, we need to turn the slashes (L'\\') to zeros (L'\0')in the directory name string... 
        //
        int i, iLen;
        wchar_t UNALIGNED *szDirectoryName = (wchar_t UNALIGNED *) (pBuffer + nBufUsed);

        iLen = ua_wstrsize(szDirectoryName);
        for (i = 0; i < iLen; ++i)
            if (szDirectoryName[i] == L'\\')
                szDirectoryName[i] = L'\0';
    }

    // For Name streams, we always tack on a CSUM

    nameChecksum = CalcChecksumOfStreamData(pBuffer + nBufUsed, nameSize / sizeof(UINT32) + 1);

    MTF_SetSTREAMDefaults(&sStream, MTF_CHECKSUM_STREAM);
    sStream.uStreamLength = sizeof(nameChecksum);
    MTF_WriteStreamHeader(&sStream, pBuffer + uOffsetToCSUMStream, nBufferSize, &nBufUsed);

    memcpy(pBuffer + uOffsetToCSUMStream + nBufUsed, &nameChecksum, sizeof(nameChecksum));

    if (pnSizeUsed)
        *pnSizeUsed = uOffsetToNextStream;

    return MTF_ERROR_NONE;
}




/***********************************************************************************
* MTF_ReadStreamHeader()                                        
*                                                            ** MTF API FUNCTION ** 
***********************************************************************************/
DWORD CMTFApi::MTF_ReadStreamHeader(MTF_STREAM_INFO   *psStreamInfo,  
                          BYTE              *pBuffer)    

{
    *psStreamInfo = *((MTF_STREAM_INFO *) pBuffer);
    return MTF_ERROR_NONE;    
}




