/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = DOWNLOAD.C
 *
 * DESCRIPTIVE NAME = PRINTER DRIVER SOURCE
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
 *      extern VOID   WriteChannel(PDDC,PBYTE,SHORT);
 *      extern BOOL   szIsEqual(PSZ,PSZ);
 *
*/
#pragma pack(1)
#define  INCL_GPIBITMAPS          /*            */
#define  INCL_WINSHELLDATA
#define  INCL_WINPOINTERS
#define  INCL_DOSMISC
#define  INCL_GPILCIDS              /*           */
#define  INCL_DOSSEMAPHORES
#define  INCL_GPIPRIMITIVES
#define  INCL_DDIBUNDLES
#define  INCL_DOSFILEMGR
#define  INCL_DOSERRORS

#include <string.h>
#include <stdlib.h>
#include <memory.h>
#include <os2.h>
#include <bseerr.h>
/*            */
#define  PASCAL
#define  FAR
#define  INCL_VMANDDI
#define  INCL_GREALL
#define  INCL_GRE_DEVICESURFACE
#include <ddi.h>
#include <pmddi.h>               /* include commonly used header file */

/*            */
#define  INCL_GENPLIB_MEMORY
#define  INCL_GENPLIB_THREAD
#include <genplib.h>
#include "inc\softfont.h"
#include "inc\prdtypet.h"           /* only so we can include the next one */
#include "inc\prdptypt.h"           /* FNT structure definition */
#include "inc\prdttypt.h"           /*           */
#include "inc\prddct.h"
#include "inc\ofm.h"                /*           OFM structure */
#include "inc\pspagtun.h"           /* V2.174057  Page Tuning */

/*
**  Constants
*/
#define RWBUFSIZE 500
#define ARBITRARY_CODEPAGE 65400    /*           IBM CODEPAGE number for arbitrary */

/*
**  External variables
*/
/* extern CHAR szInstalledFontDir[BUF_SIZE]; */

/*
**       External Function Prototypes
*/

extern VOID   WriteChannel(PDDC,PBYTE,SHORT); /* utlchnl.c */
extern BOOL   _System szIsEqual(PSZ,PSZ);

/*
**           This is in afmtopfm.h - if we get rid of that file here it is
*/
SHORT iWeightFactor[] =
{
  64,             /* a */
  14,             /* b */
  27,             /* c */
  35,             /* d */
 100,             /* e */
  20,             /* f */
  14,             /* g */
  42,             /* h */
  63,             /* i */
   3,             /* j */
   6,             /* k */
  35,             /* l */
  20,             /* m */
  56,             /* n */
  56,             /* o */
  17,             /* p */
   4,             /* q */
  49,             /* r */
  56,             /* s */
  71,             /* t */
  31,             /* u */
  10,             /* v */
  18,             /* w */
   3,             /* x */
  18,             /* y */
   2              /* z */
};

extern PVOID pProcessHeap;
extern GLOBALDATA globals;

  /*
  ** Internal Function Prototypes
  */

PSZ   SeekChar(CHAR,PSZ);
VOID  SendPFB( PDDC,  HFILE );                       /*           */

/*
**           
*/
INT _Optlink CopyStr( PSZ pszDst, PSZ pszSrc );


   /*
   ** Internal Functions
   */

/*
** !!! Utility   !!! ****   Temporary until
**  szCopy works
*/
/***************************************************************************
 *
 * FUNCTION NAME = CopyStr
 *
 * DESCRIPTION   = Copies NULL-terminated string from source to destination.
 *                 Returns the length of the string (not including the NULL
 *                 terminator).
 *
 * INPUT         = pszDst - Pointer to destination buffer where string goes.
 *                 pszSrc - Pointer to source buffer containing string to be
 *                   copied.
 *
 * OUTPUT        = Length of the copied string.
 *
 * RETURN-NORMAL = iStrLen
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/
/*
**           
** Modified this function for improved speed and reduced code size.
*/
INT _Optlink CopyStr( register PSZ pszDst, register PSZ pszSrc )
{
  register INT iStrLen = -1;    /* Contains string length (not 0-terminator) */

  do
  {
    iStrLen++;
  } while (*(pszDst++) = *(pszSrc++));

  return( iStrLen );
}


/***************************************************************************
 *
 * FUNCTION NAME = LoadFile
 *
 * DESCRIPTION   = Open and read in a file and return a pointer to it.
 *
 * INPUT         = pszFile
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = pData
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PVOID   LoadFile( PDV pdv, PSZ pszFile)
{
  HFILE      hFile;
  ULONG      usAction;
  ULONG      cbRead;
  FILESTATUS fs;
  PVOID      pData;
  APIRET     rc;
  LONG       lRequest;
  ULONG      ulNewMaxFH;
  INT        iRetry = 1;

  /*
  ** @2.195445
  ** Bump handles if needed, check RCs
  */

  do
  {
    rc = DosOpen( pszFile, (PHFILE) &hFile, &usAction, 0L, 0L, FILE_OPEN,
                  OPEN_READ_FLAGS, 0L );
    if ( rc == ERROR_TOO_MANY_OPEN_FILES )
    {
      lRequest = 1;
      DosSetRelMaxFH( &lRequest, &ulNewMaxFH );
    }
  } while ( rc && iRetry-- );


  if ( rc )
  {
    return NULL;
  }

  if ( DosQueryFileInfo( hFile, (SHORT) 1, (PVOID) &fs, sizeof(fs) ) )
  {
    return NULL;
  }

  if (pData = GplMemoryAlloc( pdv->pDCHeap, (LONG)fs.cbFile ))
  {
    if ( DosRead( hFile, (PVOID) pData, (SHORT) fs.cbFile, &cbRead ) )
    {
      return NULL;
    }
  }

  if (hFile)
  {
    DosClose( hFile );
  }
  return  pData;
}


