/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark 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 = PRDESUB3.C
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *
 * FUNCTIONS   : prde_ReadPrinterProperties
 *               prde_PM_DD_Read
 *               prde_PM_DD_Exist
 *               prde_ReadOldConfig
 *               prde_ConvertOldIniEntry
 *               prde_GetIniVersionType
 *               prde_TranslateOldDriverData
 *               prde_TranslateOldDriverDataFrm
 *               prde_TranslateOldBody
 *               prde_Translate4224Forms
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES       : Printer Device Driver Design
 *               Device Driver Interface Specification
 *               Printer Device Driver Design Specification
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#define INCL_32                         /* Convert to C/SET2    CON3201       */
#define INCL_DOSPROCESS                 /* Convert to C/SET2    CON3201       */
#define INCL_DOSSEMAPHORES
#define INCL_WINWINDOWMGR
#define INCL_GPIERRORS
#define INCL_SHLERRORS
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_DOSMODULEMGR
#define INCL_WINFRAMEMGR
#define INCL_WINLISTBOXES
#define INCL_WINBUTTONS
#define INCL_WINERRORS
#define INCL_WINDIALOGS
#define INCL_WINSHELLDATA
#define INCL_WINENTRYFIELDS
#define INCL_WINMESSAGEMGR
#define INCL_WININPUT
#define INCL_WINMENUS
#define INCL_WINPOINTERS
#define INCL_DEV
#include <os2.h>
#undef INCL_DOSPROCESS                  /* Convert to C/SET2    CON3201       */
#undef INCL_DOSSEMAPHORES
#undef INCL_WINWINDOWMGR
#undef INCL_GPIERRORS
#undef INCL_SHLERRORS
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_DOSMODULEMGR
#undef INCL_WINFRAMEMGR
#undef INCL_WINLISTBOXES
#undef INCL_WINBUTTONS
#undef INCL_WINERRORS
#undef INCL_WINDIALOGS
#undef INCL_WINSHELLDATA
#undef INCL_WINENTRYFIELDS
#undef INCL_WINMESSAGEMGR
#undef INCL_WININPUT
#undef INCL_WINMENUS
#undef INCL_WINPOINTERS
#undef INCL_DEV

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS

#define INCL_WINP_SELSERVER
#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELSERVER
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI

#define INCL_WINSHELLDATA
/* #include <pmshlp.h>                                              DLM01 */
#define INCL_WINSHELLDATA
#undef INCL_32                          /* Convert to C/SET2    CON3201       */

#include <prdconse.h>
#include <prddcone.h>
#include <prdmcone.h>
#include <prdtcone.h>

#define NO_SYS
#define INCL_HELP
#define PRDMTYPE_INCL
#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL
#undef NO_SYS
#undef INCL_HELP
#undef PRDMTYPE_INCL

#include <prdeextf.h>
#include <prdyextf.h>
#include <prduextf.h>


/*
**  Set up external accesses
*/
extern lpDMSettings           DVTDfltDMSettings [];
extern USHORT                 DEFAULT_PRINTER;
extern USHORT                 NO_OF_PRINTERS;
extern PCHAR                  OS2_INI_VERSION;
extern PCHAR                  OS2_INI_MAGIC_NUMBER1;
extern PCHAR                  OS2_INI_MAGIC_NUMBER2;
extern PCHAR                  OS2_INI_THRESHOLD;
extern PCHAR                  OS2_INI_VERSION_THRESHOLD1;
extern PCHAR                  OS2_INI_VERSION_THRESHOLD2;
extern PCHAR                  DOWNSYSFONTS_THRESHOLD;
extern USHORT                 DRIVER_TYPE;
extern USHORT                 DEFAULT_PRINTER;
extern PCHAR                  DriverNameString;
extern HMODULE                prdd_ModHandle;


/****************************************************************************
 *
 * FUNCTION NAME = prde_ReadPrinterProperties
 *
 * DESCRIPTION   = This function build an appname using LPName, DeviceName
 *                 and DriverName.  It reads the ini entry for this appname
 *                 and returns a pointer to this data.
 *
 * INPUT         = PBYTE     LPName               Logical Printer Name
 *                 PBYTE     DeviceName           Device Name
 *                 USHORT far * pPrinterType      PrinterType
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

#if 0
PBYTE pascal far prde_ReadPrinterProperties( LPName,
                                             DeviceName,
                                             pPrinterType )

PBYTE        LPName;
PBYTE        DeviceName;
USHORT far * pPrinterType;
#endif

PBYTE prde_ReadPrinterProperties( PBYTE   LPName,          /* CON3201 */
                                  PBYTE   DeviceName,      /* CON3201 */
                                  USHORT *pPrinterType )   /* CON3201 */

{
#define TFUNC "prde_ReadPrinterProperties"

    /*
    **  LOCAL VARIABLES
    */
    ULONG     IniSize; /* The size of the entry in OS2.INI CON3201   */
    USHORT    Result;
    BOOL      ModuleOK;
    PBYTE     KeyName;
    PBYTE     KeyNameBuffer;
 /* PFN       pPrfQueryProfSz;                               CON3201  */
 /* PFN       pPrfQueryProfData;                             CON3201  */
    HMODULE   ModuleHandle;
    PBYTE     DataStart;       /* Start of the printer data in OS2.INI*/

    /*
    ** Read data from OS2.INI and a pointer to a buffer is returned.
    */
    DataStart = prde_PM_DD_Read(LPName,
                                DeviceName,
                                pPrinterType);

    /*
    **  If there is no printer setting for this logical printer. Read
    **  all the logical printers and see if there is printer setting
    **  for any logical printer. If yes then use this setting instead
    **  of default setting. The OS2 1.3.0 has a problem which does not
    **  give us the logical printer name and if there is no driver data
    **  we use the application default printer.
    */
    if ( DataStart == FNULL )
    {
        if ( PrfQueryProfileSize( HINI_SYSTEMPROFILE,
                                  (PSZ)"PM_SPOOLER_PRINTER",
                                  (PSZ)FNULL,
                                  &IniSize) )
        {
            KeyNameBuffer = FNULL;
            Result = SafeSSALLOCMEM(&KeyNameBuffer, IniSize, 0);

            if (Result != DOS_OK)
            {
                goto PM_DD_READ_END;
            }
            /*
            ** Read PM_SPOOLER_PRINTER entry with a null key name. this
            ** returns a list of all listed logical printer name seperated
            ** from each other by one null. The list is terminated by two
            ** nulls.
            */
            if ( PrfQueryProfileData( HINI_SYSTEMPROFILE,        /*CON3201*/
                                      (PSZ)"PM_SPOOLER_PRINTER", /*CON3201*/
                                      (PSZ)FNULL,                /*CON3201*/
                                      (PVOID)KeyNameBuffer,      /*CON3201*/
                                      &IniSize ) )               /*CON3201*/
            {
                KeyName =  KeyNameBuffer;
                while ( *KeyName && (DataStart == FNULL) )
                {
                   /*
                   **  Read data from OS2.INI for this logical printer.
                   */
                   DataStart = prde_PM_DD_Read( KeyName,
                                                DeviceName,
                                                pPrinterType);

                   if ( (DataStart != FNULL) &&
                        (DataStart != (PBYTE)ERROR_NEG) )
                   {
                       /*
                       **  Need printername to copy into driver data.
                       */
                       prdu_strcpyN ( LPName, KeyName, 32 );
                       break;
                   }

                   while ( *KeyName++ );  /* get next key name*/

                }  /* while ( *KeyName && (DataStart == FNULL) )      */


            }  /* if ( pPrfQueryProfData( HINI_USERPROFILE,           */

            SSFREEMEM(KeyNameBuffer);

        }  /* if ( pPrfQueryProfSz( HINI_USERPROFILE,                 */

    } /* if ( DataStart == FNULL )                                    */

PM_DD_READ_END:
    if (DataStart == (PBYTE)ERROR_NEG )
    {
        DataStart = FNULL;
    }
    return( DataStart );

}
#undef TFUNC

/****************************************************************************
 *
 * FUNCTION NAME = prde_GetDefaultPrinter
 *
 * DESCRIPTION   = This function finds the first selected printer and makes
 *                 it the default printer.
 *
 *
 * INPUT         = PBYTE        LPName            Logical Printer Name
 *                 PBYTE        DeviceName        Device Name
 *                 USHORT far * pPrinterType      PrinterType
 *                 BOOL far *   pDfltPtrType
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID prde_GetDefaultPrinter( PBYTE   LPName,               /* CON3201 */
                             PBYTE   DeviceName,           /* CON3201 */
                             USHORT *pPrinterType,         /* CON3201 */
                             BOOL   *pDfltPtrType )        /* CON3201 */

