/*
**  Copyright (c) 1991 Microsoft Corporation
*/
//===========================================================================
// FILE                         HRE.C
//
// MODULE                       Host Resource Executor
//
// PURPOSE                      Convert A-form to B-form for jumbo driver
//
// DESCRIBED IN                 Resource Executor design spec.
//
// MNEMONICS                    n/a
// 
// HISTORY  1/17/92 mslin       created
//          3/30/92 mslin       Pre-compiled brush generated for each job.
//                              ideal case would be initialize PcrBrush in
//                              HRE.DLL loading, and free up when HRE 
//                              terminate. but we had problem in Dumbo, ???
//                              Expanded Brush Buffer allocated for each job.
//                              lpgBrush will be set to lpREState->lpBrushBuf
//                              in DoRpl().
//          4/15/92 mslin       added uiHREExecuteRPL() for dumbo.
//          9/27/93 mslin       added a new bit of wFlags in hHREOpen() for
//                              300/600 dpi:
//                                  bit2: 0 -- 300 dpi
//                                  bit2: 1 -- 600 dpi
//                              also remove DUMBO compiler switch. 
//          2/09/94 rajeevd     Undid all of the above changes.
//===========================================================================

// include file
#include <windows.h>
#include <windowsx.h>
#include <resexec.h>

#include "constant.h"
#include "jtypes.h"     // type definition used in cartridge
#include "jres.h"       // cartridge resource data type definition
#include "hretype.h"    // define data structure used by hre.c and rpgen.c

#include "hreext.h"
#include "multbyte.h"   // define macros to take care of byte ordering

#define HRE_SUCCESS             0x0     // successful return from HRE
#define HRE_EXECUTED_RPL        0x01    // Executed the final RP in an RPL
#define HRE_EXECUTED_ONE        0x02    // Executed only one RP from an RPL
                                        // (not the last one)
#define HRE_ERROR               0x03    // General HRE failure

// PRIVATE functions
static   UINT        PutRPL(LPHRESTATE lpHREState, LPFRAME lpFrameArray,
                     UINT uiCount);
static   UINT        FreeRPL(LPRPLLIST lpRPL);

#ifdef DEBUG
DWORD    dwrgTime[MAXBAND];
SHORT    sCurrentLine;
ULONG    ulgPageId = 0;
ULONG    ulgTimes[1000] = {0};
#endif

#include "windows.h"

//==============================================================================

#ifndef WIN32

BOOL WINAPI LibMain
    (HANDLE hInst, WORD wSeg, WORD wHeap, LPSTR lpszCmd)
{ return 1; }

int WINAPI WEP (int nParam);
#pragma alloc_text(INIT_TEXT,WEP)
int WINAPI WEP (int nParam)
{ return 1; }

#endif

//==============================================================================
HANDLE                 // context handle (NULL on failure)
WINAPI hHREOpen
(
    LPVOID lpBrushPat,   // array of 32x32 brush patterns
    UINT   cbLine,       // maximum page width in bytes
    UINT   cResDir       // entries in resource directory
)
{
   HANDLE      hHREState;
   LPHRESTATE  lpHREState;
   LPRESTATE   lpREState;
   LPRESDIR    lpDlResDir;

   // create a handle for the new session 
   if (!(hHREState = GlobalAlloc(GMEM_MOVEABLE, sizeof(HRESTATE))))
      return (NULL);
   lpHREState = (LPHRESTATE) GlobalLock (hHREState);

   // allocate Download ResDir Table
   if (!(lpDlResDir = (LPRESDIR) GlobalAllocPtr (GMEM_ZEROINIT, sizeof(RESDIR) * cResDir)))
   {
      // unlock and free HRESTATE
      GlobalUnlock(hHREState);
      GlobalFree(hHREState);
      return(NULL);
   }
   
   // allocate RESTATE data structure and Initialize it
   // this is graphic state of rendering 
   if (!(lpREState = (LPRESTATE) GlobalAllocPtr (GMEM_ZEROINIT, sizeof(RESTATE))))
   {
      GlobalUnlock(hHREState);
      GlobalFree(hHREState);
      GlobalFreePtr (lpDlResDir);
      return (NULL);
   }

#ifdef WIN32

  lpREState->lpBrushBuf = NULL;

#else

   if (!(lpREState->lpBrushBuf = (LPSTR) GlobalAllocPtr(GMEM_MOVEABLE, (cbLine + 4) * 16)))
   {
      GlobalUnlock(hHREState);
      GlobalFree(hHREState);
      GlobalFreePtr (lpDlResDir);
      GlobalFreePtr (lpREState);
      return (NULL);
   }

#endif
      
   // Initialize RESTATE
   lpREState->lpBrushPat = lpBrushPat;
                                            
   // Initialize HRESTATE
   lpHREState->hHREState = hHREState;
   lpHREState->scDlResDir = (USHORT)cResDir;
   lpHREState->lpDlResDir = lpDlResDir;
   lpHREState->lpRPLHead= NULL;
   lpHREState->lpRPLTail= NULL;
   lpHREState->lpREState = lpREState;

   GlobalUnlock(hHREState);
   return(hHREState);
}

