
/*--------------------------------------------------------------------*/
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*--------------------------------------------------------------------*/

#define INCL_32
#include "os2def.h"

#ifndef WORD
  typedef USHORT  WORD;
  typedef ULONG   DWORD;
#endif

#include "stdio.h"

#define EXE386 1
#include "newexe.h"
#include "exe386.h"

#include "abscons.h"
#include "abstype.h"

#include "abspro.h"
#include "absextn.h"

/*---------------------------------------*/
/*                                       */
/*                                       */
/*                                       */
/*                                       */
/*                                       */
/*                                       */
/*---------------------------------------*/

ULONG Pass1( PMODINFO pMI )
{
  ULONG         i;
  ULONG         rc = 0;

  PE32_EXE      pLXH;
  PO32_OBJ      pO32Obj;
  POBJINFO      pOI, pOIPrev;



  pLXH = pMI->pLXHData;

  pMI->ModCurAddr = pMI->ModBaseAddr;

  /*-------------------------------------------*/
  /* Create a Page Table reflecting the        */
  /* actual file offsets and addresses of the  */
  /* pages in the output file                  */
  /*-------------------------------------------*/

  i = pLXH->e32_mpages * sizeof(OBJPGINFO);


  if ( !(pMI->pObjPGInfo=(POBJPGINFO) malloc( i )) )
  {
    rc = errmsg( ERR_BAD_MALLOC, SRCFILE, LINENO, pMI->pModName );
    goto  Pass1_Exit;
  }

  /*--------------------------------------------------*/
  /* For each Object Table Entry                      */
  /*--------------------------------------------------*/

  pOIPrev = NULL;

  pO32Obj = (PO32_OBJ)(((PBYTE) pLXH) + pLXH->e32_objtab);

  for ( i=0; i < pLXH->e32_objcnt; i++, pO32Obj++ )
  {
    /*------------------------------*/
    /* Create Object Info Structure */
    /*------------------------------*/

    if ( !(pOI=(POBJINFO) malloc(sizeof(OBJINFO))) )
    {
      rc = errmsg( ERR_BAD_MALLOC, SRCFILE, LINENO, pMI->pModName );
      goto  Pass1_Exit;
    }
    memset(pOI, 0, sizeof(OBJINFO));

    if ( !pOIPrev )
    {
      pMI->pObjInfo = pOI;
    }
    else
    {
      pOIPrev->pObjNext = pOI;
    }
    pOIPrev = pOI;

    pOI->FileOffset  = OutFilePos;
    pOI->ObjVirtAddr = pMI->ModCurAddr;

    /*-------------------------------*/
    /* Expand Object to Output File  */
    /*-------------------------------*/
    if ( (rc = ExpandObject( pMI, pOI, pO32Obj )) )
    {
      goto Pass1_Exit;
    }
  }
Pass1_Exit: ;
  return( rc );

}

/*---------------------------------------*/
/*                                       */
/*                                       */
/*                                       */
/*                                       */
/*                                       */
/*                                       */
/*---------------------------------------*/