{
#define TFUNC "prde_GetDefaultPrinter"

    /*
    ** Local Variables
    */
    ULONG     IniSize;         /* The size of the entry in OS2.INI CON3201   */
    USHORT    Result;
    BOOL      ModuleOK;
    PBYTE     KeyName;
    PBYTE     KeyNameBuffer;
 /* PFN       pPrfQueryProfSz;                               CON3201  */
 /* PFN       pPrfQueryProfData;                             CON3201  */
    HMODULE   ModuleHandle;
    PBYTE     DataStart;       /* Start of the printer data in OS2.INI*/
    PBYTE     StartPtr;
    BYTE      Terminator;
    BYTE      pszWord[100];
    USHORT    i;
    CHAR      Prntr_Name_Buf[MAX_PRNTR_NAME];

    *pDfltPtrType = TRUE;

    if ( PrfQueryProfileSize( HINI_SYSTEMPROFILE,          /* CON3201 */
                              (PSZ)"PM_SPOOLER_PRINTER",   /* CON3201 */
                              (PSZ)FNULL,                  /* CON3201 */
                              &IniSize) )                  /* CON3201 */
    {
       KeyNameBuffer = FNULL;
       Result = SafeSSALLOCMEM(&KeyNameBuffer, IniSize, 0);  /* CON3201 */
       if (Result != DOS_OK)
       {
          return;
       }
       /*
       ** Read PM_SPOOLER_PRINTER entry with a null key name. this
       ** returns a list of all listed logical printer name seperated
       ** from each other by one null. The list is terminated by two
       ** nulls.
       */
       if ( PrfQueryProfileData( HINI_SYSTEMPROFILE,       /* CON3201 */
                                 (PSZ)"PM_SPOOLER_PRINTER",/* CON3201 */
                                 (PSZ)FNULL,               /* CON3201 */
                                 (PVOID)KeyNameBuffer,     /* CON3201 */
                                 &IniSize ) )              /* CON3201 */
       {
          KeyName =  KeyNameBuffer;
          while ( *KeyName )
          {
             prdu_strcpy( (PBYTE) LPName,
                          (PBYTE) KeyName );

             StartPtr = prde_ReadIniFile( LPName, (PSZ)"PM_SPOOLER_PRINTER"); /* CON3201 */

             if ( (StartPtr != FNULL) && (StartPtr != (PBYTE)ERROR_NEG) )
             {
                /*
                **  first ';' is for logical printer address
                */
                while ( *StartPtr++ != ';');

                Terminator = ',';                          /* CON3201 */

                while ( Terminator != ';' )
                {
                   prde_ReadTerminatedWordFromText (pszWord,
                                                    &Terminator,
                                                    (PBYTE)",;",
                                                    &StartPtr);

                   if ( !prdu_strcmpN( (PBYTE)pszWord,DriverNameString,
                                        DRIVER_NAME_LEN ))
                   {

                      for ( i = 0; i < NO_OF_PRINTERS; i++ )
                      {
                         /*
                         ** description string from the RC file.
                         */
                         WinLoadString( hab,
                                        prdd_ModHandle,
                                        IDS_FIRST_PRINTER + i,
                                        MAX_PRNTR_NAME,
                                       (PSZ)Prntr_Name_Buf );

                         /*
                         **  Now compare strings. If they match then build a
                         **  keyword to read PM_SPOOLER_DD entry in INI file.
                         */
                         if ( !prdu_strcmp(pszWord+8,
                                           Prntr_Name_Buf))
                         {
                            *pPrinterType = i;

                            prdu_strcpy(DeviceName,
                                        DriverNameString);

                            *(DeviceName+DRIVER_NAME_LEN)='.';

                            prdu_strcpy(
                                  DeviceName+DRIVER_NAME_LEN+1,
                                  Prntr_Name_Buf);

                            *pDfltPtrType = FALSE;

                            Terminator = ';';

                            *(KeyName + 0) = '\0';
                            *(KeyName + 1) = '\0';
                            break;
                         }
                      }
                   }
                }
                if ( StartPtr )                            /* CON3201 */
                {
                   SSFREEMEM(StartPtr);                    /* CON3201 */
                }
             }
             while ( *KeyName++ );  /* get next key name*/
          }
       }
       SSFREEMEM(KeyNameBuffer);                           /* CON3201 */
    }
    if (*pDfltPtrType == TRUE)
    {
       LPName[0] = '0';
    }
    return;
}
#undef TFUNC

/****************************************************************************
 *
 * FUNCTION NAME = prde_PM_DD_Read
 *
 * DESCRIPTION   = This function build an appname using LPName, DeviceName
 *                 and DriverName.  It reads the ini entry for this appname
 *                 and returns a pointer to this data.
 *
 * INPUT         = PBYTE     LPName               Logical Printer Name
 *                 PBYTE     DeviceName           Device Name
 *                 USHORT far * pPrinterType      PrinterType
 *
 * OUTPUT        = PBYTE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PBYTE prde_PM_DD_Read( PBYTE   LPName,                     /* CON3201 */
                       PBYTE   DeviceName,                 /* CON3201 */
                       USHORT *pPrinterType )              /* CON3201 */

{
#define TFUNC "prde_PM_DD_Read"

    /*
    **  Local Variables
    */
    BYTE      AppName[100];
    PBYTE     pDest;           /* Pointers used to copy information   */
    PBYTE     pSource;         /*                                     */
    USHORT    IniSize;         /* The size of the entry in OS2.INI    */
    SHORT     IniVersionType;  /* Driver version number               */
    USHORT    Result;
    PBYTE     Buffer=FNULL;    /* PD00607: Initialize pointer to NULL */
    ULONG     Size;            /* CON3201  Change from USHORT         */
 /* PFN       pPrfQueryProfSz;                               CON3201  */
 /* PFN       pPrfQueryProfData;                             CON3201  */
    HMODULE   ModuleHandle;
    USHORT    DosResult;
    BOOL      ModuleOK;
    PBYTE     IniData;         /* Pointer into the OS2.INI file for   */
    PBYTE     NameStart;       /* Start of the printer name in OS2.INI*/
    PBYTE     TempBuffer;
    PBYTE     DataStart;       /* Start of the printer data in OS2.INI*/

    /*
    **  If any parameter is null then return a null buffer.
    */
    if ( !DeviceName || !LPName )
    {
        return(FNULL);
    }

    /*
    **  Set up the AppName.
    */
    AppName[0]  = 'P';
    AppName[1]  = 'M';
    AppName[2]  = '_';
    AppName[3]  = 'D';
    AppName[4]  = 'D';
    AppName[5]  = '_';

    /*
    **  Add LPName.
    */
    pDest = AppName+6;
    pSource = LPName;

    while ( *pDest++ = *pSource++ );

    pDest--;
    *pDest++ = ',';

    /*
    **  Add DeviceName.
    */
    pSource = DeviceName;
    while ( *pDest++ = *pSource++ );


    if ( !prdu_strcmp( (PBYTE)DeviceName, DriverNameString ) &&
         ( DeviceName[ DRIVER_NAME_LEN ] != '.' ))
    {
        return( prde_ReadOldConfig( LPName, DeviceName, pPrinterType) );
    }
    else
    {
        /*
        **  Read the size of OS2.INI data.
        */
        if ( prde_PM_DD_Exist(LPName,DeviceName) )
        {
            /*
            **  Read the size of OS2.INI data.
            */
            if ( PrfQueryProfileSize( HINI_SYSTEMPROFILE,      /* CON3201 */
                                      (PSZ)AppName,            /* CON3201 */
                                      (PSZ)"DRIVERDATA",       /* CON3201 */
                                      &Size) )                 /* CON3201 */
            {
                /*
                ** There is an entry for this driver in the OS2.INI file -
                ** allocate a segment for data from OS2.INI file.
                */
                if ( (Result = SafeSSALLOCMEM (&Buffer, Size, 0)) != DOS_OK )/* CON3201 */
                {
                    return((PBYTE)ERROR_NEG);
                }

                /*
                **  Read the OS2.INI data into the buffer.
                */
                if ( PrfQueryProfileData( HINI_SYSTEMPROFILE,      /* CON3201 */
                                          (PSZ)AppName,            /* CON3201 */
                                          (PSZ)"DRIVERDATA",       /* CON3201 */
                                          (PVOID)Buffer,           /* CON3201 */
                                          &Size ))                 /* CON3201 */
                {
                    return(Buffer);
                }
            }
        }
    }

    if ( Buffer )
        SSFREEMEM(Buffer);                                 /* CON3201 */
    /*
    **  PD00436
    **  Read Old configuration. This will also read old 4019 version 22X.
    */
    if ( !(Buffer = prde_ReadOldConfig( LPName, DeviceName, pPrinterType)) )
    {
        DeviceName[ DRIVER_NAME_LEN ] = '\0';
        Buffer = prde_ReadOldConfig( LPName, DeviceName, pPrinterType);
        DeviceName[ DRIVER_NAME_LEN ] = '.';
    }

    return(Buffer);
}
#undef TFUNC