/***************************************************************************
 *
 * FUNCTION NAME = SFDownload
 *
 * DESCRIPTION   = Download a Soft Font.
 *
 * INPUT         = pddc,pszPFB
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID SFDownload( PDDC pddc, PSZ pszPFB )

  /*  PSZ pszPFB;                          PFA file name, including path */
{
  HFILE hPFA;
  BYTE  abBuf[512];
  ULONG usAct, cRead;
  APIRET rc;
  LONG   lRequest;
  ULONG  ulNewMaxFH;
  INT    iRetry = 1;

  do  /* @2.195445 */
  {
    rc = DosOpen( pszPFB, (PHFILE) &hPFA, &usAct, 0L, 0, FILE_OPEN,
                  OPEN_READ_FLAGS, 0L );
    if ( rc == ERROR_TOO_MANY_OPEN_FILES )
    {
      lRequest = 1;
      DosSetRelMaxFH( &lRequest, &ulNewMaxFH );
    }
  } while ( rc && iRetry-- );

  if ( rc )
  {
    return;
  }

  /*           */
  SendPFB( pddc, hPFA );

  DosClose( hPFA );

  return ;
}


/*
** These functions sort of copied from softfont.c
*/
/*****************************************************************************\
**
** rwASCblock
**
** Writes out ascii part of PFB
**
\*****************************************************************************/

VOID rwASCblock( PDDC pddc, HFILE hPFB, USHORT bsize, PBYTE pInBuf )
{
  register USHORT i;
  PBYTE    pB;
  ULONG    ulAmount = (ULONG) bsize;

  pB = pInBuf;

  DosRead( hPFB, pInBuf, ulAmount, (PULONG)&ulAmount );

  /*
  ** Change the x0D CR to x0A LF which is handled better by our editors
  */
  for ( i = 0; i < ulAmount; i++ )
  {
    if ( ( *pB == '\r' ) ||
         ( *pB == (BYTE)0x1A ) )    /*            Get rid of EOF */
    {
      *pB = '\x0A';
    }
    pB++;
  }

  WriteChannel( pddc, pInBuf, ulAmount );
  return;
}


/*****************************************************************************\
**
** rwBINblock
**
** Writes out binary part converting to hex
**
\*****************************************************************************/

VOID rwBINblock( PDDC pddc, HFILE hPFB, USHORT bsize, PBYTE pInBuf,
                 PBYTE pOutBuf )
{
  #define  B2H(c) (UCHAR)((c) < 10 ? '0' + (c) : 'a' + (c) - 10)

  register USHORT i;
  register BYTE byte;
  PBYTE    pBIn;
  PBYTE    pBOut;
  ULONG    ulAmount = (ULONG) bsize;

  pBIn = pInBuf;
  pBOut = pOutBuf;

  DosRead( hPFB, pInBuf, ulAmount, (PULONG)&ulAmount );

  for ( i = 0; i < ulAmount; i++ )
  {
    byte = *pBIn++;
    *pBOut++ = B2H( (byte >> 4) );
    *pBOut++ = B2H( (byte & 0x0F) );
  }

  WriteChannel( pddc, pOutBuf, ulAmount * 2 );
  return;
}

/***************************************************************************
 *
 * FUNCTION NAME = ReadHeader
 *
 * DESCRIPTION   = Read in header.  Return TRUE iff it's valid and not EOF.
 *
 * INPUT         = (hPFB,pHdr)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL ReadHeader( HFILE hPFB, PBHEAD pHdr )
{
  ULONG cbRead;

  return ( !DosRead( hPFB, (PVOID) pHdr, sizeof(BHEAD), (PULONG)&cbRead)  &&
           cbRead == sizeof(BHEAD)                                       &&
           pHdr->bCheck == CHECK_BYTE                                    &&
           pHdr->bType != EOF_TYPE );
}


/*****************************************************************************\
**
** SendPFB
**
** Parse and send PFB file
**
\*****************************************************************************/

