/****************************************************************************
**
**  Name:  DATA.CPP
**
**  Description:
**      Routines for processing Code/Data records
**
**  Status:  CODED
**
**  $Log:   S:/tbird/mt2_186/omf86/data.cpv  $
** 
**    Rev 1.3   08 Jan 1998 08:39:52   hera
** 
**    Rev 1.2   14 Nov 1997 14:51:52   Judy
** Change PC default 0000:0000 into FFFF:0000.
** 
**    Rev 1.1   18 Apr 1997 09:29:38   Judy
** 
**    Rev 1.0   26 Feb 1997 11:40:34   Judy
** Initial revision.
** 
**    Rev 1.0   14 Jun 1996 16:36:50   Judy
** Initial revision.
** 
**    Rev 1.5   03 Aug 1994 13:25:06   steve
** Joyce's changes for 386 build 11
**
**    Rev 1.4   14 Jul 1994 15:18:26   steve
** Joyce's omf86 changes for 386 build 8
**
**    Rev 1.2   16 Jun 1994 13:23:58   joyce
** Modify LoadDataImage() to improve download performance: queue the address
** only if it doesn't immediiately follow the previous data record; when
** queueing the address, only the bytes of the address which are different need
** to be sent.
**
**    Rev 1.1   02 Jun 1994 18:32:24   joyce
** 1. Fix a bug about losing data chunk in code loading session. Add a var named
** LastLoadAddr to be used at the function LdrQueueFlush() in OMF86.CPP
**
**    Rev 1.0   24 May 1994 14:48:02   joyce
** Initial revision.
**
**  $Header:   S:/tbird/mt2_186/omf86/data.cpv   1.3   08 Jan 1998 08:39:52   hera  $
**
**  Copyright (C) 1994 Microtek International.  All rights reserved.
**
*****************************************************************************/

                       /****************************
                        *                          *
                        *       INCLUDE FILES      *
                        *                          *
                        ****************************/

#ifndef __MEM_H
#include <mem.h>
#endif

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

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

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

#ifndef __OMF86__
#include "omf86.h"
#endif

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

#ifndef _LQUEUE_
#include "lqueue.h"
#endif

//Hera 4/3/97
#ifndef __TYPE__
#include "type.h"
#endif

                       /****************************
                        *                          *
                        *     LOCAL DEFINITIONS    *
                        *                          *
                        ****************************/
LADDRESS StartPC, StackTop;
U32 LastLoadAddr;
STATIC U8 FAR *IterDataPtr = NULL;
                       /****************************
                        *                          *
                        *    EXTERNAL VARIABLES    *
                        *                          *
                        ****************************/
extern U32 BytesLoaded;
extern BOOLEAN HasStartPC;
extern Blk_Info *BlkSymbol, *BlkLinkTail;

                       /****************************
                        *                          *
                        *     LOCAL PROTOTYPES     *
                        *                          *
                        ****************************/
PRIVATE RETCODE GetIteratedDataBlock(HANDLE , U32 , LADDRESS *);
PRIVATE ITER_DATA *LoadIteratedBlock(HANDLE, LADDRESS *, ITER_DATA *);
PRIVATE RETCODE LoadDataImage(HANDLE, U32, LOAD_FUNC, U32, U32);
RETCODE EXPORT OMF86LoaderGetBytes(VOID *, U8 *, U16);
RETCODE EXPORT OMF86LoaderGetFromIterDataBlock(VOID *, U8 *, U16);

                       /****************************
                        *                          *
                        *      EXECUTABLE CODE     *
                        *                          *
                        ****************************/
/******************************************************************************
**
**  ProcessREGINT
**
******************************************************************************/
RETCODE ProcessREGINT(OMF86_FUNC_PARA *funcPara) {
REGTYP regType;
RETCODE err=GOOD;
LADDRESS regContents;

   if (IsLoadCode(funcPara->flags)) {
      while (CurrentLocation() < funcPara->endLoc) {
         if ((err=OMFGetBytes(funcPara->hFile, (U8 *)&regType,
             sizeof(regType))) != GOOD)
            return(err);
         if (!regType.lFlag) { // Only process physical address type
            if (regType.regId > 1) { // DS and ES, just read and throw it out
               if ((err=GetBase(funcPara->hFile, &regContents)) != GOOD)
                  return(err);
            }
            else {
               if (!regType.regId) { // CS:IP
                  err=GetBaseOffset( funcPara->hFile, &StartPC);
                  HasStartPC = TRUE;
               }
               else        // SS:SP
                  err=GetBaseOffset( funcPara->hFile, &StackTop);
            }
         }
         else
            err = ER_OMF86_LOGICAL_ADDRESS_NOT_HANDLED;
      }
   }
   return(err);
}