/****************************************************************************
 *
 * FUNCTION NAME = prde_PM_DD_EXIST
 *
 * DESCRIPTION   = This function build an appname using LPName, DeviceName
 *                 and DriverName.  It reads the ini entry for this appname
 *                 and the VERSION key name.  If the version exist and is
 *                 current it returns TRUE, otherwise it returns FALSE.
 *
 * INPUT         = PBYTE     LPName               Logical Printer Name
 *                 PBYTE     DeviceName           Device Name
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL prde_PM_DD_Exist( PBYTE LPName,                       /* CON3201 */
                       PBYTE DeviceName )                  /* CON3201 */

{
#define TFUNC "prde_PM_DD_Exist"

    /*
    ** Local Variables
    */
    BYTE      AppName[100];
    PBYTE     pDest;           /* Pointers used to copy information   */
    PBYTE     pSource;         /*                                     */
    ULONG     IniSize;         /* The size of the entry in OS2.INI CON3201 */
    SHORT     IniVersionType;  /* Driver version number               */
 /* PFN       pPrfQueryProfSz;                               CON3201  */
 /* PFN       pPrfQueryProfData;                             CON3201  */
    HMODULE   ModuleHandle;
    USHORT    DosResult;
    BOOL      ModuleOK;
    BYTE      VersionBuf[5];

    /*
    ** If any parameter is null then return a null buffer.
    */
    if ( !DeviceName || !LPName )
    {
        return(FALSE);
    }

    /*
    ** Set up the AppName.
    */
    AppName[0]  = 'P';
    AppName[1]  = 'M';
    AppName[2]  = '_';
    AppName[3]  = 'D';
    AppName[4]  = 'D';
    AppName[5]  = '_';

    /*
    ** Add LPName.
    */
    pDest = AppName+6;
    pSource = LPName;

    while ( *pDest++ = *pSource++ );

    pDest--;
    *pDest++ = ',';

    /*
    ** Add DeviceName.
    */
    pSource = DeviceName;
    while ( *pDest++ = *pSource++ );

    if ( !PrfQueryProfileSize( HINI_SYSTEMPROFILE ,    /* CON3201 */
                               (PSZ)"PM_SPOOLER_DD",   /* CON3201 */
                               (PSZ)DeviceName,        /* CON3201 */
                               &IniSize) )             /* CON3201 */
    {
        return(FALSE);
    }

    /*
    ** Read the size of OS2.INI data.
    */
    if ( !PrfQueryProfileSize( HINI_SYSTEMPROFILE ,    /* CON3201 */
                               (PSZ)AppName,           /* CON3201 */
                               (PSZ)"VERSION",         /* CON3201 */
                               &IniSize) )             /* CON3201 */
    {
        WinGetLastError(hab);
        return(FALSE);
    }
    /*
    **  Read data from OS2.INI and store in the VersionBuf
    */
/*  IniSize = 4;   CON32B - Resetting this value will cause the       */
/*                 PrfQueryProfileData call to fail so leave it alone */
    if ( !PrfQueryProfileData( HINI_SYSTEMPROFILE,         /* CON3201 */
                               (PSZ)AppName,               /* CON3201 */
                               (PSZ)"VERSION",             /* CON3201 */
                               (PVOID)VersionBuf,          /* CON3201 */
                               &IniSize ) )                /* CON3201 */
    {
        WinGetLastError(hab);
        return(FALSE);
    }

    /*
    ** Get the version number.
    */
    *(VersionBuf+3) = '\0';

    /*
    **  Work out whether the .ini entry is current, and whether we can use it.
    */
    IniVersionType = prde_GetIniVersionType(VersionBuf);

    /*
    ** There is a valid entry.
    */
    if ( IniVersionType == INI_VERSION_CURRENT )
        return(TRUE);
    else
        return(FALSE);
}
#undef TFUNC




/****************************************************************************
 *
 * FUNCTION NAME = prde_ReadOldConfig
 *
 * DESCRIPTION   = This function returns a old configuration for specific
 *                 printer type and logical printer.  If it does not exist
 *                 returns NULL.
 *
 *                 This routine was changed to read PM_SPOOLER_DD using
 *                 DeviceName KeyWord instead of DriverNameString.  Added
 *                 code to migrate 4019 drivers version 22X.
 *
 * INPUT         = PBYTE        LPName            Logical Printer Name
 *                 PBYTE        DeviceName;
 *                 USHORT far * pPrinterType      address of printer type
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


PBYTE prde_ReadOldConfig( PBYTE   LPName,                  /* CON3201 */
                          PBYTE   DeviceName,              /* CON3201 */
                          USHORT *pPrinterType )           /* CON3201 */

{
#define TFUNC "prde_ReadOldConfig"

    /*
    **  Local Variables
    */
    SHORT     IniVersionType;  /* Driver version number               */
    USHORT    Result;
    PBYTE     Buffer = FNULL; /* PD00607                             */
    ULONG     Size;           /* CON3201                             */
    HMODULE   ModuleHandle;
    USHORT    DosResult;
    BOOL      ModuleOK;
    PBYTE     IniData;         /* Pointer into the OS2.INI file for   */
    PBYTE     NameStart;       /* Start of the printer name in OS2.INI*/
    PBYTE     TempBuffer;
    PBYTE     DataStart;       /* Start of the printer data in OS2.INI*/

    /*
    **  If any parameter is null then return a null buffer.
    */
    if ( !LPName )
    {
        return(FNULL);
    }

    /*
    ** This is an old entry and it was not converted to new
    ** format at install time. Read the size of OS2.INI data.
    */
    if ( !PrfQueryProfileSize( HINI_SYSTEMPROFILE,   /* CON3201 */
                               (PSZ)"PM_SPOOLER_DD", /* CON3201 */
                               (PSZ)DeviceName,      /* CON3201 */
                               &Size) )              /* CON3201 */
    {
        return((PBYTE)FNULL);
    }
    else
    {
        /*
        **  There is an entry for this driver in the OS2.INI
        **  file. Allocate a segment for data from OS2.INI file.
        */
        if ( (Result = SafeSSALLOCMEM (&Buffer, Size, 0)) != DOS_OK )/* CON3201 */
        {
            return((PBYTE)FNULL);
        }

        /*
        **  Read the OS2.INI data into the buffer.
        */

        if ( !PrfQueryProfileData( HINI_SYSTEMPROFILE,   /* CON3201 */
                                   (PSZ)"PM_SPOOLER_DD", /* CON3201 */
                                   (PSZ)DeviceName,      /* CON3201 */
                                   (PVOID)Buffer,        /* CON3201 */
                                   &Size) )              /* CON3201 */
        {
            SSFREEMEM(Buffer);                           /* CON3201 */
            return((PBYTE)FNULL);
        }

        /*
        ** First parm is "IBM4019.DRV"
        */
        for (IniData = Buffer; *IniData++ != ';'; );

        /*
        **  2nd parm is the version number. If no version
        **  return a null pointer.
        */
        if ( *IniData == ';' || *(IniData+3) != ';')
        {
             SSFREEMEM(Buffer);                 /* CON3201 */
             return((PBYTE)FNULL);
        }


        /*
        **  Get the version number.
        */
        for (NameStart = IniData; *IniData != ';';  IniData++);

        *IniData = '\0';

        /*
        **  Work out whether the .ini entry is current,
        **  and whether we can use it.
        */
        IniVersionType =  prde_GetIniVersionType(NameStart);

        *IniData = ';';
        switch (IniVersionType)
        {
            case INI_VERSION_PREVIOUS:
             /*
             **  The ini entry is in an old format that we
             **  can read. Call ConvertOldIniEntry which
             **  grabs a new buffer, writes data in the
             **  new format into the new buffer, and
             **  throws away the current IniBuffer. It
             **  returns a pointer to the new one.
             **  We translate the whole of the driver's
             **  .ini entry so that when the entry is
             **  written back to os2sys.ini, it will all
             **  be in the current format.
             */
             TempBuffer = prde_ConvertOldIniEntry (
                                           Buffer,
                                           (PUSHORT)&Size,
                                           DeviceName,
                                           pPrinterType );
             if ( !TempBuffer )
             {
                 /*
                 **  Couldn't alloc new segments in sub-
                 **  routine. Don't change to new buffer.
                 */
                 SSFREEMEM(Buffer);             /* CON3201 */
                 return((PBYTE)FNULL);
             }
             else
             {
                 /*
                 **  Subroutine call successful. Reset
                 **  IniBuffer and all pointers into it.
                 */
                 Buffer = TempBuffer;
                 NameStart = Buffer;
                 while ( *NameStart++ != ';');
                 NameStart += 4;
                 IniData = NameStart;

             }
             break;

            default :
             /*
             **        version - don't use the data
             */
             SSFREEMEM(Buffer);                /* CON3201 */
             return((PBYTE)FNULL);
        }
        /*
        **  We are searching for the name to match Printer-
        **  Name to so if we have reached an '=' try to match
        **  the name.  Otherwise if we have found a ',' then
        **  the next character is the start of a new name and
        **  if we have found a ';' then there are no more
        **  names.
        */
        while ( *IniData )
        {
            if ( *IniData == '=' )
            {
                /*
                **  Make the name in the IniBuffer null terminated
                **  so we can use strcmp on it.
                */
                *IniData = '\0';

                if ( !prdu_strcmpN( LPName, NameStart, 32) )
                {
                    /*
                    **  The name matches so move to scanning the
                    **  data and set DataStart.
                    */
                    *IniData = '=';

                    DataStart = IniData + 1;

                    while ( *IniData != ',' && *IniData != ';' )
                    {
                        IniData++;
                    }

                    *IniData++ = ';';

                    *IniData = '\0';

                    return(DataStart);
                }
                /*
                **  Restore the '=' to IniBuffer as we may be
                **  copying this data back to OS2.INI.
                */
                *IniData = '=';
            }

            if ( *IniData == ',' )
            {
                NameStart = IniData + 1;
            }

            IniData++;
        } /* while                ...........................*/

        /*
        **  The logical printer was not in the INI.
        */
        SSFREEMEM(Buffer);                    /* CON3201 */
        return((PBYTE)FNULL);
    }
}