VOID SendPFB( PDDC pddc,  HFILE hPFB )
{
  BHEAD  Hdr;
  PBYTE  pInBuf;
  PBYTE  pOutBuf;
  USHORT nblocks;
  USHORT rblocks;
  USHORT i;

  /*
  ** Lets get some buffers - the buffers  in softfont are static - not good or
  ** available
  */
  if ( !(pInBuf = GplMemoryAlloc( pddc->pdv->pDCHeap, RWBUFSIZE ) ) )
  {
    return;
  }
  if ( !(pOutBuf = GplMemoryAlloc( pddc->pdv->pDCHeap, 2 * RWBUFSIZE ) ) )
  {
    return;
  }

  while ( ReadHeader( hPFB, (PBHEAD)&Hdr ) ) /* returns 'stuff to do?' */
  {
    nblocks = (USHORT) (Hdr.ulLength / (ULONG) RWBUFSIZE );
    rblocks = (USHORT) (Hdr.ulLength % (ULONG) RWBUFSIZE );

    for (i = 0; i < nblocks; i++)
    {
      if (Hdr.bType == BINARY_TYPE)
      {
        rwBINblock( pddc, hPFB, RWBUFSIZE, pInBuf, pOutBuf );
      }
      else
      {
        rwASCblock( pddc, hPFB, RWBUFSIZE, pInBuf );
      }
    }

    /*
    ** "Short bufs"
    */
    if (Hdr.bType == BINARY_TYPE)
    {
      rwBINblock( pddc, hPFB, rblocks, pInBuf, pOutBuf );
    }
    else
    {
      rwASCblock( pddc, hPFB, rblocks, pInBuf );
    }
  }
  GplMemoryFree( pInBuf );
  GplMemoryFree( pOutBuf );

  return;
}


/*
**           These group of functions below support the OFM stuff
*/


/*****************************************************************************\
**
** GetPM_Fonts
**
** Allocates buffer, gets font file names from ini
**
\*****************************************************************************/

PSZ GetPM_Fonts( PDV pdv )
{
  ULONG ulLen;
  PSZ pszFontFiles;

  /*
  ** See how many font files are in the PM_fonts in the ini file
  **
  ** First see how much we need - could be lots of fonts
  */
  PrfQueryProfileSize( HINI_PROFILE, "PM_Fonts", NULL, &ulLen );

  if ( ulLen == 0 )
  {
    return ( NULL ); /* no fonts */
  }

  pszFontFiles = (PSZ)GplMemoryAlloc( pdv->pDCHeap, (USHORT)ulLen +
                                      sizeof( USHORT ) );

  PrfQueryProfileString( HINI_PROFILE, "PM_Fonts", NULL, NULL, pszFontFiles,
                         ulLen );

  return( pszFontFiles );
}

/*****************************************************************************\
**
** IsOFMFile
**
** Checks suplied name to see if it ends in .ofm.  If true returns positive
** length.  If false returns negative length.
**
\*****************************************************************************/

LONG IsOFMFile( PSZ pszName )
{
  register SHORT sLength1;
  register SHORT sLength2;
  SHORT          sSign = -1;
  SHORT          sIsMARKSYM;

  sIsMARKSYM = ! strcmp( pszName, "MARKSYM.OFM" );

  sLength1 = 0;

  /*
  ** Find the dot if there is one
  */
  while ( *pszName &&
          *pszName != '.' )
  {
    sLength1++;
    pszName++;
  }

  /*
  ** if there are 4 char left and they are ".OFM"
  ** set up positive return
  */
  if ( (sLength2 = strlen(  pszName )) == 4 )
  {
    if ( *(pszName+1) == 'O' &&
         *(pszName+2) == 'F' &&
         *(pszName+3) == 'M' )
      sSign = 1;
  }

  if ( sIsMARKSYM )
    sSign = -1;

  return ( sLength1 + sLength2 ) * sSign;
}

/*****************************************************************************\
**
** isHWFont
**
** See if font is Printer font
**
\*****************************************************************************/

BOOL isHWFont( PFNT pFnt, PSZ pszFullName, USHORT uHWFonts )
{
  register SHORT i;

  if (! pszFullName ) /* For     names make em a dup */
  {
    return TRUE;
  }

  for ( i = 0; i < uHWFonts; i++ )
  {
    if ( szIsEqual( pszFullName, pFnt->pszFullName ) )
    {
      return TRUE;
    }
    pFnt++;
  }

  return FALSE;

}


/*
**           
** FillOFMFont has been changed to do one alloc for all 4 strings.  The ptrs
** then point into this buf
*/
/*****************************************************************************\
**
** FillOFMFont
**
\*****************************************************************************/