//---------------------------------------------------------------------------
UINT                            // will be zero (0) if resource is processed
                                // succesfully, otherwise it will be an error
                                // code as defined above.
WINAPI uiHREWrite
(
    HANDLE      hHREState,      // handle returned previously by hREOpen
    LPFRAME     lpFrameArray,   // FAR pointer to an array of FRAME structs
    UINT        uiCount         // Number of FRAME structs pointed to by 
                                // lpFrameArray
)

// PURPOSE                      To add a resource block (RPLK) to the
//                              HRE state hash table for the context
//                              identified by hHREState.
//
// ASSUMPTIONS & ASSERTIONS     The memory for the RBLK has allready been
//                              Allocated and locked.  HRE will not copy the
//                              data, just the pointers.
//                              The lpFrameArray does not point to an SPL.
//                              All SPL's will be handled externally to HRE.
//
// INTERNAL STRUCTURES          
//
// UNRESOLVED ISSUES            
//
//---------------------------------------------------------------------------       
{
   LPHRESTATE     lpHREState;
   LPJG_RES_HDR   lpResHdr;
   LPRESDIR       lpResDir;
   ULONG          ulUID;
   USHORT         usClass;
   HANDLE         hFrame;
   LPFRAME        lpFrameArrayDup, lpFrame;
   UINT           uiLoopCount;

   lpHREState = (LPHRESTATE) GlobalLock (hHREState);

   // get resource class                                            
   lpResHdr = (LPJG_RES_HDR )lpFrameArray->lpData;
   usClass = GETUSHORT(&lpResHdr->usClass);
   switch(usClass)
   {
      case JG_RS_RPL: /*0x4*/
         // store into RPL list
         if( PutRPL(lpHREState, lpFrameArray, uiCount) != HRE_SUCCESS )
         {
            GlobalUnlock(hHREState);
            return(HRE_ERROR);   // out of memory
         }
         break;

      case JG_RS_GLYPH: /*0x1*/
      case JG_RS_BRUSH: /*0x2*/
      case JG_RS_BITMAP: /*0x3*/
         // check to see if uid >= size of hash table then reallocate
         ulUID = GETULONG(&lpResHdr->ulUid);
         lpResDir = lpHREState->lpDlResDir;
         if (ulUID >= lpHREState->scDlResDir)
         {
               return(HRE_ERROR);
         }

         // Free frame array of previous resource block
         lpFrameArrayDup = lpResDir[ulUID].lpFrameArray;
         if(lpFrameArrayDup)
           GlobalFreePtr (lpFrameArrayDup);
          
         // copy frame array
         if (!(hFrame = GlobalAlloc(GMEM_MOVEABLE, uiCount * sizeof(FRAME))))
            return (HRE_ERROR);
         if (!(lpFrameArrayDup = (LPFRAME)GlobalLock(hFrame)))
         {
            GlobalFree(hFrame);
            return (HRE_ERROR);
         }
         lpFrame = lpFrameArrayDup;
         for(uiLoopCount=0; uiLoopCount<uiCount; uiLoopCount++)
         {
            *lpFrame++ = *lpFrameArray++;
         }

         // put into hash table
         lpResDir[ulUID].lpFrameArray = lpFrameArrayDup;
         lpResDir[ulUID].uiCount = uiCount;
         break;
         
      default:
         // error return 
         break;

   }

   GlobalUnlock(hHREState);
   return(HRE_SUCCESS);

}


//---------------------------------------------------------------------------
UINT   WINAPI uiHREExecute
(
    HANDLE   hHREState,  // resource executor context
  LPBITMAP lpbmBand,   // output band buffer
  LPVOID   lpBrushPat  // array of 32x32 brush patterns
)
{
   LPHRESTATE  lpHREState;
   LPRESTATE   lpRE;
   LPRPLLIST   lpRPL, lpRPLSave;

   lpHREState = (LPHRESTATE) GlobalLock (hHREState);
   
   // Record parameters in RESTATE.
   lpRE = lpHREState->lpREState;
   lpRE->lpBandBuffer = lpbmBand;
   lpRE->lpBrushPat   = lpBrushPat;

   lpRPL = lpHREState->lpRPLHead;
   do
   {
     DoRPL(lpHREState, lpRPL);
      lpRPLSave = lpRPL;
      lpRPL=lpRPL->lpNextRPL;
      FreeRPL(lpRPLSave);
   }
   while(lpRPL);
   // if last RP executed then update lpRPLHead
   lpHREState->lpRPLHead = lpRPL;
   
   GlobalUnlock(hHREState);
   return(HRE_EXECUTED_RPL);

}