#undef TFUNC



/****************************************************************************
 *
 * FUNCTION NAME = prde_ConvertOldIniEntry
 *
 * DESCRIPTION   = This function takes old format .ini entries and convert
 *                 it to the new format.
 *
 *                 This function takes the driver's .ini entry for old
 *                 versions of 42xx, 52xx and 4019 and creates from it a new
 *                 format, without losing information.  It throws away the
 *                 old entry and returns a pointer to the new.
 *
 *                 This function is called from prdm_Dialog.
 *
 *
 * INPUT         = PBYTE         pSource          ptr to start of old entry
 *                 PUSHORT       pEntryLength     ptr to length of old entry
 *                 PBYTE far *   pKeyWord;        ptr to DeviceName
 *                 USHORT far *  pPrinterType;    ptr to printer type
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PBYTE prde_ConvertOldIniEntry( PBYTE    pSource,            /* CON3201 */
                               PUSHORT  pEntryLength,       /* CON3201 */
                               PBYTE    DeviceName_KeyWord, /* CON3201 */
                               USHORT  *pPrinterType )      /* CON3201 */

{
#define TFUNC "prde_ConvertOldIniEntry"

    /*
    **  Local Variables
    */
    USHORT          Result;             /* return from functions      */
    USHORT          NewEntrySize;       /* size of new .ini entry     */
    PBYTE           pDest;              /* ptr into new .ini entry    */
    BYTE            Separator;          /* keeps track of where we are*/
    USHORT          TypeEntryLength;    /* size of old 42xx/52xx      */
                                        /*   printer type entry       */
    PBYTE           pDestHeaderStart;   /* ptr to start of header     */
    lpDMSettings    TempDMSettings;     /* Stores old 4019 info       */
    USHORT          Type;               /* Printer Type               */
    BOOL            FoundType;          /* Falg for finding printer   */
    CHAR            Prntr_Name_Buf[MAX_PRNTR_NAME];
    PBYTE           pEntry;             /* CON3201 ptr to entry start */
    /*
    **  A safe estimate for the size of a new driver entry compared to
    **  an old one is to add 50 bytes.
    */
    NewEntrySize = *pEntryLength + (*pEntryLength >> 3) + 1;

    Result = SafeSSALLOCMEM ( &pDest,                       /* CON3201 */
                              NewEntrySize,                 /* CON3201 */
                              0 );                          /* CON3201 */

    if ( Result != DOS_OK )
    {
        return (PBYTE)NULL;
    }

    pEntry = pDest;                  /* CON3201 Save entry start addr */

    Result = SafeSSALLOCMEM ( &TempDMSettings,              /* CON3201 */
                              sizeof(DMSettingsType),       /* CON3201 */
                              0 );                          /* CON3201 */

    if ( Result != DOS_OK )
    {
        return (PBYTE)NULL;
    }

    /*
    **  Start copying old entry into new. Copy the driver name and ';'.
    */
    while ( (*pDest++ = *pSource++) != ';');

    /*
    **  Skip past the version number in the source; write the current
    **  version number in the dest.
    */
    while ( *pSource++ != ';');

    prdu_strcpy(pDest, OS2_INI_VERSION);
    pDest += 3;
    *pDest++ = ';';

    /*
    **  Set separator to null. It will be set to the character after
    **  the entry for each logical printer name. This character is ','
    **  if there are more printers listed and ';' if not.
    */
    Separator = '\0';

    /*
    **  There might not be any printers listed - in this case the char
    **  at pSource will be ';'. Copy this across and we're done.
    */
    if (*pSource == ';')
    {
        Separator = ';';
        *pDest++ = *pSource;
    }

    /*
    **  Now both pSource and pDest point to just after the version
    **  number. Go through the entry for each logical printer name.
    */
    while (Separator != ';')
    {
        FoundType = FALSE;             /* FoundType flag to not found */

        /*
        **  Copy across the <PrinterName>= string.
        */
        while ( (*pDest++ = *pSource++) != '=');

        /*
        ** We must convert an old-style 42xx or 52xx entry. The
        ** differences are: header increased by 15 bytes and
        ** entry length (for each printer type) increased by 36.
        **
        ** Copy across the current printer type, which is 2 bytes
        ** long.
        */

        if (*pPrinterType == 99)
        {
            /*
            **  Read in the Printer type for this entry.
            */
            prdm_ReadWordFromText( *pPrinterType,
                                   PRINTER_TYPE_LENGTH,
                                   (pSource) );


            /*
            **  description string from the RC file.
            */
            WinLoadString( hab,
                           prdd_ModHandle,
                           IDS_FIRST_PRINTER + *pPrinterType,
                           MAX_PRNTR_NAME,
                           (PSZ)Prntr_Name_Buf );

            prdu_strcpy(DeviceName_KeyWord, DriverNameString);

            *(DeviceName_KeyWord+DRIVER_NAME_LEN)='.';

            prdu_strcpy( DeviceName_KeyWord+DRIVER_NAME_LEN+1,
                         Prntr_Name_Buf);


        }
        else
        {
            pSource++;
            pSource++;
        }
        /*
        **  Loop for each printer type listed.
        */
        Separator = '\0';

        while ( !Separator )
        {
            /*
            **  Remember pDest.
            */
            pDestHeaderStart = pDest;

            /*
            **  Read in the Printer type for this entry.
            */
            prdm_ReadWordFromText( Type,
                                   PRINTER_TYPE_LENGTH,
                                   (pSource) );

            /*
            **  Read the entry length, add 15, and write it.
            */
            prdm_ReadWordFromText( TypeEntryLength,
                                   NO_DATA_SIZE_DIGITS,
                                   pSource );

            pSource -= (PRINTER_TYPE_LENGTH +
                        NO_DATA_SIZE_DIGITS);

            if ( *pPrinterType == Type)
            {
                /*
                **  If it is a 4224 printer we need to get
                **  rid of the envelope forms as we copy everything else.
                **
                **  If it isn't we just copy the same as we did before.
                */
                if ( (DRIVER_TYPE == DDT_IBM42XX_DRV) &&
                     ( (Type == IBM_4224_MONO) ||
                       (Type == IBM_4224_COLOR) ) )
                {
                    /*
                    **  Call new routine to convert the 4224 INI.
                    */
                    prde_Translate4224Forms( (PBYTE *)&pSource,  /* CON3201 */
                                             (PBYTE *)&pDest,    /* CON3201 */
                                             TypeEntryLength);
                }
                else
                {
                    /*
                    **  Copy the PrinterType field in the header.
                    */
                    prdu_memcpy( pDest, pSource, 2);

                    pSource += 2;
                    pDest += 2;

                    TypeEntryLength += 36;         /* PD00285             */

                    prdm_WriteTextFromWord( TypeEntryLength,
                                            NO_DATA_SIZE_DIGITS,
                                            pDest );

                    pSource += NO_DATA_SIZE_DIGITS;
                    /*
                    **  Copy more of the header up to the start of the
                    **  new fields. This is 31 bytes' worth.
                    */
                    prdu_memcpy( pDest, pSource,31);

                    pSource += 31;
                    pDest += 31;

                    /*
                    **  Write 15 zeroes into the dest buffer.
                    */
                    prdu_memset( pDest, '0',3);
                    pDest += 3;

                    prdu_memset( pDest, '1',1); /* set SimDup to default */
                    pDest += 1;                 /* PD00058               */


                    prdu_memset( pDest, '0',32);  /*PD00285              */
                    pDest += 32;

                    /*
                    **  Copy the rest of the info for this printer type.
                    **  Length still to copy is TypeEntryLength - 53.
                    */
                    TypeEntryLength -= 74;          /* PD00285            */

                    prdu_memcpy( pDest, pSource, TypeEntryLength);

                    pSource += TypeEntryLength;
                    pDest += TypeEntryLength;

                } /* ... if ( (DRIVER_TYPE == DDT_IBM42XX_DRV) && ...     */

                /*
                **  The first byte in DfltFontInfo is font type
                **  (resident, card etc). The constants for the
                **  types are different in the old and new styles
                **  so convert this.  PD00340
                */
                prde_ReadHeaderData( TempDMSettings,
                                     pDestHeaderStart,
                                     INI_VERSION_CURRENT );

                prde_TranslateOldBody( pDestHeaderStart+HEADER_LENGTH,
                                       TempDMSettings );


                FoundType = TRUE;       /* found printer type         */

            }   /* if ( pPrinterType == Type )                        */
            else
            {
                pSource += TypeEntryLength;
            }

            /*
            **  If the next character is a separator (',' or ';')
            **  then we've done all the types listed for this
            **  logical printer name.
            */
            if (*pSource == ',' || *pSource == ';')
            {
                /*
                **  Set Separator to get out of this loop and copy
                **  the separator across.
                */
                Separator = *pSource;
                *pDest++ = *pSource++;
            }

        }          /*  ... while more printer type info ...  */

        /*
        **  Check if we found data for this printer type. If not remove
        **  the logical printer name.
        */
        if ( !FoundType )
        {
           pDest--;                         /* PD00252                    */
           pDest--;                         /* PD00252                    */
           for (; (*pDest != ',') && (*pDest != ';'); pDest-- );
        }
    }
    /*
    **  Finish off the new entry with a null. But if the last thing we
    **  put there was ',' then replace it with ';'.
    */
    if ( *pDest == ',' && !FoundType )
    {                                       /* PD00252                   */
        *pDest = ';';                       /* took out *pDest++ = ';';  */
    }
    else
    {
       if ( *pDest == ';' && !FoundType )   /* PD00252                   */
       {
           *pDest++;
           *pDest = ';';                    /* took out *pDest++ = ';';  */
       }
    }
    pDest++;
    *pDest = '\0';

    /*
    **  We've translated the whole of the driver entry. Throw away the
    **  segment containing the old driver entry.
    */
    SSFREEMEM( pSource );                               /* CON3201 */

    SSFREEMEM ( TempDMSettings );                       /* CON3201 */

    /*
    **  Reset EntryLength to the length of the new entry.
    */
    *pEntryLength = pDest - pEntry + 1; /* Compute entry len CON3201 */

    /*
    **  Return a pointer to the start of the new entry.
    */
    return ( pEntry );                                  /* CON3201 */
}
#undef TFUNC