VOID FillOFMFont( PDV pdv, PFNT pFnt, PSZ pszKeyName )
{
  CHAR            chFontFileName[ 255 ];
  PCHAR           pFontFileName;
  ULONG           ulCount;
  POFMMETRICS     pOFM;
  PATMSTR         pFontName;
  PATMSTR         pFullName;
  LONG            lFileLen;
  LONG            lTotalLen;

  /*
  ** Save room for drive if needed
  */
  pFontFileName = chFontFileName+2;

  /*
  ** Lookup the actual full file name for the ofm file
  */
  if ( (ulCount = PrfQueryProfileString( HINI_PROFILE, "PM_Fonts",
     pszKeyName, NULL, pFontFileName, (ULONG) sizeof(chFontFileName)-2)) == 0 )
  {
    return;
  }

  if ( *pFontFileName == '\\' )   /* no drive, put in boot drive */
  {
    pFontFileName--;
    *pFontFileName = ':';
    pFontFileName--;
    *pFontFileName = (CHAR)globals.BootDrive;
  }


  pFnt->usResource = 0;                   /* SoftFont */

  /*
  ** Read in the whole file
  */
  if ( ( pOFM = LoadFile( pdv, pFontFileName ) ) == NULL )
  {
    /*
    ** If by remote chance OFM file fails to load set ptrs to NULL
    */
    pFnt->pszFullName = NULL;
    pFnt->pszFontName = NULL;
    return;
  }

  lFileLen = strlen( pFontFileName ) + 1; /* Len of OFM/PFM names + null */

  /*
  ** Old PFM (Packed Font Metrics) will have OFM.
  ** Old PFA (Packed Font ASCII  ) will have PFB.
  */

  /*
  ** FullName/FontName structs in OFM are OFFSETS not pointers
  */
  pFullName = (PATMSTR)((PBYTE)pOFM + (USHORT)pOFM->FullName );
  if ( pFullName->len > 31 )  /* Must truncate */
  {
    pFullName->str[31] = '\0';
    pFullName->len = 32;
  }
  else
  {
    pFullName->len++; /* include null */
  }

  pFontName = (PATMSTR)((PBYTE)pOFM + (USHORT)pOFM->FontName );
  if ( pFontName->len > 31 )  /* Must truncate */
  {
    pFontName->str[31] = '\0';
    pFontName->len = 32;
  }
  else
  {
    pFontName->len++; /* include null */
  }

  /* Total len of strings is 2 filenames + fontname + fullname */

  lTotalLen = ( lFileLen * 2 ) + pFullName->len + pFontName->len;

  if ( ! ( pFnt->pszFullName = GplMemoryAlloc( globals.hMCB, lTotalLen ) ) )
  {
    return;
  }

  strcpy( pFnt->pszFullName, pFullName->str );

  pFnt->pszFontName = pFnt->pszFullName + pFullName->len;

  strcpy( pFnt->pszFontName, pFontName->str );

  pFnt->pszOFM = pFnt->pszFontName + pFontName->len;

  strcpy( pFnt->pszOFM, pFontFileName );

  pFnt->pszPFB = pFnt->pszOFM + lFileLen;

  lFileLen -= 4;                             /* Change OFM to PFB */
  pFontFileName[ lFileLen   ] = 'P';
  pFontFileName[ lFileLen+1 ] = 'F';
  pFontFileName[ lFileLen+2 ] = 'B';

  strcpy( pFnt->pszPFB, pFontFileName );

  GplMemoryFree( pOFM ); /* Free the OFM data */

  return;
}

/*
**           
** SFReadOFMs either counts the number of OFM fonts in system -or-
** fills in the array of FNT structs with the requested info
*/
/*****************************************************************************\
**
** SFReadOFMs
**
** Acts as comined SFQueryFonts and FillSFonts depending on arguments
** If cFnt is 0 then we return a count else we get a list of OFM files
** from .ini and load the FNT struct from them.
**
\*****************************************************************************/

LONG   SFReadOFMs( PDV pdv, PFNT pFnt, BOOL bFillPFnt )
{
  PSZ            pszFontFiles;
  LONG           lCount = 0;
  LONG           lLength;

  pszFontFiles = globals.FontData.pszFontFiles;

  /*
  ** Then ini entry should be in form of  "name10name20nameN00"
  */
  while ( *pszFontFiles )
  {
    if ( (lLength = IsOFMFile( pszFontFiles )) > 0 )
    {
      lCount++;
      if ( bFillPFnt )
      {
        FillOFMFont( pdv, pFnt, pszFontFiles ); /* Call with key name */

        pFnt++;   /* go to next struct */
      }
    }
    else
    {
      lLength *= -1;
    }

    /*
    ** want to get to first character of NEXT name
    */
    pszFontFiles += lLength + 1;
  }

  return lCount;

}


/*
**           
** SFQueryFonts checks the font list. If different will reload global list
*/
/***************************************************************************
 *
 * FUNCTION NAME = SFQueryFonts
 *
 * DESCRIPTION   = How many Soft Fonts are available? Returns number,
 *                 or 0 for error.
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = cFonts
 *
 * RETURN-ERROR  = 0
 *
 **************************************************************************/

SHORT SFQueryFonts( PDV pdv )
{
  PSZ pszFontFiles;
  LONG lSize;
  INT  i;
  PFNT pFNT;

  //Lock (Font)globals before this call

  pszFontFiles = GetPM_Fonts( pdv );  /* Get list of fonts from ini */
  if ( ! pszFontFiles )
  {
    return 0;
  }

  /* Check if there has been a change since last time */

  if ( ( lSize = GplMemoryGetObjectSize( pszFontFiles ) ) ==
           GplMemoryGetObjectSize( globals.FontData.pszFontFiles )         &&
         ( ! memcmp( pszFontFiles, globals.FontData.pszFontFiles, lSize ) ) )
  {
    /* No Change return count */
    GplMemoryFree( pszFontFiles );
    return  globals.FontData.lCount ;
  }

  /*
  ** There is a difference so rebuild list
  */

  if ( globals.FontData.pszFontFiles )    /* Free the old ptr if needed */
  {
    GplMemoryFree( globals.FontData.pszFontFiles );
  }

  if ( globals.FontData.pFNTList )
  {
    pFNT = globals.FontData.pFNTList;
    for ( i = 0; i < globals.FontData.lCount; i++ )
    {
      GplMemoryFree( pFNT->pszFullName );
      pFNT++;
    }
    GplMemoryFree( globals.FontData.pFNTList );
  }

  /* Make a new copy of files */
  globals.FontData.pszFontFiles = GplMemoryAlloc( globals.hMCB, lSize );
  memcpy( globals.FontData.pszFontFiles, pszFontFiles, lSize );

  GplMemoryFree( pszFontFiles );

  globals.FontData.lCount = SFReadOFMs( pdv, NULL, FALSE );

  lSize = globals.FontData.lCount * sizeof( FNT );

  globals.FontData.pFNTList = GplMemoryAlloc( globals.hMCB, lSize );

  /* Fill in the PFN structs */

  return ( SFReadOFMs( pdv, globals.FontData.pFNTList, TRUE ) );

}


