mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1016 lines
30 KiB
1016 lines
30 KiB
/******************************* MODULE HEADER ******************************
|
|
* fontfile.c
|
|
* Functions associated with generating the combined font file
|
|
* used with NT printer drivers. This handles the mechanics of
|
|
* creating/adding/deleting data in the file. No attempt is made
|
|
* to understand the contents of the file. That is left to
|
|
* individual drivers.
|
|
*
|
|
* Copyright (C) 1992 - 1993 Microsoft Corportation.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
|
|
#include <stddef.h>
|
|
#include <windows.h>
|
|
#include <winddi.h>
|
|
#include "fontfile.h" /* File layout details */
|
|
#include "fontgen.h" /* Globally visible components */
|
|
#include "libproto.h" /* bWrite() proto */
|
|
|
|
|
|
|
|
/*
|
|
* Local functions.
|
|
*/
|
|
|
|
|
|
BOOL bGetFileHDR( HANDLE, FF_HEADER * );
|
|
BOOL bGetRecHDR( HANDLE, FF_REC_HEADER *, DWORD );
|
|
BOOL bFixInit( HANDLE ); /* Initialise new Fixed file */
|
|
void vFIClean( FID * ); /* Clean up any mess */
|
|
BOOL bDelList( FID *, int * ); /* Delete fonts in current set */
|
|
BOOL bAddFList( FID *, FONTLIST * ); /* Add new fonts to existing */
|
|
|
|
|
|
|
|
|
|
/******************************* Function Header ****************************
|
|
* pFIOpen()
|
|
* Function to initialize the internal operations for the font installer
|
|
* single font file building operations. The value returned is passed
|
|
* to other functions here, giving them access to the data required
|
|
* to complete their tasks.
|
|
*
|
|
* RETURNS:
|
|
* Pointer to private data, cast as a (void *); 0 on error.
|
|
*
|
|
* HISTORY:
|
|
* 09:49 on Mon 24 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* Starting work on it.
|
|
*
|
|
****************************************************************************/
|
|
|
|
FID *
|
|
pFIOpen( pwstrDataFile, hHeap )
|
|
PWSTR pwstrDataFile; /* Driver's data file name */
|
|
HANDLE hHeap; /* Heap access */
|
|
{
|
|
|
|
FID *pFID; /* For our convenience */
|
|
PWSTR pwstr; /* For file name manipulation */
|
|
|
|
int iPtOff; /* Location of . in file name */
|
|
int iSize; /* Determine the size of things */
|
|
|
|
|
|
/*
|
|
* Firstly allocate a FID structure from the heap. We cannot use
|
|
* a stack version as it needs to be persistent.
|
|
*/
|
|
|
|
if( !(pFID = (FID *)HeapAlloc( hHeap, 0, sizeof( FID ) )) )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!pvFIOpen: HeapAlloc( FID ) fails!\n" );
|
|
#endif
|
|
|
|
return 0; /* Bad news */
|
|
}
|
|
|
|
memset( pFID, 0, sizeof( FID ) ); /* Easier clean up */
|
|
|
|
pFID->hHeap = hHeap; /* Keep it for later! */
|
|
pFID->dwID = FID_ID; /* Make sure we get our own back! */
|
|
|
|
/*
|
|
* We want to generate some file names, so determine the
|
|
* length of the input name, and allocate that much storage
|
|
* for it. We do not know what format the name is, so allow
|
|
* room at the end to add ".fi_": 5 WCHARs including the null.
|
|
*/
|
|
|
|
iSize = (wcslen( pwstrDataFile ) + 5) * sizeof( WCHAR );
|
|
|
|
if( !(pFID->pwstrCurName = (PWSTR)HeapAlloc( hHeap, 0, iSize )) ||
|
|
!(pFID->pwstrFixName = (PWSTR)HeapAlloc( hHeap, 0, iSize )) ||
|
|
!(pFID->pwstrVarName = (PWSTR)HeapAlloc( hHeap, 0, iSize )) )
|
|
{
|
|
|
|
#if DBG
|
|
DbgPrint( "Print!pvFIOpen: HeapAlloc( pwstrDataFile ) fails!\n" );
|
|
#endif
|
|
vFIClean( pFID );
|
|
|
|
return 0;
|
|
}
|
|
pwstr = pFID->pwstrCurName; /* For stuffing around */
|
|
|
|
wcscpy( pFID->pwstrCurName, pwstrDataFile ); /* Working copies */
|
|
wcscpy( pFID->pwstrFixName, pwstrDataFile );
|
|
wcscpy( pFID->pwstrVarName, pwstrDataFile );
|
|
|
|
|
|
/* Scan from RHS looking for '.': PRESUME THERE IS ONE! */
|
|
iPtOff = wcslen( pwstr );
|
|
|
|
while( --iPtOff > 0 )
|
|
{
|
|
if( *(pwstr + iPtOff) == (WCHAR)'.' )
|
|
break;
|
|
}
|
|
|
|
if( iPtOff <= 0 )
|
|
{
|
|
iPtOff = wcslen( pwstr ); /* Presume none! */
|
|
*(pwstr + iPtOff) = L'.';
|
|
}
|
|
++iPtOff; /* Skip the period */
|
|
|
|
|
|
|
|
/* Generate all 3 names & open the existing file */
|
|
wcscpy( pFID->pwstrCurName + iPtOff, FILE_FONTS );
|
|
wcscpy( pFID->pwstrFixName + iPtOff, TFILE_FIX );
|
|
wcscpy( pFID->pwstrVarName + iPtOff, TFILE_VAR );
|
|
|
|
|
|
pFID->hCurFile = CreateFileW( pFID->pwstrCurName, GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL, OPEN_EXISTING, 0, 0 );
|
|
|
|
/*
|
|
* Repeat for the two new files: note that we want to create these,
|
|
* truncate any existing file, and allow no other access to them
|
|
* while we are manipulating them. They should be invisible.
|
|
*/
|
|
|
|
|
|
pFID->hFixFile = CreateFileW( pFID->pwstrFixName,
|
|
GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
|
pFID->hCurFile );
|
|
|
|
if( pFID->hFixFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
/* Bad news */
|
|
#if DBG
|
|
DbgPrint( "Print!bFIOpen: Fixed file initialisation failure\n" );
|
|
#endif
|
|
|
|
|
|
vFIClean( pFID );
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
pFID->hVarFile = CreateFileW( pFID->pwstrVarName,
|
|
GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
|
pFID->hCurFile );
|
|
|
|
if( pFID->hVarFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!bFIOpen: Var file creation failure\n" );
|
|
#endif
|
|
|
|
|
|
vFIClean( pFID );
|
|
|
|
return 0;
|
|
}
|
|
|
|
return pFID;
|
|
}
|
|
|
|
/****************************** Function Header *****************************
|
|
* bFIClose
|
|
* Close up operations on the font installer file. This involves
|
|
* amalgamating the Fix and Var files, updating the overall header
|
|
* and renaming the file after deleting the old one.
|
|
*
|
|
* RETURNS:
|
|
* TRUE/FALSE - FALSE if any operation fails.
|
|
*
|
|
* HISTORY:
|
|
* 15:01 on Mon 24 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* Gotta start somewhere
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL
|
|
bFIClose( pFID, bUpdate )
|
|
FID *pFID; /* The file collection to close */
|
|
BOOL bUpdate; /* True to make new file THE file */
|
|
{
|
|
|
|
long lSize; /* Bytes copied from variable file */
|
|
|
|
|
|
FF_HEADER ffh; /* The overall file header */
|
|
|
|
|
|
|
|
if( pFID->dwID != FID_ID )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!bFIClose(): invalid pFID" );
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* If bUpdate, then reorganise the files: the existing file is
|
|
* removed, the Var file is appended to the Fix file, and that
|
|
* composite file is made the new "existing" file.
|
|
*/
|
|
|
|
|
|
if( !bUpdate )
|
|
{
|
|
/* No updating is to be done */
|
|
vFIClean( pFID ); /* Does all the dirty work */
|
|
|
|
return TRUE; /* By definition */
|
|
}
|
|
|
|
/*
|
|
* Update is ON! First read the header from the fixed file, then
|
|
* fill in the missing details. This amounts to the location of
|
|
* the start of the variable length data in the file.
|
|
*/
|
|
|
|
if( !bGetFileHDR( pFID->hFixFile, &ffh ) )
|
|
{
|
|
vFIClean( pFID );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Need to know the size of the fixed file to put in the header.
|
|
*/
|
|
|
|
lSize = (long)SetFilePointer( pFID->hFixFile, 0, NULL, FILE_END );
|
|
|
|
lSize = (lSize + 3) & ~0x3; /* DWORD multiple */
|
|
|
|
ffh.ulVarData = lSize;
|
|
|
|
SetFilePointer( pFID->hFixFile, lSize, NULL, FILE_BEGIN );
|
|
SetFilePointer( pFID->hVarFile, 0, NULL, FILE_BEGIN );
|
|
|
|
ffh.ulVarSize = lSize = lFICopy( pFID->hFixFile, pFID->hVarFile );
|
|
if( lSize < 0 )
|
|
{
|
|
/* Some sort of error */
|
|
vFIClean( pFID );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if( lSize == 0 )
|
|
ffh.ulVarData = 0; /* NONE! */
|
|
|
|
/*
|
|
* Now write the header back out.
|
|
*/
|
|
|
|
SetFilePointer( pFID->hFixFile, 0, NULL, FILE_BEGIN );
|
|
if( !bWrite( pFID->hFixFile, &ffh, sizeof( ffh ) ) )
|
|
{
|
|
/* Too bad: throw it all away. */
|
|
vFIClean( pFID );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* No longer need the file handles, so close them, and set
|
|
* the values to illegal so that we will not try to free them later.
|
|
* We can also delete the variable part of the file, since that
|
|
* is now appended to the end of the fixed file.
|
|
*/
|
|
|
|
CloseHandle( pFID->hFixFile ); /* No longer needed */
|
|
pFID->hFixFile = INVALID_HANDLE_VALUE; /* Won't be cleaned up */
|
|
|
|
CloseHandle( pFID->hVarFile ); /* No longer need this file */
|
|
pFID->hVarFile = INVALID_HANDLE_VALUE; /* Won't be cleaned up */
|
|
|
|
|
|
DeleteFileW( pFID->pwstrVarName );
|
|
|
|
|
|
/*
|
|
* Now delete the existing file and rename the Fix file to the
|
|
* proper name!
|
|
*/
|
|
|
|
|
|
if( pFID->hCurFile != INVALID_HANDLE_VALUE )
|
|
{
|
|
/* Have a current file, so delete it, close our handle */
|
|
CloseHandle( pFID->hCurFile );
|
|
pFID->hCurFile = INVALID_HANDLE_VALUE; /* Is now */
|
|
|
|
if( !DeleteFileW( pFID->pwstrCurName ) )
|
|
{
|
|
vFIClean( pFID );
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* RENAME */
|
|
if( !MoveFileW( pFID->pwstrFixName, pFID->pwstrCurName ) )
|
|
{
|
|
/* BAD NEWS: we have lost the lot! */
|
|
|
|
vFIClean( pFID );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Clean up whatever is left.
|
|
*/
|
|
|
|
vFIClean( pFID );
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************** Function Header ***************************
|
|
* bFIUpdate
|
|
* Called to integrate changes to the font file. Caller may delete
|
|
* existing fonts and/or add new ones. The deleted fonts are
|
|
* passed as an array of integers, each being an index into the
|
|
* existing fonts. The first is a count of the number of
|
|
* index values following; then comes the zero based index value.
|
|
* New fonts are passed as a linked list of type FONTLIST.
|
|
* NOTE: The master font file is NOT updated by this call.
|
|
*
|
|
* RETURNS:
|
|
* TRUE/FALSE; FALSE leaves no permanent changes.
|
|
*
|
|
* HISOTRY:
|
|
* 12:59 on Tue 25 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* First version.
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL
|
|
bFIUpdate( pFID, piDel, pFList )
|
|
FID *pFID; /* Access to our data */
|
|
int *piDel; /* Array of fonts to delete */
|
|
FONTLIST *pFList; /* Fonts to add */
|
|
{
|
|
|
|
/*
|
|
* Not much to do! First step is to copy the fixed part of the
|
|
* file to our new fixed file, deleting fonts as we go. This also
|
|
* splits off the variable portion. Then add whatever new fonts are
|
|
* to be added. We do not amalgamate the file: that is done at
|
|
* bFIClose() time, giving the caller the chance to abort the whole
|
|
* operation.
|
|
*/
|
|
|
|
if( pFID->dwID != FID_ID )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!bFIUpdate: pFID is invalid" );
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if( !bDelList( pFID, piDel ) )
|
|
return FALSE;
|
|
|
|
if( !bAddFList( pFID, pFList ) )
|
|
return FALSE;
|
|
|
|
return TRUE; /* Made it AOK */
|
|
}
|
|
|
|
|
|
/****************************** Function Header ******************************
|
|
* bDelList
|
|
* Delete the nominated fonts from the master font file. DOES NOT UPDATE
|
|
* THE MASTER FILE. The fonts are nominated by as an array of ints,
|
|
* the first of which is a count of the number of ints following.
|
|
* These values are zero based and represent the number of the font
|
|
* in sequence in the file.
|
|
*
|
|
* RETURNS:
|
|
* TRUE/FALSE
|
|
*
|
|
* HISTORY:
|
|
* 13:02 on Tue 25 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* First version to do something.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL
|
|
bDelList( pFID, piDel )
|
|
FID *pFID; /* Access to our stuff */
|
|
int *piDel; /* A -1 terminated array of font indices to delete */
|
|
{
|
|
|
|
|
|
ULONG ulRec; /* Loop through the records */
|
|
DWORD dwHdrPosn; /* Position within the file */
|
|
DWORD dwFixPosn; /* Write position in fixed file */
|
|
DWORD dwVarPosn; /* Absolute position within variable part */
|
|
int iDelLeft; /* Number of deletion choices left */
|
|
int iSkip; /* Number we have dropped */
|
|
|
|
BOOL bDelete; /* True if this font to be deleted */
|
|
|
|
|
|
FF_HEADER ffh; /* Contains sizes! */
|
|
FF_REC_HEADER ffrh;
|
|
|
|
/*
|
|
* Do we have any to delete?
|
|
*/
|
|
|
|
|
|
if( pFID->hCurFile == INVALID_HANDLE_VALUE )
|
|
{
|
|
/* NO existing file, so create a new empty one! */
|
|
|
|
return bFixInit( pFID->hFixFile );
|
|
}
|
|
|
|
if( !bGetFileHDR( pFID->hCurFile, &ffh ) )
|
|
return FALSE;
|
|
|
|
if( piDel == NULL || *piDel <= 0 )
|
|
{
|
|
/* Just split the master file into two: fixed and variable parts */
|
|
|
|
LONG lSize;
|
|
|
|
|
|
SetFilePointer( pFID->hCurFile, 0, NULL, FILE_BEGIN );
|
|
|
|
lSize = sizeof( ffh ) + ffh.ulFixSize;
|
|
|
|
if( lFInCopy( pFID->hFixFile, pFID->hCurFile, lSize ) != lSize ||
|
|
lFInCopy( pFID->hVarFile, pFID->hCurFile, ffh.ulVarSize ) !=
|
|
(long)ffh.ulVarSize )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!bDelList: file split fails\n" );
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Another speed up case is the other version: deleting all fonts!
|
|
*/
|
|
|
|
if( *piDel >= (int)ffh.ulRecCount )
|
|
{
|
|
/* Simply create an empty file */
|
|
|
|
return bFixInit( pFID->hFixFile );
|
|
}
|
|
|
|
/*
|
|
* Now determine which fonts to delete. We do this the easy (but
|
|
* slower) way, namely to process each record individually. We
|
|
* read the header, determine whether to delete, and if not, then
|
|
* copy the relevant portions to the output files.
|
|
*/
|
|
|
|
dwHdrPosn = ffh.ulFixData; /* Initial location */
|
|
dwFixPosn = ffh.ulFixData; /* Writing location in fixed file */
|
|
dwVarPosn = ffh.ulVarData; /* Starting location in variable */
|
|
iSkip = 0; /* Count number we drop off */
|
|
iDelLeft = *piDel; /* Number to delete */
|
|
ffh.ulFixSize = 0; /* Count it as we copy */
|
|
|
|
for( ulRec = 0; ulRec < ffh.ulRecCount; ++ulRec )
|
|
{
|
|
|
|
/* First read the header to read the record size */
|
|
|
|
if( !bGetRecHDR( pFID->hCurFile, &ffrh, dwHdrPosn ) )
|
|
return FALSE; /* SHOULD NOT HAPPEN */
|
|
|
|
if( ffrh.ulNextOff == 0 )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!bDelList: unexpected EOF record at #%ld\n",
|
|
ulRec );
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
/*
|
|
* Is this on the delete list??
|
|
*/
|
|
|
|
bDelete = FALSE; /* Assume not */
|
|
|
|
if( iDelLeft > 0 )
|
|
{
|
|
/* Scan the list, looking for this index */
|
|
int iI;
|
|
|
|
for( iI = 1; !bDelete && iI <= *piDel; ++iI )
|
|
{
|
|
if( *(piDel + iI) == (int)ulRec )
|
|
{
|
|
bDelete = TRUE;
|
|
--iDelLeft;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( bDelete )
|
|
{
|
|
/* Skip this one, so adjust offsets & counts. */
|
|
iSkip++; /* Reduce count at the end. */
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* First step is to copy the variable part. This is done
|
|
* first as we need to update the data position within the
|
|
* header record for the fixed part. So copy now to find
|
|
* out where it is being placed.
|
|
*/
|
|
|
|
dwVarPosn = ffh.ulVarData + ffrh.ulVarOff; /* Current file posn */
|
|
|
|
if( ffrh.ulVarSize )
|
|
{
|
|
/*
|
|
* Data exists, so set file pointers. There are two to
|
|
* set. One is to position the variable data at the dword
|
|
* aligned end of the variable file, the other is to
|
|
* set the position of the current file pointer to the
|
|
* correct location in that file.
|
|
*/
|
|
|
|
/* First the new variable file */
|
|
|
|
ffrh.ulVarOff = (GetFileSize( pFID->hVarFile, NULL ) +3) & ~0x3;
|
|
SetFilePointer( pFID->hVarFile, ffrh.ulVarOff, NULL,
|
|
FILE_BEGIN );
|
|
|
|
/* The current file's variable data */
|
|
|
|
SetFilePointer( pFID->hCurFile, dwVarPosn, NULL, FILE_BEGIN );
|
|
|
|
if( lFInCopy( pFID->hVarFile, pFID->hCurFile, ffrh.ulVarSize )
|
|
!= (long)ffrh.ulVarSize )
|
|
{
|
|
#if DBG
|
|
DbgPrint(
|
|
"Print!bDelList: Write of variable data fails, rec #%ld\n",
|
|
ulRec );
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Set the fixed file pointer. First time this will skip
|
|
* the file header we write out at the end. Second and later
|
|
* times, it will ensure DWORD alignment of the header.
|
|
*/
|
|
|
|
|
|
SetFilePointer( pFID->hCurFile, dwHdrPosn + sizeof( ffrh),
|
|
NULL, FILE_BEGIN );
|
|
SetFilePointer( pFID->hFixFile, dwFixPosn, NULL, FILE_BEGIN );
|
|
|
|
if( !bWrite( pFID->hFixFile, &ffrh, sizeof( ffrh ) ) )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!bDelList: bWrite of new header, rec %ld\n",
|
|
ulRec );
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* And also the actual data part! */
|
|
|
|
if( lFInCopy( pFID->hFixFile, pFID->hCurFile, ffrh.ulSize ) !=
|
|
(long)ffrh.ulSize )
|
|
{
|
|
#if DBG
|
|
DbgPrint(
|
|
"Print!bDelList: Can't copy FIX part of file at rec #%ld\n",
|
|
ulRec );
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
dwFixPosn += ffrh.ulNextOff; /* Next location */
|
|
ffh.ulFixSize += sizeof( ffrh ) + ffrh.ulSize;
|
|
|
|
}
|
|
dwHdrPosn += ffrh.ulNextOff;
|
|
}
|
|
|
|
/*
|
|
* Need to write the trailing header to our file. This contains
|
|
* a zero size, so that is really all that is important.
|
|
*/
|
|
|
|
ffrh.ulNextOff = 0;
|
|
|
|
if( !bWrite( pFID->hFixFile, &ffrh, sizeof( ffrh ) ) )
|
|
return FALSE;
|
|
|
|
ffh.ulRecCount -= iSkip; /* The number we dropped! */
|
|
|
|
/*
|
|
* Rewrite the header record for the adding code.
|
|
*/
|
|
|
|
SetFilePointer( pFID->hFixFile, 0, NULL, FILE_BEGIN );
|
|
|
|
return bWrite( pFID->hFixFile, &ffh, sizeof( ffh ) );
|
|
}
|
|
|
|
/****************************** Function Header ******************************
|
|
* bAddFList
|
|
* Add a list of new fonts to an existing font file. This is
|
|
* called to add the data to our existing file. File creation or
|
|
* shrinking is done elsewhere.
|
|
*
|
|
* RETURNS:
|
|
* Number of bytes written to the file; -1 for error.
|
|
*
|
|
* HISTORY:
|
|
* 14:20 on Sat 22 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* Started working on it.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
BOOL
|
|
bAddFList( pFID, pFList )
|
|
FID *pFID; /* Font installation data */
|
|
FONTLIST *pFList; /* The fonts to be added */
|
|
{
|
|
|
|
DWORD dwLoc; /* File location of interest */
|
|
DWORD dwVarLoc; /* Location in the variable data part */
|
|
int iSize; /* Number of bytes written by user */
|
|
int iVarSize; /* Size of variable length portion */
|
|
|
|
|
|
FF_HEADER ffh; /* The overall file header */
|
|
FF_REC_HEADER ffrh; /* Per record header */
|
|
|
|
|
|
if( pFList == NULL )
|
|
return TRUE; /* No data, no processing! */
|
|
|
|
/*
|
|
* First step is to step through the file, down the chain of
|
|
* records until we reach the end. We append the data there: the
|
|
* data consists of a record header plus whatever data the user
|
|
* writes and tells us about. We also allow the user the option
|
|
* of adding data to variable length part of the file.
|
|
*/
|
|
|
|
if( !bGetFileHDR( pFID->hFixFile, &ffh ) )
|
|
return FALSE;
|
|
|
|
|
|
/* Can now read the file header - it WILL exist! */
|
|
dwLoc = ffh.ulFixData;
|
|
|
|
while( bGetRecHDR( pFID->hFixFile, &ffrh, dwLoc ) && ffrh.ulNextOff )
|
|
dwLoc += ffrh.ulNextOff; /* Next location */
|
|
|
|
/*
|
|
* Can now process the user's list of stuff to write out.
|
|
* The writing out is done by user supplied functions - they
|
|
* tell us how much was written, we simply update the red tape.
|
|
*/
|
|
|
|
dwVarLoc = SetFilePointer( pFID->hVarFile, 0, NULL, FILE_END );
|
|
|
|
for( ; pFList; pFList = (FONTLIST *)pFList->pFLNext )
|
|
{
|
|
|
|
/* First write out the header array type data */
|
|
|
|
SetFilePointer( pFID->hFixFile, dwLoc + sizeof( FF_REC_HEADER ),
|
|
NULL, FILE_BEGIN );
|
|
|
|
iSize = iFIWriteFix( pFID->hFixFile, pFID->hHeap, pFList->pvFixData );
|
|
|
|
if( iSize < 0 )
|
|
return FALSE; /* Bad news */
|
|
|
|
ffrh.ulSize = (ULONG)iSize; /* For the record */
|
|
ffh.ulRecCount++; /* One more! */
|
|
|
|
/*
|
|
* Position of next entry: make it DWORD aligned so that we
|
|
* can memory map the file.
|
|
*/
|
|
ffrh.ulNextOff = sizeof( ffrh ) + (iSize + 3) & ~0x3;
|
|
ffh.ulFixSize += ffrh.ulNextOff;
|
|
|
|
/*
|
|
* The variable length part of the data. Much the same as
|
|
* above, simply a different function to call.
|
|
*/
|
|
|
|
SetFilePointer( pFID->hVarFile, dwVarLoc, NULL, FILE_BEGIN );
|
|
|
|
iVarSize = iFIWriteVar( pFID->hVarFile, pFID->hHeap, pFList->pvVarData );
|
|
|
|
if( iVarSize < 0 )
|
|
return FALSE; /* Not good */
|
|
|
|
ffrh.ulVarSize = (ULONG)iVarSize;
|
|
if( iVarSize > 0 )
|
|
{
|
|
/* A zero return means no data - quite legitimate */
|
|
|
|
ffrh.ulVarOff = dwVarLoc;
|
|
dwVarLoc += (iVarSize + 3) & ~0x3;
|
|
}
|
|
else
|
|
ffrh.ulVarOff = 0; /* No data for this one. */
|
|
|
|
|
|
/* Finally, write out the header for the array data */
|
|
|
|
SetFilePointer( pFID->hFixFile, dwLoc, NULL, FILE_BEGIN );
|
|
|
|
if( !bWrite( pFID->hFixFile, &ffrh, sizeof( FF_REC_HEADER ) ) )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!bWrite of FF_REC_HEADER fails\n" );
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
/* Set the file pointer to the location of the next header */
|
|
dwLoc += ffrh.ulNextOff;
|
|
}
|
|
|
|
/*
|
|
* Last step: write out the final header, which has ulSize set to
|
|
* zero to indicate that it is the terminating record.
|
|
*/
|
|
|
|
ffh.ulVarSize = GetFileSize( pFID->hVarFile, NULL );
|
|
|
|
SetFilePointer( pFID->hFixFile, dwLoc, NULL, FILE_BEGIN );
|
|
|
|
ffrh.ulNextOff = 0; /* No more in this chain! */
|
|
|
|
if( !bWrite( pFID->hFixFile, &ffrh, sizeof( ffrh ) ) )
|
|
return FALSE;
|
|
|
|
/*
|
|
* Finally, update the master header.
|
|
*/
|
|
|
|
SetFilePointer( pFID->hFixFile, 0, NULL, FILE_BEGIN );
|
|
if( !bWrite( pFID->hFixFile, &ffh, sizeof( ffh ) ) )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************** Function Header **************************
|
|
* bGetFileHDR
|
|
* Read in the FF_HEADER for the font installer file. This is
|
|
* always located at the beginning of the file! Returns TRUE
|
|
* if the read was AOK, and the structure is verified.
|
|
*
|
|
* RETURNS:
|
|
* TRUE/FALSE
|
|
*
|
|
* HISTORY:
|
|
* 15:40 on Sat 22 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* First incarnation.
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL
|
|
bGetFileHDR( hFile, pffh )
|
|
HANDLE hFile; /* The file */
|
|
FF_HEADER *pffh; /* The header to fill in */
|
|
{
|
|
/*
|
|
* Not hard: seek to the beginning of the file, then read in the
|
|
* structure there, and VERIFY it!
|
|
*/
|
|
|
|
DWORD dwIn; /* Bytes read */
|
|
|
|
|
|
SetFilePointer( hFile, 0, NULL, FILE_BEGIN ); /* Start */
|
|
|
|
if( !ReadFile( hFile, pffh, sizeof( FF_HEADER ), &dwIn, NULL ) ||
|
|
dwIn != sizeof( FF_HEADER ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return pffh->ulID == FF_ID;
|
|
}
|
|
|
|
|
|
/******************************* Function Header ****************************
|
|
* bGetRecHDR
|
|
* Read the FF_REC_HEADER structure at the given location with the
|
|
* file, and return TRUE if read successfully. This means the
|
|
* read was AOK, and the structure is acceptable.
|
|
*
|
|
* RETURNS:
|
|
* TRUE/FALSE
|
|
*
|
|
* HISTORY:
|
|
* 15:38 on Sat 22 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* Starting out.
|
|
*
|
|
****************************************************************************/
|
|
|
|
BOOL
|
|
bGetRecHDR( hFile, pffrh, dwLoc )
|
|
HANDLE hFile; /* File to read from */
|
|
FF_REC_HEADER *pffrh; /* Structure to fill in */
|
|
DWORD dwLoc; /* Location of data in file: absolute */
|
|
{
|
|
/*
|
|
* Seek to the specified location, and read in the data there!
|
|
* Perform consistency checks as above in bGetFileHDR.
|
|
*/
|
|
|
|
DWORD dwIn; /* Bytes read */
|
|
|
|
|
|
SetFilePointer( hFile, dwLoc, NULL, FILE_BEGIN );
|
|
|
|
if( !ReadFile( hFile, pffrh, sizeof( FF_REC_HEADER ), &dwIn, NULL ) ||
|
|
dwIn != sizeof( FF_REC_HEADER ) )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return pffrh->ulRID == FR_ID;
|
|
}
|
|
|
|
|
|
/**************************** Function Header ******************************
|
|
* bFixInit
|
|
* Writes a no information header into the file. This means that
|
|
* other functions can proceed on the basis that the file contains
|
|
* valid structures and links.
|
|
*
|
|
* RETURNS:
|
|
* TRUE/FALSE; FALSE on failure.
|
|
*
|
|
* HISTORY:
|
|
* 13:39 on Mon 24 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* Initial
|
|
*
|
|
***************************************************************************/
|
|
|
|
BOOL
|
|
bFixInit( hFile )
|
|
HANDLE hFile;
|
|
{
|
|
/*
|
|
* As a minimum, the file needs a FF_HEADER and a FF_REC_HEADER
|
|
* structure. The first contains an offset to the second, and
|
|
* no variable length data start location. The latter contains
|
|
* a zero size field, indicating no more data.
|
|
*/
|
|
|
|
FF_HEADER ffh; /* Overall file header */
|
|
FF_REC_HEADER ffrh; /* Individual record header */
|
|
|
|
/*
|
|
* Initialise the FF_HEADER before writing it out.
|
|
*/
|
|
|
|
|
|
ffh.ulID = FF_ID;
|
|
ffh.ulVersion = FF_VERSION;
|
|
ffh.ulFixData = sizeof( ffh ); /* Follows us directly */
|
|
ffh.ulFixSize = sizeof( ffrh ); /* Bytes in fixed area */
|
|
ffh.ulRecCount = 0; /* No records yet! */
|
|
ffh.ulVarData = 0; /* None - YET! */
|
|
ffh.ulVarSize = 0;
|
|
|
|
|
|
ffrh.ulRID = FR_ID;
|
|
ffrh.ulSize = 0;
|
|
ffrh.ulNextOff = 0; /* EOF for fixed part of file */
|
|
ffrh.ulVarOff = 0;
|
|
ffrh.ulVarSize = 0;
|
|
|
|
if( !bWrite( hFile, &ffh, sizeof( ffh )) ||
|
|
!bWrite( hFile, &ffrh, sizeof( ffrh )) )
|
|
{
|
|
#if DBG
|
|
DbgPrint( "Print!bFixInit fails\n" );
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**************************** Function Header ******************************
|
|
* vFIClean
|
|
* The clean up the mess during bail out function. Removes the
|
|
* temporary files, frees heap storage and whatever else is
|
|
* required.
|
|
*
|
|
* RETURNS:
|
|
* Zilch
|
|
*
|
|
* HISOTRY:
|
|
* 13:25 on Mon 24 Feb 1992 -by- Lindsay Harris [lindsayh]
|
|
* Start on it - it probably will grow.
|
|
*
|
|
***************************************************************************/
|
|
|
|
void
|
|
vFIClean( pFID )
|
|
FID *pFID;
|
|
{
|
|
/*
|
|
* Need to be slightly careful about what we do. In particular, NO
|
|
* bad memory accesses.
|
|
*/
|
|
|
|
if( pFID->dwID != FID_ID )
|
|
return;
|
|
|
|
/*
|
|
* Free any temporary files we may have created. Note that we
|
|
* must close the files before we can remove. Silly idea that is.
|
|
*/
|
|
|
|
|
|
if( pFID->hCurFile != INVALID_HANDLE_VALUE )
|
|
CloseHandle( pFID->hCurFile );
|
|
|
|
if( pFID->hFixFile != INVALID_HANDLE_VALUE )
|
|
CloseHandle( pFID->hFixFile );
|
|
|
|
if( pFID->hVarFile != INVALID_HANDLE_VALUE )
|
|
CloseHandle( pFID->hVarFile );
|
|
|
|
if( pFID->pwstrFixName )
|
|
{
|
|
DeleteFileW( pFID->pwstrFixName ); /* Ignore failure */
|
|
|
|
HeapFree( pFID->hHeap, 0, (LPSTR)pFID->pwstrFixName );
|
|
pFID->pwstrFixName = 0;
|
|
}
|
|
|
|
if( pFID->pwstrVarName )
|
|
{
|
|
DeleteFileW( pFID->pwstrVarName );
|
|
|
|
HeapFree( pFID->hHeap, 0, (LPSTR)pFID->pwstrVarName );
|
|
pFID->pwstrFixName = 0;
|
|
}
|
|
|
|
if( pFID->pwstrCurName )
|
|
{
|
|
HeapFree( pFID->hHeap, 0, (LPSTR)pFID->pwstrCurName );
|
|
pFID->pwstrCurName = 0;
|
|
}
|
|
|
|
|
|
pFID->dwID = (DWORD)~FID_ID; /* Invalid in case mem reused */
|
|
|
|
HeapFree( pFID->hHeap, 0, (LPSTR)pFID );
|
|
|
|
return;
|
|
}
|