/****************************************************************************
 *
 * FUNCTION NAME = prde_GetIniVersionType
 *
 * DESCRIPTION   = The merged drivers can read .ini entry formats from
 *                 previous drivers.  This routine works out whether the
 *                 .ini entry is of the current format, a previous format
 *                 (which we can read) or is unusable.
 *
 *                 For each driver there is a threshold .ini version number
 *                 OS2_INI_THRESHOLD:  an entry that is older than this is
 *                 unusable.
 *
 *                 Entries older than OS2_INI_MAGIC_NUMBER1 are in an old
 *                 format and need translation.
 *
 *                 Entries between OS2_INI_MAGIC_NUMBER1 and
 *                 OS2_INI_VERSION_THRESHOLD1 are development version and is
 *                 unudable.
 *
 *                 4019 Driver ONLY:
 *                 Entries between OS2_INI_VERSION_THRESHOLD1 and
 *                 OS2_INI_VERSION_THRESHOLD2 are in old format and need
 *                 translation.
 *
 *                 Entries older that OS2_INI_MAGIC_NUMBER2 but not older
 *                 than OS2_INI_MAGIC_NUMBER1:  are development version and
 *                 is unusable.
 *
 *                 Entries with version numbers between OS2_INI_MAGIC_NUMBER2
 *                 and OS2_INI_VERSION are in the current format.
 *
 *                 These numbers are defined in prdd42xx.c etc.
 *
 *
 * INPUT         = PBYTE     VersionNumber   from .ini entry
 *
 * OUTPUT        = USHORT
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

USHORT  prde_GetIniVersionType( PBYTE VersionNumber )      /* CON3201 */

{
#define TFUNC "prde_GetIniVersionType"
    /*
    **  Local variables.
    */
    USHORT              ReturnVal;

    if ( prdu_strcmp( (PBYTE)OS2_INI_THRESHOLD,
                                            (PBYTE)VersionNumber ) < 0 )
    {
        /*
        **  The .ini entry is too old to use.
        */
        ReturnVal = INI_VERSION_DONT_USE;
    }
    else if ( prdu_strcmp( (PBYTE)OS2_INI_MAGIC_NUMBER1,
                                            (PBYTE)VersionNumber ) < 0 )
    {
        /*
        **  The .ini entry version is at the threshold value or
        **  after, but before the INI magic number.
        */
        ReturnVal = INI_VERSION_PREVIOUS;
    }
    else if ( prdu_strcmp( (PBYTE)OS2_INI_VERSION_THRESHOLD1,
                                           (PBYTE)VersionNumber ) < 0 )
    {
        /*
        **  The .in entry version is development version.
        */
        ReturnVal = INI_VERSION_DONT_USE;
    }
    else if ( prdu_strcmp( (PBYTE)OS2_INI_VERSION_THRESHOLD2,
                                           (PBYTE)VersionNumber ) < 0 )
    {
        /*
        **  The .in entry version is development version for 42XX and
        **  52XX drivers. It is 22X version for 4019 driver.
        */
        ReturnVal = INI_VERSION_DONT_USE;
    }
    else if ( prdu_strcmp( (PBYTE)OS2_INI_MAGIC_NUMBER2,
                                           (PBYTE)VersionNumber ) < 0 )
    {
        /*
        **  The .in entry version is development version.
        */
        ReturnVal = INI_VERSION_DONT_USE;
    }
    else if ( prdu_strcmp( (PBYTE)OS2_INI_VERSION,
                                           (PBYTE)VersionNumber ) <= 0 )
    {
        /*
        **  The .in entry version is current.
        */
        ReturnVal = INI_VERSION_CURRENT;
    }
    else
    {
        /*
        **  The .ini entry is more recent than the driver. Don't
        **  use it - anything might have happened.
        */
        ReturnVal = INI_VERSION_DONT_USE;
    }

#ifdef TEST_TYPE_OLD_INI
    Ring3OutputPair( "Return IniVersionType ", (ULONG)ReturnVal, DECIMAL);
#endif

    return ReturnVal;
}
#undef TFUNC


/****************************************************************************
 *
 * FUNCTION NAME = prde_TranslateOldDriverData
 *
 * DESCRIPTION   = This routine converts the previous version of the Driver
 *                 data and puts it into the current driver data format.
 *
 *
 * INPUT         = PBYTE     DriverData
 *                 PDRIVDATA OldDriverData
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

USHORT prde_TranslateOldDriverData ( pDMDriverStruc DriverData,    /* CON3201 */
                                     PDRIVDATA      OldDriverData) /* CON3201 */