ULONG ExpandObject( PMODINFO pMI, POBJINFO pOI, PO32_OBJ pO32Obj )
{
  ULONG         i, j, n;
  ULONG         rc = 0;
  ULONG         cMapEntries;
  ULONG         VirtSize;
  LONG          DLen;
  ULONG         FilePos;
  ULONG         DataLen;
  ULONG         ObjBytes;
  ULONG         O32Flags;
  ULONG         PGMapIndex;
  PO32_MAP      pO32Map;
  PE32_EXE      pLXH;
  PBYTE         pScrBuf2;
  PLX_ITER      pITR;

  PBYTE         s, d;

  /*-----------------------------------------*/
  /* Get Virtual Size and number of Page Map */
  /* entries for this object.                */
  /*-----------------------------------------*/

  VirtSize    = (pO32Obj->o32_size + PageSize-1) & ~(PageSize-1);
  cMapEntries = pO32Obj->o32_mapsize;
  ObjBytes    = 0;

  pLXH        = pMI->pLXHData;

  if ( !(pScrBuf2=(PBYTE)malloc(PageSize)) )
  {
    rc = errmsg(ERR_BAD_MALLOC, SRCFILE, LINENO, pMI->pModName );
    goto Expand_Exit;
  }


  /*--------------------------------------------*/
  /* Get address/index of first object page map */
  /* entry for this object.                     */
  /*--------------------------------------------*/
  PGMapIndex = pO32Obj->o32_pagemap - 1;

  pO32Map = &((PO32_MAP)(((PBYTE)pLXH) + pLXH->e32_objmap))[PGMapIndex];

  /*--------------------------------------*/
  /* Process page map entries for object  */
  /*--------------------------------------*/

  for (i=0; i < cMapEntries; i++, pO32Map++ )
  {
     /*----------------------------------------------*/
     /* Record the file position and virtual address */
     /* of each page in the ObjPGInfo array          */
     /*----------------------------------------------*/

     (pMI->pObjPGInfo)[PGMapIndex+i].PGFilePos  = OutFilePos;
     (pMI->pObjPGInfo)[PGMapIndex+i].PGVirtAddr = pMI->ModCurAddr;

    /*------------------------------------------------*/
    /* If the .EXE contains data for this page, then  */
    /* read the page data into pScrBuf.               */
    /*------------------------------------------------*/

    O32Flags = pO32Map->o32_pageflags;

    memset( pScrBuf, 0, PageSize );

    if ( O32Flags == VALID || O32Flags == ITERDATA || O32Flags == ITERDATA2 )
    {
      FilePos = pLXH->e32_datapage + (pO32Map->o32_pagedataoffset << pLXH->e32_pageshift);
      DataLen = pO32Map->o32_pagesize;


      if ( ReadFileAt( pMI->hModFile, FilePos, pScrBuf, DataLen ) )
      {
        rc = errmsg( ERR_BAD_INFILE, SRCFILE, LINENO, pMI->pModName );
        goto Expand_Exit;
      }
    }

    switch ( O32Flags )
    {

      /*------------------------------------------------*/
      /* VALID - Just write the page to the output file */
      /*------------------------------------------------*/
      case VALID:
      case ZEROED:
        n = 1;
        goto WritePages;

      case RANGE:
        n = pO32Map->o32_pagesize;

WritePages: ;
        while (n--)
        {
          if ( WriteFileAt( hOutFile, OutFilePos, pScrBuf, PageSize ) )
          {
            rc = errmsg( ERR_BAD_OUTFILE, SRCFILE, LINENO, pMI->pModName );
            goto Expand_Exit;
          }

          OutFilePos      += PageSize;
          pMI->ModCurAddr += PageSize;
          ObjBytes        += PageSize;
        }
        break;

      /*------------------------------------------------------*/
      /* ITERDATA - Expand the interation records to pScrBuf2 */
      /* until the data length in the page map entry is       */
      /* exhausted                                            */
      /*------------------------------------------------------*/
      case ITERDATA:
        s = pScrBuf;
        d = pScrBuf2;

        DLen = DataLen;

        while ( DLen >= 0 )
        {
          pITR = (PLX_ITER) s;

          for ( j=0; j < pITR->LX_nIter; j++ )
          {
            memcpy( d, &pITR->LX_Iterdata, pITR->LX_nBytes );
            d    += pITR->LX_nBytes;
            DLen -= pITR->LX_nBytes;
          }

          s += sizeof(struct LX_Iter) + pITR->LX_nBytes - 1;
        }

        if ( WriteFileAt( hOutFile, OutFilePos, pScrBuf2, PageSize ) )
        {
          rc = errmsg( ERR_BAD_OUTFILE, SRCFILE, LINENO, pMI->pModName );
          goto Expand_Exit;
        }

        OutFilePos      += PageSize;
        pMI->ModCurAddr += PageSize;
        ObjBytes        += PageSize;
        break;

      /*-----------------------------------------------------------*/
      /* Call the 'magic' algorithm in "complib". Actually just    */
      /* the ADDSTOR compression algorithm.                        */
      /*-----------------------------------------------------------*/
      case ITERDATA2:
       if( !EP2_32_Decompress(DataLen, PageSize, pScrBuf, pScrBuf2) )
       {
         rc = errmsg( ERR_NO_EXEPACK2, SRCFILE, LINENO, pMI->pModName );
         goto Expand_Exit;
       }

       if ( WriteFileAt( hOutFile, OutFilePos, pScrBuf, PageSize ) )
       {
         rc = errmsg( ERR_BAD_OUTFILE, SRCFILE, LINENO, pMI->pModName );
         goto Expand_Exit;
       }

       OutFilePos      += PageSize;
       pMI->ModCurAddr += PageSize;
       ObjBytes        += PageSize;
       break;
    }
  }

  /*----------------------------------------------*/
  /* Zero-fill remainder of object not explicitly */
  /* initialized by Page Map entries.             */
  /*----------------------------------------------*/

  memset( pScrBuf, 0, PageSize );

  DLen = VirtSize - ObjBytes;

  while ( DLen > 0 )
  {
    n = (DLen > PageSize) ? PageSize : DLen;

    if ( n )
    {
      if ( WriteFileAt( hOutFile, OutFilePos, pScrBuf, n ) )
      {
        rc = errmsg( ERR_BAD_OUTFILE, SRCFILE, LINENO, pMI->pModName );
        goto Expand_Exit;
      }
      OutFilePos      += n;
      pMI->ModCurAddr += n;
    }
    DLen -= n;
  }

Expand_Exit: ;

  if ( pScrBuf2 )
  {
    free( pScrBuf2 );
  }
  return ( rc );

}