/******************************************************************************
**
**  ProcessREDATA
**
******************************************************************************/
RETCODE ProcessREDATA(OMF86_FUNC_PARA *funcPara) {
LADDRESS addr;
RETCODE err;
U32 logicalAddr;

   if (IsLoadCode(funcPara->flags)) {
      if ((err = GetBaseOffset(funcPara->hFile, &addr)) != GOOD) return(err);
      logicalAddr = (U32)addr.offset + ((U32)addr.segment << 4) ;
      if ((err = LoadDataImage(funcPara->hFile, logicalAddr,
           (LOAD_FUNC)OMF86LoaderGetBytes, 1uL,
           (U32)(funcPara->endLoc-CurrentLocation()))) != GOOD) return(err);
   }
   return(GOOD);
}

/******************************************************************************
**
**  ProcessPEDATA
**
******************************************************************************/
RETCODE ProcessPEDATA(OMF86_FUNC_PARA *funcPara) {
LADDRESS addr;
RETCODE err;
U32 logicalAddr;

   if (IsLoadCode(funcPara->flags)) {
      if ((err = GetPhysicalBase(funcPara->hFile, &addr)) != GOOD) return(err);
      logicalAddr = (U32)addr.offset + ((U32)addr.segment << 4) ;
      if ((err = LoadDataImage(funcPara->hFile, logicalAddr,
           (LOAD_FUNC)OMF86LoaderGetBytes, 1uL,
           funcPara->endLoc-CurrentLocation())) != GOOD) return(err);
   }
   return(GOOD);
}

/******************************************************************************
**
**  ProcessRIDATA
**
******************************************************************************/
RETCODE ProcessRIDATA(OMF86_FUNC_PARA *funcPara) {
LADDRESS addr;
RETCODE err;

   if (IsLoadCode(funcPara->flags)) {
      if ((err = GetBaseOffset(funcPara->hFile, &addr)) != GOOD) return(err);
      if ((err = GetIteratedDataBlock(funcPara->hFile, funcPara->endLoc,
           &addr)) != GOOD)
         return(err);
   }
   return(GOOD);
}

/******************************************************************************
**
**  ProcessPIDATA
**
******************************************************************************/
RETCODE ProcessPIDATA(OMF86_FUNC_PARA *funcPara) {
LADDRESS addr;
RETCODE err;

   if (IsLoadCode(funcPara->flags)) {
      if ((err = GetPhysicalBase(funcPara->hFile, &addr)) != GOOD)
         return(err);
      if ((err = GetIteratedDataBlock(funcPara->hFile, funcPara->endLoc,
           &addr)) != GOOD)
         return(err);
   }
   return(GOOD);
}

/******************************************************************************
**
**  ProcessMODEND
**
******************************************************************************/
RETCODE ProcessMODEND(OMF86_FUNC_PARA *funcPara) {
RETCODE err;
MOD_TYP modType;
Blk_Info *blkTemp; //Hera 4/3/97
BOOLEAN isLoaded; //Hera 4/3/97

   /* Winky 11/13/97 */
   StartPC.segment = 65535L;
   StartPC.offset  = 0L;
   /* EOF Winky 11/13/97 */

   if (IsLoadCode(funcPara->flags)) {
      if ((err=OMFGetBytes(funcPara->hFile, (U8 *)&modType,
	  (U16)sizeof(modType))) != GOOD) return(err);
      if (!modType.lFlag) {
         if (HAS_STARTADDR(modType.mAttr)) { /* start address given */
            if ((err=OMFGetBytes(funcPara->hFile, (U8 *)&StartPC,
                (U16)sizeof(StartPC))) != GOOD)
               return(err);
            HasStartPC = TRUE;

            /* Winky 11/13/97 */
            if (StartPC.segment == 0)  StartPC.segment = 65535L;
            /* EOF Winky 11/13/97 */
         }
      }
      else
         return(ER_OMF86_LOGICAL_ADDRESS_NOT_HANDLED);
   }
   if (IsLoadSymbol(funcPara->flags)) {
      if ((err=LoadModuleEnd(funcPara)) != GOOD)
	 return(err);
      //Hera 4/3/97
      blkTemp = BlkSymbol;
      while (blkTemp != NULL) {
	  IsPublicSymbol(blkTemp->blkName, blkTemp->base, &isLoaded);
	  BlkSymbol = BlkSymbol->next;
	  TFree((LPSTR)blkTemp);
	  blkTemp = BlkSymbol;
      }
      //Hera
      if (funcPara->oFlag == MCREATE && (err = LoadPublics(funcPara)) != GOOD)
         return(err);
   }
   return(GOOD);
}

