/****************************************************************************
**
**  Name:  FILE.CPP
**
**  Description:
**      File processing routines for OMF86 Loader.
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_186/omf86/file.cpv  $
** 
**    Rev 1.0   26 Feb 1997 11:40:34   Judy
** Initial revision.
** 
**    Rev 1.0   14 Jun 1996 16:36:52   Judy
** Initial revision.
** 
**    Rev 1.11   10 Mar 1995 13:48:44   nghia
** Revised BlockState[] stack to use BLOCK_STATE_TYPE.
** 
**    Rev 1.10   11 Oct 1994 09:41:28   joyce
** 1. Modify SkipOver() : add BlockState stack pushes and pops.
**
**    Rev 1.9   26 Sep 1994 13:38:42   joyce
** 1. Fix a bug in SkipOver().
**
**    Rev 1.8   14 Sep 1994 10:48:42   joyce
** Change SkipOver to fix potential bugs.
**
**    Rev 1.7   23 Aug 1994 14:24:22   joyce
** 1. Remove CheckSum related functions.
** 2. Fix a bug in SkipOver().
**
**    Rev 1.6   03 Aug 1994 13:25:16   steve
** Joyce's changes for 386 build 11
**
**    Rev 1.5   14 Jul 1994 15:18:34   steve
** Joyce's omf86 changes for 386 build 8
**
**    Rev 1.4   17 Jun 1994 15:10:20   joyce
** 1. Add file size checking during Flush(); if the endLoc > loadFieSize, the
**    file is corrupted, and loading can not proceed.
** 2. Add return code checking for LdrWarning(), so if user cancelled the load,
**    it would clean up and return.
**
**    Rev 1.3   16 Jun 1994 13:32:52   joyce
** Use LdrWarning() to replace Warning() and remove err.h from the include list.
**
**    Rev 1.2   02 Jun 1994 18:38:24   joyce
** Numerous changes as the result of code review.
**
**    Rev 1.1   25 May 1994 16:12:38   joyce
** Modify the CheckChecksum() routine.
**
**    Rev 1.0   24 May 1994 14:48:12   joyce
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/omf86/file.cpv   1.0   26 Feb 1997 11:40:34   Judy  $
**
**  Copyright (C) 1994 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/
#include <io.h>
#include <fcntl.h>
#include <mem.h>

#ifndef _BASEWIND_
#include "basewind.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef __OMF86LDR__
#include "omf86ldr.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
STATIC U8 FAR *LdrBuf=NULL;
STATIC U8 *ReadPtr=NULL;
STATIC S16 CharsInBuf=0;
STATIC U32 CurLoc=0;
                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern U32 LoadFileSize;
extern BLOCK_STATES BlockState[BLOCK_STATE_SIZE];
extern U8 BlkStateCnt;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/

/****************************************************************************
**
**  CurrentLocation
**
*****************************************************************************/
U32 CurrentLocation(VOID) {
   return(CurLoc);
}

/****************************************************************************
**
**  OMFOpenFile
**
*****************************************************************************/
RETCODE OMFOpenFile(LPSTR fileName, HANDLE *hFile, OFSTRUCT *pof) {
RETCODE err;

   // check for the null filename
   if (*fileName == '\0')
      return(ER_CANNOT_OPEN);
   // fill in the file struct so caller has fully-qualified filename
   if ((err = _lopen(fileName, READ)) == -1L)
      return (ER_CANNOT_OPEN);
   /* get the file handle */
   *hFile = (HANDLE)err;
   /* Still need to fill in ofstruct, since this is the only way to obtain
       the fully-qualified pathname (stored in symbol table). */
   OpenFile(fileName, pof, OF_PARSE);

   if ((LdrBuf = (U8*)TMalloc((U32)LDR_BUFSIZE)) == NULL)
      return(ERR_BAD_MEMORY);
   ReadPtr = NULL;
   CharsInBuf = 0;
   CurLoc = 0L;
   return(GOOD);

}  /* OMFOpenFile */

/*****************************************************************************
**
**  OMFGetByte
**
*****************************************************************************/
RETCODE OMFGetByte(HANDLE hFile, U8 *pByte) {
   if (!hFile) return(ER_BADGET);
   if (CharsInBuf <= 0) {
      CharsInBuf = _lread(hFile, (S8*)LdrBuf, LDR_BUFSIZE);
      if (CharsInBuf <= 0)
         return(ER_BADGET);
      ReadPtr = (U8 *)LdrBuf;
   }
   *pByte = *ReadPtr++;
   CharsInBuf--;
   CurLoc++;
   return(GOOD);

}  /* OMFGetByte */