{
   PULONG   DataToConvert;         /* Pointer to the old data */
   ULONG    OldData;               /* Temporary value for storing old data */
   PBYTE    OldPrinterName;        /* Pointer to the old printer name */
   CHAR     Prntr_Name_Buf[MAX_PRNTR_NAME]; /* Stores the printer array */
   BYTE     CountryCode[4];        /* Country code            */
   ULONG    DefaultForm;

   if (DRIVER_TYPE == DDT_IBM42XX_DRV)
   {
      DataToConvert = (PULONG)OldDriverData->abGeneralData;
      /*
      **  Set the printertype and the name to the corresponding printer in
      **  the old driver data.
      */

      DriverData->PrinterType = *DataToConvert++;

      WinLoadString( hab,
                     prdd_ModHandle,
                     (USHORT)(IDS_FIRST_PRINTER + DriverData->PrinterType),
                     MAX_PRNTR_NAME,
                     (PSZ)Prntr_Name_Buf );

      prdu_strcpy(OldDriverData->szDeviceName,
                              Prntr_Name_Buf);

      /*
      **  Do a one to one map
      */

      DriverData->Resolution = *DataToConvert++;
      DriverData->Orientation = *DataToConvert++;
      DriverData->NumberOfForms = *DataToConvert++;
      DriverData->FormNumber1 = *DataToConvert++;
      DriverData->FormNumber2 = *DataToConvert++;

      /*
      **  PD00307
      **  Have to adjust form numbers for the 4224s as we've gotten
      **  rid of the 6 envelope forms.
      */
      if ( (DRIVER_TYPE == DDT_IBM42XX_DRV) &&
           ( (DriverData->PrinterType == IBM_4224_COLOR) ||
             (DriverData->PrinterType == IBM_4224_MONO) ) )
      {

        PrfQueryProfileString( HINI_USERPROFILE,                   /* CON3201 */
                               (PSZ)"PM_National",                 /* CON3201 */
                               (PSZ)"iCountry",                    /* CON3201 */
                               (PSZ)"1",                           /* CON3201 */
                               CountryCode,                        /* CON3201 */
                               3 );                                /* CON3201 */

        if (((CountryCode[0] == '1') &&
             (CountryCode[1] == '\0') ) ||
              !prdu_strcmpN(CountryCode,"55",3) )                  /* PD00812 */
        {
            DefaultForm = DEFAULT_PAPER_FORM_US;
        }
        else
        {
            DefaultForm = DEFAULT_PAPER_FORM_NONUS;
        }
          if (DriverData->FormNumber1 >= NEW_NO_OF_4224_FORMS)
          {
              if (DriverData->FormNumber1 >= OLD_NO_OF_4224_FORMS)
                  DriverData->FormNumber1 -= 6;
              else
                  DriverData->FormNumber1 = DefaultForm;
          }

          if (DriverData->FormNumber2 >= NEW_NO_OF_4224_FORMS)
          {
              if (DriverData->FormNumber2 >= OLD_NO_OF_4224_FORMS)
                  DriverData->FormNumber2 -= 6;
              else
                  DriverData->FormNumber2 = DefaultForm;
          }
      }

      OldPrinterName = OldDriverData->abGeneralData + 24;
      prdu_memcpy ( DriverData->PrinterName, OldPrinterName, 35 );
      DriverData->DriverType = DRIVER_TYPE;
      DriverData->Resolution2 = DriverData->Resolution;  /* PD00587 */
      DriverData->Resolution3 = DriverData->Resolution;  /* 600DPI  */
   }
   return(OK);
}

/****************************************************************************
 *
 * FUNCTION NAME = prde_TranslateOldDriverDataFrm
 *
 * DESCRIPTION   = This routine converts the previous version of the Driver
 *                 data forms and puts it into the current driver data
 *                 format.
 *
 * INPUT         = PBYTE     DriverData
 *                 PDRIVDATA OldDriverData
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 *                                                             PD00041
 ****************************************************************************/

VOID prde_TranslateOldDriverDataFrm ( pDMDriverStruc DriverData,    /*CON3201*/
                                      PBYTE          pFormData,     /*CON3201*/
                                      BOOL           ConvertForm1,  /*CON3201*/
                                      BOOL           ConvertForm2 ) /*CON3201*/

{

    PBYTE  pTmpFormData;       /* pointer to the form data */
    PBYTE  pFormNameData;      /* pointer to the form name */
    PBYTE  pFormInfoData;      /* pointer to the driver data form structure */

    /*
    **  If the form is in the valid range look up the form information
    **  in the INI data that was passed in as pFormData.  All that is needed
    **  is the name, units, and type.  The rest of the information will be
    **  put into pDMSettings based on this information.
    */

    if (ConvertForm1)
    {
       pTmpFormData = pFormData + DriverData->FormNumber1 *
                      (FORM_DATA_LENGTH + 2);

       pFormNameData = pTmpFormData + 2;
       pFormInfoData = (PBYTE)DriverData->FormInfo1.FormName;
       while (*pFormNameData != 1)
       {
          *pFormInfoData = *pFormNameData;
          pFormInfoData++;
          pFormNameData++;
       }
       *pFormInfoData = 0;
       pFormNameData++;                                            /* PD00615 */
       DriverData->FormInfo1.FormType = *pTmpFormData;
       DriverData->FormInfo1.FormUnits = *pFormNameData;
    }

    if (ConvertForm2)
    {
       pTmpFormData = pFormData + DriverData->FormNumber2 *
                      ( FORM_DATA_LENGTH + 2 );

       pFormNameData = pTmpFormData + 2;
       pFormInfoData = (PBYTE) DriverData->FormInfo2.FormName;
       while (*pFormNameData != 1)
       {
          *pFormInfoData = *pFormNameData;                         /* PD00615 */
          pFormInfoData++;
          pFormNameData++;
       }
       *pFormInfoData = 0;
       pFormNameData++;
       DriverData->FormInfo2.FormType = *pTmpFormData;
       DriverData->FormInfo2.FormUnits = *pFormNameData;
    }

}
/****************************************************************************
 *
 * FUNCTION NAME = prde_TranslateOldBody
 *
 * DESCRIPTION   = This function reads the variable length body data from
 *                 the INI entry for the given printer to convert the first
 *                 byte in DfltFontInfo (font type: resident, card, etc).
 *                 The constants for the types are different in the old and
 *                 new styles.
 *
 * INPUT         = PBYTE        pSource        Pointer to INI data
 *                 lpDMSettings TempDMSettings
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID prde_TranslateOldBody( PBYTE        pSource,          /* CON3201 */
                            lpDMSettings TempDMSettings )  /* CON3201 */