/*
**           
** FillSFonts now copies the global copy to the local memory
*/
/***************************************************************************
 *
 * FUNCTION NAME = FillSFonts
 *
 * DESCRIPTION   = Fill in FNT for each of the available soft fonts at the
 *                 address specified.
 *
 * INPUT         = pFnt,cFnt
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

VOID   FillSFonts( PDV pdv, PFNT pFnt,  SHORT cFnt, USHORT uHWFonts )

  /* PFNT pFnt;                            pointer, where to array of FNTs */
  /* SHORT cFnt;                          how many to put down, max */
{
  SHORT sUseDLFonts;        /*            */
  PFNT  pStartFNT;
  LONG  lCount;
  PFNT  pGlobalFnt;
  INT   iVarSize;

  //Lock (Font)globals before this call

  sUseDLFonts = pdv->sUseDLFonts;    /*            */
  lCount = globals.FontData.lCount;
  pGlobalFnt = globals.FontData.pFNTList;

  /*
  ** Point to start of font list
  */
  if ( pFnt )
  {
    pStartFNT = pFnt - uHWFonts;
  }

  while ( cFnt && lCount )
  {
    *pFnt = *pGlobalFnt;    /* Copy the FNT struct */

    /* Since only the first ptr is alloc-ed do it here */

    iVarSize = GplMemoryGetObjectSize( pGlobalFnt->pszFullName );
    pFnt->pszFullName = GplMemoryAlloc( pdv->pDCHeap, iVarSize );

    /* Copy the variable string data over form globale memory */

    memcpy( pFnt->pszFullName, pGlobalFnt->pszFullName, iVarSize );

    /* Now set pointers accordingly */

    pFnt->pszFontName = pFnt->pszFullName + strlen( pFnt->pszFullName ) + 1;

    pFnt->pszOFM      = pFnt->pszFontName + strlen( pFnt->pszFontName ) + 1;

    pFnt->pszPFB      = pFnt->pszOFM + strlen( pFnt->pszOFM ) + 1;

    /*
    ** If this is the same name as a HW font mark resource as -1
    */
    if ( isHWFont( pStartFNT, pFnt->pszFullName, uHWFonts ) ||
         ( sUseDLFonts == 0 )                                ) /*          */
    {
      pFnt->usResource = -1;
    }

    cFnt--;
    lCount--;
    pFnt++;
    pGlobalFnt++;

  }

}


/*****************************************************************************\
**
** Convert the OFM to our font struct
**
\*****************************************************************************/