/******************************************************************************
**
**  GetIteratedDataBlock
**
******************************************************************************/
PRIVATE RETCODE GetIteratedDataBlock(HANDLE hFile, U32 endLoc, LADDRESS *addr)
{
VOID FAR *iterDataBlock = NULL;
U32 blkSize;
RETCODE err;

   blkSize = endLoc - CurrentLocation();
   if ((iterDataBlock = (VOID *)TMalloc(blkSize)) == NULL)
      return(ERR_BAD_MEMORY);
   if ((err=OMFGetBytes(hFile, (U8 *)iterDataBlock, (U16)blkSize)) == GOOD)
      LoadIteratedBlock(hFile, addr, (ITER_DATA FAR *)iterDataBlock);
   TFree((LPSTR)iterDataBlock);
   return(err);
}

/******************************************************************************
**
**  LoadIteratedBlock
**
******************************************************************************/
PRIVATE ITER_DATA FAR *LoadIteratedBlock( HANDLE hFile, LADDRESS *addr,
                                         ITER_DATA FAR *ptrIter) {
ITER_DATA FAR *tmpPtr = NULL;
U32 logicalAddr;

   // 08/08/95 - Nghia
   // Fixed GPF bug - Crashed when loading MSC60 & LL
   // <tmpPtr> was not initialize to be used in recursive calls.
   // Also added some defensive coding to avoid bogus pointers.
   if (ptrIter && !ptrIter->blkCnt) {
      /* IterDataPtr is used in OMF86LoaderGetFromIterDataBlock() */
      IterDataPtr = (U8 FAR *)ptrIter->content;
      logicalAddr = (U32)addr->offset + ((U32)addr->segment << 4) ;
      LoadDataImage(hFile, logicalAddr,
                    (LOAD_FUNC)OMF86LoaderGetFromIterDataBlock,
                    ptrIter->rptCnt, ptrIter->byteCnt);
      //Hera 1/7/97
      //tmpPtr = (ITER_DATA FAR *)ptrIter->content + ptrIter->byteCnt;
      tmpPtr = (ITER_DATA FAR *)(ptrIter->content + ptrIter->byteCnt);
      //Hera
      addr->offset += ptrIter->byteCnt * ptrIter->rptCnt;
   }
   else {
      // 08/08/95 - Nghia
      // There should be validation of the PIDATA record length and the
      // <blkCnt> of DATA BLOCK.
      U16 repeat;
      for (repeat = 0; ptrIter && repeat < ptrIter->rptCnt; repeat++) {
         U16 block;
         tmpPtr = (ITER_DATA FAR *)&ptrIter->byteCnt;
         // 08/08/95 - Nghia
         // Recursive call to process the PIDATA record
         for (block = 0; tmpPtr && block < ptrIter->blkCnt; block++)
            tmpPtr = LoadIteratedBlock(hFile, addr, tmpPtr );
      }
   }
   return(tmpPtr);
} /* LoadIteratedBlock */

/*****************************************************************************
**
**  OMF86LoaderGetBytes
**
*****************************************************************************/
RETCODE EXPORT OMF86LoaderGetBytes(VOID FAR *info, U8 FAR *dest, U16 count) {
   return(OMFGetBytes(*((HANDLE*)info), dest, count));
} /* GetBytes */

/*****************************************************************************
**
**  OMF86LoaderGetFromIterDataBlock
**
*****************************************************************************/
#pragma warn -par
RETCODE EXPORT OMF86LoaderGetFromIterDataBlock(VOID FAR *info, U8 FAR *dest,
                                               U16 count) {
   _fmemcpy(dest, IterDataPtr, count);
   IterDataPtr += count;
   return(GOOD);
} /* OMF86LoaderGetFromIterDataBlock */

/******************************************************************************
**
**  LoadDataImage
**
******************************************************************************/
PRIVATE RETCODE LoadDataImage(HANDLE hFile, U32 addr, LOAD_FUNC loadFunc,
                             U32 rptCnt, U32 byteCnt) {
RETCODE err;
BOOLEAN aborted;
U32 addrBitsChanged;

   /* Send new address record, changing as few bytes as possible */
   if ((addrBitsChanged = addr ^ LastLoadAddr) != 0) {
      if ((err = LdrQueueSetAddressRecord(addr,
           BYTES_TO_TRANSMIT(addrBitsChanged))) != GOOD) return(err);
   }
   if ((err = LdrQueueCheckLoadAbort()) != GOOD) return(err);
   if ((err = LdrQueueGetLoadAbort(&aborted)) != GOOD) return(err);
   if ((err = LdrQueueDataRecord(&hFile, loadFunc, addr,
              rptCnt, byteCnt)) != GOOD)  return(err);
   BytesLoaded += byteCnt * rptCnt;
   LastLoadAddr = addr + rptCnt*byteCnt;
   return(GOOD);
} /* LoadDataImage */

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