{
#define TFUNC "prde_TranslateOldBody"

    /*
    **  Local Variables
    */
    SHORT      FormNum;        /* Loop control to fetch data on all   */
                               /* the defined forms                   */
    USHORT     Result;         /* Function call return values         */
    USHORT     i, j;           /* Loop control variables              */
    USHORT     ListIndex;      /* Index of selected item in list box  */
    USHORT     CodePageNo;     /* Index into DVT code page list       */
    USHORT     PathNameSize;   /* For download fonts and code pages   */
    USHORT     NoOfManualPaper;
    USHORT     NoOfManualEnv;
    /*
    **  For every form that is defined: Pass the data from the OS2.INI
    **  file.
    */
    for ( FormNum = 0; FormNum < TempDMSettings->NumberOfForms; FormNum++ )
    {
        /*
        **  Read in the form type and form ID
        */
        pSource++;
        pSource++;

        /*
        **  pass form data into our storage converting ALT_POINTs
        **  to the correct decimal point character.
        */
        for ( i = 0; i < FORM_DATA_LENGTH; i++, pSource++ );
    }
    /*.. for (FormNum = 0; FormNum < ....every defined form.......*/

    /*
    **  Get the source form data.
    **  The source form data has the following format :-
    **  Form number in paper trays 1 .. MAX_NO_OF_PAPER_TRAYS
    **  Form number in the tractor feed
    **  Form number in the envelope tray
    **  Number of manual paper forms followed by form numbers
    **  Number of manual envelope forms followed by form numbers
    */
    if ( TempDMSettings->SourceDataSize )
    {
        /*
        **  pass the form numbers mounted in the automatic paper trays.
        */
        for ( i = 0; i < NO_OF_AUTO_TRAYS; i++ )
        {
            pSource += NO_FORM_CNT_DIGITS;
        }

        /*
        **  Get the number of manual paper forms.
        */
        prdm_ReadWordFromText( NoOfManualPaper,
                               NO_FORM_CNT_DIGITS,
                               pSource );

        /*
        **  Now read in form numbers for the manual paper forms.
        */
        for ( i = 0; i < NoOfManualPaper; i++ )
        {
            pSource += NO_FORM_CNT_DIGITS;
        }

        /*
        **  Get the number of manual envelope forms.
        */
        prdm_ReadWordFromText( NoOfManualEnv,
                               NO_FORM_CNT_DIGITS,
                               pSource );

        /*
        **  Now read in form numbers for the manual paper forms.
        */
        for ( i = 0; i < NoOfManualEnv; i++ )
        {
            pSource += NO_FORM_CNT_DIGITS;
        }

    }  /*..........if TempDMSettings->SourceDataSize != 0 ...........*/

    /*
    ** Get all the indexes of the owned cards.
    */
    if ( TempDMSettings->NumberOwnedCards )
    {
        /*
        **  For each index in the Ini file.
        */
        for ( i = 0; i < TempDMSettings->NumberOwnedCards; i++ )
        {
            pSource += NO_INDEX_DIGITS;
        }

    }

    /*
    **  pass the index of the cards in the slots.
    */
    for ( i = 0; i < MAX_NO_OF_CARD_SLOTS; i++ )
    {
        pSource += NO_INDEX_DIGITS;
    }

    /*
    **  Pass the names of all the cards from the shipped set.
    */
    if ( TempDMSettings->ShippedCardCount )
    {
        /*
        **  Pass the data from the Ini file buffer.
        */
        for ( i = 0;
              i < (TempDMSettings->ShippedCardCount * sizeof(tCard));
              i++, pSource++ );
    }

    /*
    **  Pass the path names of all the added cards.
    */
    if ( TempDMSettings->CardDataSize )
    {
        /*
        **  Pass the data from the Ini file buffer.
        */
        for ( i = 0; i < TempDMSettings->CardDataSize; i++, pSource++ );
    }

    /*
    ** Pass the info for the download fonts.
    */
    if ( TempDMSettings->NumberOfDownFonts )
    {

        /*
        **  Cycle through the fonts in the INI file.
        */
        for ( i = 0; i < TempDMSettings->NumberOfDownFonts; i++ )
        {
            PathNameSize = 0;
            for ( j = 0; j < PATHNAME_SIZE_LENGTH; j++ )
            {
                PathNameSize *= 10;
                PathNameSize += pSource[j] - '0';
            }

            for ( j = 0; j < PathNameSize + DM_DOWN_FXD_LENGTH; j++ )
                pSource++;

            /*
            **  download type
            */
            pSource++;

            pSource += DOWNFILE_SIZE_HI_LEN;

            pSource += DOWNFILE_SIZE_LO_LEN;

        }
    }   /* end of get download font info                              */


    /*
    **  downloadable code pages.
    */
    for ( i = 0; i < TempDMSettings->NoOfAddedCPs; i++ )
    {
        prdm_ReadWordFromText( CodePageNo,
                               NO_CODE_PAGE_DIGITS,
                               pSource );

        prdm_ReadWordFromText( PathNameSize,
                               PATHNAME_SIZE_LENGTH,
                               pSource );

        for ( j = 0; j < PathNameSize; j++ )
            pSource++;

    }

    if ( TempDMSettings->MetricsPathLength )
    {
        for ( i = 0; i < TempDMSettings->MetricsPathLength; i++ )
            pSource++;
    }

    /*
    **  The first byte in DfltFontInfo is font type (resident, card
    **  etc). The constants for the types are different in the old and
    **  new styles so convert this.
    **
    **  PD00340: Convert decimal numbers to ASCCII.
    */

    switch (*pSource - '0')
    {
        case 1:
            *pSource = FT_RESIDENT + '0';
            break;

        case 2:
            *pSource = FT_DOWNLOAD + '0';
            break;

        case 3:
            *pSource = FT_ENGINE + '0';
            break;

        case 4:
            *pSource = FT_MARKER + '0';
            break;

        case 5:
            *pSource = FT_CARD + '0';
            break;

        default:
            break;
    }

    return;
}
#undef TFUNC