//---------------------------------------------------------------------------
UINT                            // will be zero (0) if HRE context is closed
                                // succesfully, otherwise it will be an error
                                // code as defined above.
WINAPI uiHREClose
(
    HANDLE      hHREState       // handle returned previously by hREOpen
)

// PURPOSE                      To close a previously opened context in the
//                              HRE.  All memory and state information 
//                              associated with the context will be freed.
//
// ASSUMPTIONS & ASSERTIONS     None.
//
// INTERNAL STRUCTURES          None.
//
// UNRESOLVED ISSUES            programmer development notes
//
// --------------------------------------------------------------------------
{
   LPHRESTATE  lpHREState;
   LPRESTATE   lpRE;
   LPRESDIR    lpDlResDir;
   SCOUNT      scDlResDir;
   SCOUNT      sc;
   LPFRAME     lpFrameArray;
    
   if (!(lpHREState = (LPHRESTATE) GlobalLock (hHREState)))
     return HRE_ERROR;

   lpDlResDir = lpHREState->lpDlResDir;
   if(lpDlResDir != NULL)                 // mslin, 4/15/92 for dumbo
   {
      scDlResDir = lpHREState->scDlResDir;
      // free frame array of DlResDir
      for(sc = 0; sc < scDlResDir; sc++)
      {
         if( (lpFrameArray = lpDlResDir[sc].lpFrameArray) != NULL)
           GlobalFreePtr (lpFrameArray);
      }

      // unlock and free DlResDir
      GlobalFreePtr(lpDlResDir);
   }

     lpRE = lpHREState->lpREState;

#ifndef WIN32
   GlobalFreePtr (lpRE->lpBrushBuf);
#endif   
   GlobalFreePtr (lpRE);
   
   GlobalUnlock(hHREState);
   GlobalFree(hHREState);
   
   return(HRE_SUCCESS);
}
 
// ------------------------------------------------------------------------
static
UINT                         // HRE_SUCCESS if allocate memory OK
                             // HRE_ERROR if allocate memory failure
PutRPL
(
   LPHRESTATE lpHREState,
   LPFRAME lpFrameArray,
   UINT uiCount
)
// PURPOSE
//                            Allocate a RPL entry and then put RPL into 
//                            tail of RPL list.
//
//           
// ------------------------------------------------------------------------
{
   HANDLE      hRPL;
   LPRPLLIST   lpRPL;
   HANDLE      hFrame;
   LPFRAME     lpFrameArrayDup, lpFrame;
   UINT        uiLoopCount;

   BOOL        fAllocMemory = FALSE;
   if (hRPL = GlobalAlloc(GMEM_MOVEABLE, sizeof(RPLLIST)))
   {
        if (lpRPL = (LPRPLLIST)GlobalLock(hRPL))
        {
            if (hFrame = GlobalAlloc(GMEM_MOVEABLE, uiCount * sizeof(FRAME)))
            {
                if (lpFrameArrayDup = (LPFRAME)GlobalLock(hFrame))
                {
                    // all allocations are ok:
                    fAllocMemory = TRUE;
                }
                else
                {
                    GlobalFree(hFrame);
                    GlobalUnlock(hRPL);
                    GlobalFree(hRPL);     
                }
            }
            else
            {
                GlobalUnlock(hRPL);
                GlobalFree(hRPL);     
            }
        }
        else
        {
            GlobalFree(hRPL);
        }

   }
   
   if (!fAllocMemory)
   {
       return (HRE_ERROR);
   }


   lpFrame = lpFrameArrayDup;
   for(uiLoopCount=0; uiLoopCount<uiCount; uiLoopCount++)
   {
      *lpFrame++ = *lpFrameArray++;
   }

   lpRPL->uiCount = uiCount;
   lpRPL->lpFrame = lpFrameArrayDup;
   lpRPL->lpNextRPL = NULL;
   if(lpHREState->lpRPLHead == NULL)
   {
      // first RPL
      lpHREState->lpRPLHead = lpHREState->lpRPLTail = lpRPL;
   }
   else
   {
      lpHREState->lpRPLTail->lpNextRPL = lpRPL;
      lpHREState->lpRPLTail = lpRPL;
   }
   return(HRE_SUCCESS);
}

// ------------------------------------------------------------------------
static
UINT                            // HRE_SUCCESS if allocate memory OK
                                // HRE_ERROR if allocate memory failure
FreeRPL
(
   LPRPLLIST lpRPL
)
// PURPOSE
//                               Free a RPL entry and its frame array
//
// ------------------------------------------------------------------------
{
    GlobalFreePtr (lpRPL->lpFrame);
    GlobalFreePtr (lpRPL);
    return HRE_SUCCESS;
}