PFONTDEF ConvertOFMtoPFM( PDV pdv, POFMMETRICS pOFM )
{
  PFONTDEF        pFD;
  PFONTHEADER     pFH;
  PFONTGLOBAL     pFG;
  PBYTE           pB;
  PCHARWIDTH      pCW;
  PCHARWIDTH      pCD;
  CHARWIDTH       cdSpaceChar;
  PKERNPAIRS      pKP;
  PATMSTR         pASTR;
  FONTMETRICS     fm;
  USHORT          usS;  /* general unsigned var */
  USHORT          usMax;
  ULONG           ulSum;
  register USHORT usGlyph;
  register USHORT usDupGlyph;
  register SHORT  sI;   /* general signed var   */
  long            lGlyphCount;

  #define GLYPHCOUNT 383

  /* Some countries have more than 383 glyphs */
  lGlyphCount = pOFM->CharacterCount > GLYPHCOUNT ? pOFM->CharacterCount :
                                                    GLYPHCOUNT;
  /*
  ** Calculate the size of FONTDEF
  ** Add up size of FONTDEF + 10 bytes for alignment here and there plus
  ** number of glyphs * size of CHARWIDTH  plus
  ** number of kerning pairs * size of KERNINGPAIRS plus
  ** 2 names font & family
  ** size of FONTMETRICS
  */

  usS = sizeof( FONTDEF ) + 10 + sizeof( FONTMETRICS );
  usS += lGlyphCount * sizeof( CHARWIDTH );  /* This is 1 more then sLastChar */
  usS += (USHORT)pOFM->KerningPairsCount * sizeof( KERNPAIRS );
  usS += 32 * 2;  /* font name */

  /*
  ** Alocate buffer
  */
  if ( (pFD = (PFONTDEF)GplMemoryAlloc( pdv->pDCHeap, usS )) == NULL )
    return ( pFD );

  /*
  ** Fill in Font Header
  */
  pFH = (PFONTHEADER )pFD;
  pFH->usVersion = 0; /* Not used anywhere */
  pFH->usGlobalOffset = sizeof( FONTHEADER );

  /*
  ** Fill in FontGlobal area
  */
  pFG = &(pFD->Global );
  pFG->fVariablePitch = ( pOFM->IsFixedPitch ) ? FALSE : TRUE ;
  pFG->sFontBBox[0] = (SHORT) ( pOFM->FontBBox.llx );
  pFG->sFontBBox[1] = (SHORT) ( pOFM->FontBBox.lly );
//fm.lMaxDescender = -(LONG)pFG->sFontBBox[1];
  fm.lMaxDescender = abs((LONG)pFG->sFontBBox[1] );
  pFG->sFontBBox[2] = (SHORT) ( pOFM->FontBBox.urx );
  pFG->sFontBBox[3] = (SHORT) ( pOFM->FontBBox.ury );
  fm.lMaxAscender = pFG->sFontBBox[3];
  pFG->usCapHeight = (USHORT)(pOFM->CapHeight );
  fm.lMaxBaselineExt = fm.lMaxAscender + fm.lMaxDescender;

  /*
  ** Point to variable area
  */
  pB = (PBYTE)pFD + sizeof( FONTDEF );
  if ( (ULONG) pB & 1 )
  {
    pB++;   /* Word align */
  }

  pFH->usCharMetricsOffset = (USHORT)(pB - (PBYTE)pFD );

  /*
  ** Must init the char data to -1 (unused)
  */
  pCD = (PCHARWIDTH)pB;
  for ( sI = 0; sI < lGlyphCount; sI++ )
  {
    pCD->glyph = (USHORT)-1;
    pCD++;
  }

  /*
  ** Copy over the char widths
  ** Note - the chararcters are placed in the array by their value eg. say the
  ** first character is 32 (space) it wuould be placed in [31] or thirty-second
  ** postion.
  */
  pCW = (PCHARWIDTH)((PBYTE)pOFM + (USHORT)pOFM->CharWidthsOffset );
  pCD = (PCHARWIDTH)pB;
  usS = (USHORT)pOFM->CharacterCount;   /* for optimization */
  for ( sI = 0; sI < usS; sI++ )
  {
/** if ( ( usGlyph = pCW->glyph ) < 256 )            **/
           usGlyph = pCW->glyph;
/** { **/
      *(pCD+(usGlyph-1)) = *pCW;
/** } **/
    /*           
    ** The glyphs below are duplicates do dup em
    */
    usDupGlyph = 0;
    switch( usGlyph )
    {
      case  20:           /* "paragraph"   */
        usDupGlyph = 244;
        break;
      case  21:           /* "section"     */
        usDupGlyph = 245;
        break;
      case  45:           /* "hyphen"      */
        usDupGlyph = 240;
        break;
      case  94:           /* "asciicircum" */
        usDupGlyph = 314;
        break;
      case 126:           /* "asciitilde"  */
        usDupGlyph = 315;
        break;
    }

    if ( usDupGlyph )
      *(pCD+(usDupGlyph-1)) = *pCW
      ;


    pCW++;
  }

  /*
  ** Use blank char (default) for -1 characters
  */
  cdSpaceChar = *(pCD+(' '-1));

  /*
  ** Loop through all the characters keeping track of the widest, a running
  ** sum and fixeding any -1 chars
  */
  pCD = (PCHARWIDTH)pB;
  usMax = 0;
  ulSum = (LONG)(pCD+(' '-1))->wx * 166L;
  for ( sI = 0; sI < lGlyphCount; sI++ )
  {
    if ( (usGlyph = pCD->glyph) != (USHORT)-1 )
    {
      if ( pCD->wx > (SHORT) usMax )
        usMax = (USHORT)pCD->wx;

      if ( (SHORT) usGlyph >= 'a' && (SHORT) usGlyph <= 'z' )
        ulSum += (LONG)((LONG)pCD->wx * (LONG)iWeightFactor[usGlyph - 'a'] );
    }
    else
    { /*
      ** Any necessary character that this font does not support will currently
      ** have ipscriptCode == -1. Force all of these characters to map to (and
      ** have character metrics of) the default character, typically a blank.
      */
      *pCD = cdSpaceChar;
    }
    pCD++;
  }
  fm.lMaxCharInc = (LONG)usMax;
  fm.lAveCharWidth = ulSum / 1000L;

  /* Even up */
  if ( (ULONG) ( pB += lGlyphCount * sizeof(CHARWIDTH)) & 1 )
    pB++;

  pFH->usKerningDataOffset = (USHORT)(pB - (PBYTE)pFD );

  /*
  ** Copy the Kerning Data over
  */
  pKP = (PKERNPAIRS)((PBYTE)pOFM + (USHORT)pOFM->KerningPairsOffset );
  usS = (USHORT)pOFM->KerningPairsCount;   /* for optimization */
  for ( sI = 0; sI < usS; sI++ )
  {
    *((PKERNPAIRS)pB) = *((PKERNPAIRS)pKP );
    pB += sizeof(KERNPAIRS );
    pKP++;
  }

  /* Even up */
  if ( (ULONG) pB & 1 )
  {
    pB++;
  }

  /*
  ** Set up strings offset -- only font name is needed
  */
  pFH->usStringsOffset = (USHORT)(pB - (PBYTE)pFD );

  pASTR = (PATMSTR)((PBYTE)pOFM + (USHORT)pOFM->FullName );
  if ( pASTR->len > 31 )  /* Must truncate */
  {
    pASTR->str[31] = '\0';
  }

  CopyStr( (PSZ) pB, (PSZ) pASTR->str );
  pB += pASTR->len + 1;

  /*
  ** Copy into FONTMETRICS while still set up
  */
  CopyStr( (PSZ) fm.szFacename, (PSZ) pASTR->str );

  /* Even up */
  if ( (ULONG) pB & 1 )
  {
    pB++;
  }

  pFH->usMetricsOffset = (USHORT)(pB - (PBYTE)pFD );

  /*
  ** Set up fontmetrics
  */
  pASTR = (PATMSTR)((PBYTE)pOFM + (USHORT)pOFM->FamilyName );
  if ( pASTR->len > 31 )  /* Must truncate */
  {
    pASTR->str[31] = '\0';
  }
  CopyStr( (PSZ) fm.szFamilyname, (PSZ) pASTR->str );

  /*
  ** -- See strings section above for fm.szFacename
  */
  fm.idRegistry          =(USHORT)pOFM->Registry;
/*fm.usCodePage          = 850; */
  fm.lEmHeight           = 1000;
  fm.lXHeight            = pOFM->XHeight;
  fm.lLowerCaseAscent    = pOFM->Ascender;
  fm.lLowerCaseDescent   = -(LONG)pOFM->Descender;
  fm.lInternalLeading    = fm.lMaxAscender - fm.lLowerCaseAscent;
  fm.lExternalLeading    = 0;
  fm.usWidthClass        = 5;
  fm.lEmInc              = 1000L;
  fm.sCharSlope          = -FIXEDINT(pOFM->ItalicAngle );
  fm.sInlineDir          = 0;
  fm.sCharRot            = 0;
  fm.usWeightClass       = (USHORT)pOFM->WeightClass;
  fm.sXDeviceRes         = 1000;
  fm.sYDeviceRes         = 1000;
  fm.sFirstChar          = 1;
  fm.sLastChar           = lGlyphCount - 1;
  fm.sDefaultChar        = 31;
  fm.sBreakChar          = 31;
  fm.sNominalPointSize   = 120;
  fm.sMinimumPointSize   = 10;
  fm.sMaximumPointSize   = 7200;
  fm.fsType = 0;
  if ( pOFM->IsFixedPitch )
  {
    fm.fsType |= FM_TYPE_FIXED;
  }
  if ( pOFM->KerningPairsCount )
  {
    fm.fsType |= FM_TYPE_KERNING;
  }
  fm.fsDefn              = FM_DEFN_OUTLINE;
  fm.fsSelection         = 0;
  if ( fm.sCharSlope )
  {
    fm.fsSelection |= FM_SEL_ITALIC;
  }
  fm.fsCapabilities      = 0;
  fm.lSubscriptXSize     = 650L;
  fm.lSubscriptYSize     = 600L;
  fm.lSubscriptXOffset   = 0L;
  fm.lSubscriptYOffset   = fm.lSuperscriptYSize / 2;
  fm.lSuperscriptXSize   = 650L;
  fm.lSuperscriptYSize   = 600L;
  fm.lSuperscriptXOffset = 0L;
  fm.lSuperscriptYOffset = pOFM->CapHeight * 4 / 10;
  fm.lUnderscoreSize     = pOFM->UnderlineThickness;
  fm.lUnderscorePosition = abs(pOFM->UnderlinePosition );
  fm.lStrikeoutSize      = pOFM->UnderlineThickness;
  fm.lStrikeoutPosition  = fm.lLowerCaseAscent / 2;
  fm.sKerningPairs       = (SHORT) pOFM->KerningPairsCount;
  fm.sFamilyClass        = (SHORT) pOFM->FontClass;
  fm.lMatch              = 0L;

  /*           
  ** Make some changes if encoding scheme is FontSpecific
  */
  if ( szIsEqual( (PSZ) (((PATMSTR)((PBYTE)pOFM + (USHORT)pOFM->EncodingScheme))->str),
                  (PSZ) "AdobeStandardEncoding" )   ||
       szIsEqual( (PSZ) (((PATMSTR)((PBYTE)pOFM + (USHORT)pOFM->EncodingScheme))->str),
                  (PSZ) "SymbolExtension" ) )  /* APL fix */
  {
    fm.usCodePage = 850;
  }
  else
  {
    fm.usCodePage = ARBITRARY_CODEPAGE;
    fm.sLastChar = 255;
  }

  /*
  ** Copy over the font metrics
  */
  utl_memcopy( pB, (PSZ) &fm, sizeof(FONTMETRICS) );

  pB += sizeof( FONTMETRICS );
  /* Even up */
  if ( (ULONG) ( pB ) & 1 )
  {
    pB++;
  }

  pB -= pFH->usCharMetricsOffset;
  pFH->usSectionsSize = OFFSETOF( pB );

  return( pFD );
}