/*****************************************************************************
**
**  OMFGetBytes
**
*****************************************************************************/
RETCODE OMFGetBytes(HANDLE hFile, U8 *pByte, U16 number) {
U16 size;
U16 bytes=0;

   if (!number) return(GOOD);
   if (!hFile || (pByte == NULL))
      return(ER_BADGET);
   while (number > 0) {
      if (CharsInBuf <= 0) {
         if ((CharsInBuf = _lread(hFile, (S8*)LdrBuf, LDR_BUFSIZE)) <= 0)
            break;
         ReadPtr =(U8 *)LdrBuf;
      }
      size = min((U16)CharsInBuf, number);
      memcpy((LPSTR)pByte, (LPSTR)ReadPtr, size);
      ReadPtr += size;
      CharsInBuf -= size;
      pByte += size;
      number -= size;
      bytes += size;
   }
   if (bytes < number)
      return(ER_BADGET);
   CurLoc += bytes;
   return(GOOD);
}  /* OMFGetBytes */

/******************************************************************************
**
**  Flush
**
******************************************************************************/
RETCODE Flush(HANDLE hFile, U32 endLoc) {
U8 buffer[BUFSIZE];
RETCODE err;

   if (endLoc > LoadFileSize) return(ER_BAD_FILE);
   while (CurrentLocation() < endLoc) {
      if ((err=OMFGetBytes(hFile, buffer, (U16)min((U32)BUFSIZE,
           endLoc - CurrentLocation()))) != GOOD)
         return(err);
   }
   return(GOOD);
}

/******************************************************************************
**
**  SkipOver
**
******************************************************************************/
RETCODE SkipOver(HANDLE hFile, U32 endLoc, U8 signature) {
U32 length;
RETCODE err;
OMF86_REC_HEADER recHdr;
S32 fileOffset;
U16 localScope = 0;

   if (!hFile) return(ER_BAD_SEEK);
   if ((err=Flush(hFile, endLoc+1L)) != GOOD)
      return(err);
   while ((err=OMFGetBytes(hFile, (U8 *)&recHdr, sizeof(recHdr))) == GOOD) {
      if (((signature == THEADR) &&
           ((recHdr.type == signature) || (recHdr.type == MODEND)))) {
         fileOffset = CurrentLocation() - sizeof(recHdr);
         if (SeekFile(hFile, fileOffset, SEEK_SET) == -1L)
            return(ER_BAD_SEEK);
         return(GOOD);
      }
      length = CurrentLocation() + recHdr.len;
      if ((err=Flush(hFile, length)) != GOOD)
         return(err);
      if (recHdr.type == BLKDEF) {
         BlockState[BlkStateCnt++] = BLOCK_START;
         localScope++;
      }
      if (recHdr.type == BLKEND) {
         if (BlkStateCnt < 1)
            return(ER_BAD_FILE);
         BlockState[--BlkStateCnt] = BLOCK_END;
         if (!localScope && (signature == BLKDEF))
            return(GOOD);
         localScope--;
      }
   }
   return(err);
}  /* SkipOver */

/*****************************************************************************
**
**  SeekFile
**
*****************************************************************************/
S32 SeekFile(HANDLE hfile, S32 pos, S16 seekTo) {
S32 retPos;

   if (!hfile) return(-1L);
   retPos = _llseek(hfile, pos, seekTo);
   CharsInBuf = 0;
   if (retPos == -1L)
      retPos = _llseek(hfile, CurLoc, SEEK_SET);
   if (retPos == -1L)
      return(retPos);
   CurLoc = retPos;
   return(CurLoc);
}  /* SeekFile */

/*****************************************************************************
**
**  OMFCloseFile
**
*****************************************************************************/
RETCODE OMFCloseFile(HANDLE hfile) {
RETCODE err;

   /* De-allocate file buffer */
   if ((LdrBuf != NULL) && (TFree((LPSTR)LdrBuf) != GOOD) &&
       (err = LdrWarning(ER_BAD_FREE, NULL, NULL, NULL)) != GOOD)
      return(err);
   LdrBuf = NULL;
   _lclose(hfile);
   return(GOOD);
}  /* OMFCloseFile */

/******************************** E O F ***********************************/
