/*
** header.c - Routines used to access compressed file header information.
**
** written by DavidDi
*/


// Headers
///////////

#ifndef LZA_DLL

#include <io.h>
#include <dos.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

#endif

#include "lz_common.h"
#include "lz_buffers.h"
#include "lz_header.h"


/*
** int WriteHdr(PFH pFH, int doshDest);
**
** Write compressed file header to output file.
**
** Arguments:  pFH      - pointer to source header information structure
**             doshDest - DOS file handle of open output file
**
** Returns:    int - TRUE if successful.  LZERROR_BADOUTHANDLE if
**                   unsuccessful.
**
** Globals:    none
**
** header format:
**                8 bytes  -->   compressed file signature
**                1 byte   -->   algorithm label
**                1 byte   -->   extension char
**                4 bytes  -->   uncompressed file size (LSB to MSB)
**
**       length = 14 bytes
*/
INT WriteHdr(PFH pFH, INT doshDest, PLZINFO pLZI)
{
   INT i, j;
   DWORD ucbWritten;
   BYTE rgbyteHeaderBuf[HEADER_LEN];   // temporary storage for next header byte to write

   // Sanity check
   if (!pLZI) {
      return(LZERROR_GLOBLOCK);
   }

   // Copy the compressed file signature.
   for (i = 0; i < COMP_SIG_LEN; i++)
      rgbyteHeaderBuf[i] = pFH->rgbyteMagic[i];

   // Copy the algorithm label and file name extension character.
   rgbyteHeaderBuf[i++] = pFH->byteAlgorithm;
   rgbyteHeaderBuf[i++] = pFH->byteExtensionChar;

   // Copy input file size (long ==> 4 bytes),
   // LSB first to MSB last.
   for (j = 0; j < 4; j++)
      rgbyteHeaderBuf[i++] = (BYTE)((pFH->cbulUncompSize >> (8 * j)) &
                                    (DWORD)BYTE_MASK);

   // Write header to file.
   if ((ucbWritten = FWRITE(doshDest, rgbyteHeaderBuf, HEADER_LEN)) != HEADER_LEN)
   {
#ifdef LZA_DLL
      if (ucbWritten == (DWORD)(-1))
#else
      if (_error != 0U)
#endif
         // Bad DOS file handle.
         return(LZERROR_BADOUTHANDLE);
      else
         // Insufficient space on destination drive.
         return(LZERROR_WRITE);
   }

   // Keep track of bytes written.
   pLZI->cblOutSize += (LONG)ucbWritten;

   // Header written ok.
   return(TRUE);
}


/*
** int GetHdr(PFH pFH, int doshSource);
**
** Get compressed file header.
**
** Arguments:  pFH        - pointer to destination header information structure
**             doshSource - DOS file handle of open input file
**
** Returns:    int - TRUE if compressed file header read successfully.  One
**                   the LZERROR_ codes if not.
**
** Globals:    none
*/
INT GetHdr(PFH pFH, INT doshSource, LONG *pcblInSize)
{
   DWORD ucbRead;
   BYTE rgbyteHeaderBuf[HEADER_LEN];
   INT i, j;

   // Get input file length and move back to beginning of input file.
   if ((*pcblInSize = FSEEK(doshSource, 0L, SEEK_END)) <  0L ||
       FSEEK(doshSource, 0L, SEEK_SET) != 0L)
      return(LZERROR_BADINHANDLE);

   if ((ucbRead = FREAD(doshSource, rgbyteHeaderBuf, HEADER_LEN))
       != HEADER_LEN)
   {
#ifdef LZA_DLL
      if (ucbRead == (DWORD)(-1))
#else
      if (_error != 0U)
#endif
         // We were handed a bad input file handle.
         return((INT)LZERROR_BADINHANDLE);
      else
         // Input file shorter than compressed header size.
         return(LZERROR_READ);
   }

   // Put compressed file signature into rgbyteMagic[] of header info struct.
   for (i = 0; i < COMP_SIG_LEN; i++)
      pFH->rgbyteMagic[i] = rgbyteHeaderBuf[i];

   // Get algorithm label and file name extension character.
   pFH->byteAlgorithm = rgbyteHeaderBuf[i++];
   pFH->byteExtensionChar = rgbyteHeaderBuf[i++];

   // Extract uncompressed file size, LSB --> MSB (4 bytes in long).
   pFH->cbulUncompSize = 0UL;
   for (j = 0; j < 4; j++)
      pFH->cbulUncompSize |= ((DWORD)(rgbyteHeaderBuf[i++]) << (8 * j));

   // Stick compressed file size into header info struct.
   pFH->cbulCompSize = (DWORD)*pcblInSize;

   // File header read ok.
   return(TRUE);
}


/*
** BOOL IsCompressed(PFH pFHIn);
**
** See if a file is in compressed form by comparing its file signature with
** the expected compressed file signature.
**
** Arguments:  pFHIn - pointer to header info struct to check
**
** Returns:    BOOL - TRUE if file signature matches expected compressed file
**                    signature.  FALSE if not.
**
** Globals:    none
*/
BOOL IsCompressed(PFH pFHIn)
{
   INT i;
   // storage for FHIn's compressed file signature (used to make it an sz)
   CHAR rgchBuf[COMP_SIG_LEN + 1];

   // Copy file info struct's compressed file signature into rgchBuf[] to
   // make it an sz.
   for (i = 0; i < COMP_SIG_LEN; i++)
      rgchBuf[i] = pFHIn->rgbyteMagic[i];

   rgchBuf[i] = '\0';

   return((STRCMP(rgchBuf, COMP_SIG) == 0) ? TRUE : FALSE);
}


/*
** void MakeHeader(PFH pFHBlank, BYTE byteAlgorithm,
**                 BYTE byteExtensionChar);
**
** Arguments:  pFHBlank          - pointer to compressed file header struct
**                                 that is to be filled in
**             byteAlgorithm     - algorithm label
**             byteExtensionChar - uncompressed file name extension character
**
** Returns:    void
**
** Globals:    none
**
** Global cblInSize is used to fill in expanded file length field.
** Compressed file length field is set to 0 since it isn't written.
**
*/
VOID MakeHeader(PFH pFHBlank, BYTE byteAlgorithm,
                BYTE byteExtensionChar, PLZINFO pLZI)
{
   INT i;

   // !!! Assumes pLZI parm is valid.  No sanity check (should be done above in caller).

   // Fill in compressed file signature.
   for (i = 0; i < COMP_SIG_LEN; i++)
      pFHBlank->rgbyteMagic[i] = (BYTE)(*(COMP_SIG + i));

   // Fill in algorithm and extesion character.
   pFHBlank->byteAlgorithm = byteAlgorithm;
   pFHBlank->byteExtensionChar = byteExtensionChar;

   // Fill in file sizes.  (cbulCompSize not written to compressed file
   // header, so just set it to 0UL.)
   pFHBlank->cbulUncompSize = (DWORD)pLZI->cblInSize;
   pFHBlank->cbulCompSize = 0UL;
}