/*****************************************************************************\
**
** DefaultFontCount
**
\*****************************************************************************/

LONG DefaultFontCount( PDESPPD pdesPpd )
{
  LONG lFontCount;

  /*
  ** Initial count is FreeVM ( base memory minus fixed overhead ) minus
  ** 100000 for work space divided by 80K (est of font )
  */
  if ( pdesPpd->desItems.lFreeVM  <= 100000L     ||
       (lFontCount =
       ((((pdesPpd->desItems.lFreeVM - 100000L) * 100 / 80000L ) + 50) / 100 ) )
        < 2 )
  {
    lFontCount = 2;   /* All printers can take 2 fonts */
  }

  return lFontCount;
}

/*****************************************************************************\
**
** ConvertPFM
**
** This function converts the old PFM with CHARDATA to having CHARWIDTH data.
** The glyph = bPscriptCode and wx = sWidthX, llx = 0 and ury = wx
**
\*****************************************************************************/

PFONTDEF ConvertPFM( PDV pdv, PFONTDEF pPFM )
{
  typedef struct _KCHARCOUNT {
    BYTE cChar;
    BYTE uCount;
  } KCHARCOUNT, *PKCHARCOUNT;

  typedef struct _KCHARAMOUNT {
    BYTE cChar;
    SHORT sAmount;
  } KCHARAMOUNT, *PKCHARAMOUNT;

  PFONTDEF        pFD;
  PFONTHEADER     pFH;
  PFONTGLOBAL     pFG;
  PCHARWIDTH      pCW;
  PCHARDATA       pCD;
  USHORT          usS;  /* general unsigned var */
  PFONTMETRICS    pFontMetrics;
  PBYTE           pB;
  SHORT           i, j;
  SHORT           sFirstToLastChar;
  USHORT          usShift;
  USHORT          usSize;
  PKERNPAIRS      pKP;
  PBYTE           pKernData;
  SHORT           sKPCount;
  BYTE            KernChar1;
  SHORT           count;


  pFontMetrics = (PFONTMETRICS)((PBYTE)pPFM + pPFM->Header.usMetricsOffset);
  sFirstToLastChar = pFontMetrics->sFirstChar + pFontMetrics->sLastChar;
  sKPCount = pFontMetrics->sKerningPairs;

  usSize = pPFM->Header.usMetricsOffset + sizeof( FONTMETRICS );
  /*
  ** New size is old size plus number of chars times the size difference plus
  ** 10 for slack
  */
  usS =  usSize +
         (sFirstToLastChar + 2) * (sizeof(CHARWIDTH) - sizeof(CHARDATA)) +
         sKPCount * sizeof(KERNPAIRS) +
         10;
  /*
  ** Alocate buffer - note: it will be zero filled
  */
  if ( (pFD = (PFONTDEF)GplMemoryAlloc( pdv->pDCHeap, usS )) == NULL )
    return ( pFD );

  /*
  ** copy the fixed part
  */
  *pFD = *pPFM;

  /* Point to chardata in resource */
  pCD = (PCHARDATA)((PBYTE)pPFM + pPFM->Header.usCharMetricsOffset);
  pB  = (PBYTE)pFD  + pFD->Header.usCharMetricsOffset;
  pCW = (PCHARWIDTH)pB;

  for ( i = 0; i <= sFirstToLastChar; i++ )
  {
    pCW->glyph = pCD->bPscriptCode;
    pCW->urx = pCW->wx  = pCD->sWidthX;
    pCW++;
    pCD++;
  }

  /* Even up */
  pB = (PBYTE)pCW;
  if ( (ULONG)pB & 1 )
    pB++;

  pFD->Header.usKerningDataOffset = (USHORT)(pB - (PBYTE)pFD );

  pKP = (PKERNPAIRS)pB;
  pKernData = (PBYTE)((PBYTE)pPFM + pPFM->Header.usKerningDataOffset);
  i = 0;
  while ( i < sKPCount )
  {
    count = ((PKCHARCOUNT)pKernData)->uCount;
    KernChar1 = ((PKCHARCOUNT)pKernData)->cChar;
    pKernData += sizeof(KCHARCOUNT);
    for ( j = 0; j < count; j++ )
    {
      pKP->g1 = KernChar1;
      pKP->g2 = ((PKCHARAMOUNT)pKernData)->cChar;
      pKP->KernUnits = ((PKCHARAMOUNT)pKernData)->sAmount;
      pKP++;
      pKernData += sizeof(KCHARAMOUNT);
    }
    i += count;
  }
  pB = (PBYTE)pKP;
  if ( (ULONG)pB & 1 )
    pB++;

  pFD->Header.usStringsOffset = (USHORT)(pB - (PBYTE)pFD );

  usShift = pFD->Header.usStringsOffset - pPFM->Header.usStringsOffset;

  memcpy( pB, (PBYTE)pPFM + pPFM->Header.usStringsOffset,
              usSize - pPFM->Header.usStringsOffset );

  /*
  ** Reset the offsets with the shift
  */
  pFD->Header.usMetricsOffset     += usShift;
  pFD->Header.usSectionsSize      += usShift;

  return pFD;

}
/*
**           These group of functions above support the OFM stuff
*/