/****************************************************************************
 *
 * FUNCTION NAME = prde_Translate4224Forms
 *
 * DESCRIPTION   = This function deletes the 6 envelope forms that used to be
 *                 supported by the 4224s, adjusts the numbers of the
 *                 selected/connected forms, changes any user-defined
 *                 envelopes to type paper, etc.
 *
 *
 * INPUT         = PBYTE   ppSource        Pointer to new INI data
 *                 PBYTE   ppDest          Pointer to old INI data
 *                 USHORT  EntryLength     INI entry length
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID prde_Translate4224Forms( PBYTE  *ppSource,
                              PBYTE  *ppDest,
                              USHORT  EntryLength )

{
#define TFUNC "prde_Translate4224Forms"

    /*
    **  Local Variables
    */
    USHORT                i,j,k;            /* Loop controls                  */
    USHORT                NoOfForms;        /* Old number of forms            */
    USHORT                NoOfManForms;     /* Number of manual forms         */
    USHORT                NoOfEnvForms;     /* Number of env forms            */
    USHORT                TempEntryLength;  /* amount left to write           */
    USHORT                Form;             /* id number of the form          */
    USHORT                Count;            /* number of skipped forms        */
    USHORT                SourceDataSize;   /* size of source data            */
    PBYTE                 pDestHeaderStart; /* beginning of header            */
    PBYTE                 pTemp;            /* pointer                        */
    PBYTE                 pTemp2;           /* pointer                        */
    PBYTE                 pEntryLength;     /* pointer                        */
    PBYTE                 pNoOfManualForms; /* pointer                        */
    BYTE                  CountryCode[4];   /* Country code                   */
    ULONG                 DefaultForm;      /* Default form                   */

    pDestHeaderStart = *ppDest;

    /*
    **  Find the default form.
    */
    PrfQueryProfileString( HINI_USERPROFILE,                       /* CON3201 */
                           (PSZ)"PM_National",                     /* CON3201 */
                           (PSZ)"iCountry",                        /* CON3201 */
                           (PSZ)"1",                               /* CON3201 */
                           CountryCode,                            /* CON3201 */
                           3 );                                    /* CON3201 */

    if (( (CountryCode[0] == '1') &&
         (CountryCode[1] == '\0') )  ||
          !prdu_strcmpN(CountryCode,"55",3) )                      /* PD00812 */
    {
        DefaultForm = DEFAULT_PAPER_FORM_US;
    }
    else
    {
        DefaultForm = DEFAULT_PAPER_FORM_NONUS;
    }
    /*
    **  Copy the PrinterType field in the header.
    */
    prdu_memcpy( *ppDest, *ppSource, 2);

    *ppSource += 2;
    *ppDest += 2;

    /*
    **  The entry length must be adjusted for added fields and removed forms:
    **  36 bytes of new fields and 6 removed forms.
    */
    EntryLength += (36 - (6*(FORM_DATA_LENGTH+2)));
    TempEntryLength = EntryLength;

    pEntryLength = *ppDest;
    *ppSource += NO_DATA_SIZE_DIGITS;
    *ppDest   += NO_DATA_SIZE_DIGITS;

    /*
    **  Copy more of the header up to the start of the new fields.  This is 31
    **  bytes' worth.
    */
    prdu_memcpy( *ppDest, *ppSource,31);

    *ppSource += 31;
    *ppDest += 31;

    /*
    **  Write 36 zeroes into the dest buffer.
    */
    prdu_memset( *ppDest, '0',3);
    *ppDest += 3;

    prdu_memset( *ppDest, '1',1); /* set SimDup to default */
    *ppDest += 1;                 /* PD00058               */

    prdu_memset( *ppDest, '0',32);  /*PD00285              */
    *ppDest += 32;

    /*
    **  Copy the rest of the header information.
    */
    prdu_memcpy( *ppDest, *ppSource, HEADER_LENGTH-74);
    *ppDest   += (HEADER_LENGTH-74);
    *ppSource += (HEADER_LENGTH-74);

    TempEntryLength -= HEADER_LENGTH;

    /*
    ** Get the old number of forms
    */
    pTemp = pDestHeaderStart + OFF_NUMBER_OF_FORMS;
    prdm_ReadWordFromText( NoOfForms,
                           NO_FORM_CNT_DIGITS,
                           pTemp );

    /*
    **  Loop through each of the forms:
    **
    **    If it is a valid pre-defined form, copy it unchanged into the new
    **    INI.
    **
    **    If it is a user defined form, make sure that the type is paper.
    **
    **    Otherwise it's an obsolete pre-defined form, so don't copy it.
    */
    for (i = 0; i < NoOfForms ; i++)
    {
        if (i < NEW_NO_OF_4224_FORMS)
        {
            /*
            **  Copy the entry.
            */
            for (j = 0;j < FORM_DATA_LENGTH+2; j++, TempEntryLength--)
            {
                **ppDest = **ppSource;
                *ppDest   += 1;
                *ppSource += 1;
            }
        }
        else
        {
            if (i >= OLD_NO_OF_4224_FORMS)
            {
                /*
                **  It's a user-defined form so set type to paper, then copy
                **  the rest of the entry for this form.
                */
                prdu_memset( *ppDest, 'P', 1);
                *ppDest   +=1;
                *ppSource +=1;
                TempEntryLength--;

                for (j = 0;j < FORM_DATA_LENGTH+1; j++, TempEntryLength--)
                {
                    **ppDest = **ppSource;
                    *ppDest   += 1;
                    *ppSource += 1;
                }
            }
            else
            {
                /*
                **  This form is obsolete, so skip past it.
                */
                for (j = 0;j < FORM_DATA_LENGTH+2; j++)
                    *ppSource += 1;

            } /* ... if (i > OLD_#_OF_4224_FORMS) ... */

        } /* ... if (i < NEW_#_OF_4224_FORMS)  ... */

    } /* ... for (i = 0; i < NoOfForms ; i++)  ... */

    /*
    **   Now that the forms are written, write out the new number of forms,
    **   and set the selected form to 0 if it is a pre-defined
    **   envelope form.
    */
    NoOfForms = NoOfForms - 6;

    pTemp = pDestHeaderStart + OFF_NUMBER_OF_FORMS;

    prdm_WriteTextFromWord( NoOfForms,
                            NO_FORM_CNT_DIGITS,
                            pTemp );

    pTemp = pDestHeaderStart + OFF_SELECTED_FORM;
    prdm_ReadWordFromText( Form,
                           NO_FORM_CNT_DIGITS,
                           pTemp );

    /*
    **  Selected form may have to be adjusted.
    */
    if (Form >= NEW_NO_OF_4224_FORMS)
    {
        /*
        **  If it is a user-defined form, subtract 6.  If it is a pre-defined
        **  envelope, set the selected form to the default.
        */
        if (Form >= OLD_NO_OF_4224_FORMS)
           Form -= 6;
        else
           Form = (USHORT) DefaultForm;

        /*
        **  Now write out the adjusted form.
        */
        pTemp -= NO_FORM_CNT_DIGITS;
        prdm_WriteTextFromWord( Form,
                                NO_FORM_CNT_DIGITS,
                                pTemp );
    }


    /*
    **  Forms for auto sources will be copied, adjusting the form numbers for
    **  user-defined forms and setting any pre-defined envelopes to the
    **  default form.
    */
    pTemp  = *ppSource;

    for ( i = 0; i < NO_OF_AUTO_TRAYS; i++ )
    {
         prdm_ReadWordFromText( Form,
                                NO_FORM_CNT_DIGITS,
                                pTemp );

         if (Form >= NEW_NO_OF_4224_FORMS)
         {
            /*
            **  If it is a user-defined form, subtract 6.  If it is a
            **  pre-defined envelope, set the selected form to the default.
            */
             if (Form >= OLD_NO_OF_4224_FORMS)
                 Form -= 6;
             else
                 Form = (USHORT) DefaultForm;

             pTemp2 = *ppDest;
             prdm_WriteTextFromWord( Form,
                                     NO_FORM_CNT_DIGITS,
                                     pTemp2 );

             *ppDest += NO_FORM_CNT_DIGITS;
         }
         else
         {
             /*
             **  Just copy it over.
             */
             prdu_memcpy( *ppDest, *ppSource, 3);
             *ppDest += NO_FORM_CNT_DIGITS;
         }

         *ppSource += NO_FORM_CNT_DIGITS;
         TempEntryLength -= NO_FORM_CNT_DIGITS;
    }

    /*
    **  Get the number of manual paper forms, saving the pointer to it, so we
    **  can add in any user-defined manual envelope forms later.
    */
    pNoOfManualForms = *ppDest;

    prdm_ReadWordFromText( NoOfManForms,
                           NO_FORM_CNT_DIGITS,
                           pTemp );

    *ppSource   += NO_FORM_CNT_DIGITS;
    *ppDest     += NO_FORM_CNT_DIGITS;
    TempEntryLength -= NO_FORM_CNT_DIGITS;

    /*
    **  Now read in form numbers for the manual paper forms.
    */
    for ( i = 0; i < NoOfManForms; i++ )
    {
         prdm_ReadWordFromText( Form,
                                NO_FORM_CNT_DIGITS,
                                pTemp );

         if (Form >= OLD_NO_OF_4224_FORMS)
         {
            /*
            **  For user-defined forms subtract 6 (the number of pre-defined
            **  envelopes that were deleted) from the form number and write it
            **  out.
            */
             pTemp2 = *ppDest;
             Form -= 6;
             prdm_WriteTextFromWord( Form,
                                     NO_FORM_CNT_DIGITS,
                                     pTemp2 );

             *ppDest     += NO_FORM_CNT_DIGITS;
         }
         else
         {
             /*
             **  Its a pre-defined paper form, so just copy it.
             */
             prdu_memcpy( *ppDest, *ppSource, 3);
             *ppDest += NO_FORM_CNT_DIGITS;
         }

         *ppSource   += NO_FORM_CNT_DIGITS;
         TempEntryLength -= NO_FORM_CNT_DIGITS;
    }

    /*
    **  Get the number of manual envelope forms.
    */
    prdm_ReadWordFromText( NoOfEnvForms,
                           NO_FORM_CNT_DIGITS,
                           pTemp );

    *ppSource += NO_FORM_CNT_DIGITS;

    /*
    **  Now read in form numbers for the manual envelope forms.  If the
    **  envelope is user-defined, then we want to transfer it to the manual
    **  paper form list.  If it is pre-defined, then want to eliminate it
    **  totally.
    */
    Count = 0;
    for ( i = 0; i < NoOfEnvForms; i++ )
    {
         prdm_ReadWordFromText( Form,
                                NO_FORM_CNT_DIGITS,
                                pTemp );

         if (Form >= OLD_NO_OF_4224_FORMS)
         {
            /*
            **  For user-defined forms subtract 6 (the number of pre-defined
            **  envelopes that were deleted) from the form number and write it
            **  out.
            */
             pTemp2 = *ppDest;
             Form -= 6;
             prdm_WriteTextFromWord( Form,
                                     NO_FORM_CNT_DIGITS,
                                     pTemp2 );

             *ppDest += NO_FORM_CNT_DIGITS;
         }
         else
         {
             /*
             **  It's a pre-defined envelope so add one to count so we can
             **  adjust the number of manual paper forms later.
             */
             Count++;
         }

         *ppSource += NO_FORM_CNT_DIGITS;
         TempEntryLength -= NO_FORM_CNT_DIGITS;
    }

    /*
    **  Set number of manual envelope forms to 0
    */
    i = 0;
    pTemp = *ppDest;
    prdm_WriteTextFromWord( i,
                            NO_FORM_CNT_DIGITS,
                            pTemp );

    *ppDest     += NO_FORM_CNT_DIGITS;
    TempEntryLength -= NO_FORM_CNT_DIGITS;

    /*
    **  Now adjust the number of manual paper forms and the size of the
    **  source data.
    */
    NoOfManForms += (NoOfEnvForms - Count);
    prdm_WriteTextFromWord( NoOfManForms,
                            NO_FORM_CNT_DIGITS,
                            pNoOfManualForms);

    pTemp = pDestHeaderStart + OFF_SOURCE_DATA_SIZE;
    prdm_ReadWordFromText( SourceDataSize,
                           NO_DATA_SIZE_DIGITS,
                           pTemp );

    SourceDataSize = SourceDataSize - (Count * NO_FORM_CNT_DIGITS);

    pTemp = pDestHeaderStart + OFF_SOURCE_DATA_SIZE;
    prdm_WriteTextFromWord( SourceDataSize,
                            NO_DATA_SIZE_DIGITS,
                            pTemp);

    /*
    **  Now write the adjusted EntryLength out there.
    */
    EntryLength -= Count * NO_FORM_CNT_DIGITS;
    prdm_WriteTextFromWord( EntryLength,
                            NO_DATA_SIZE_DIGITS,
                            pEntryLength );

    /*
    **  And copy the rest of the stuff.
    */
    prdu_memcpy( *ppDest, *ppSource, TempEntryLength);

    *ppSource += TempEntryLength;
    *ppDest += TempEntryLength;

    return;
}
#undef TFUNC
