Leaked source code of windows server 2003
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.
 
 
 
 
 
 

4255 lines
120 KiB

/*++
Copyright (c) 1996-1997 Microsoft Corporation
Module Name:
ppdparse.c
Abstract:
Parser for converting PPD file from ASCII text to binary data
Environment:
PostScript driver, PPD parser
Revision History:
12/03/96 -davidx-
Check binary file date against all source printer description files.
09/30/96 -davidx-
Cleaner handling of ManualFeed and AutoSelect feature.
09/17/96 -davidx-
Add link field to order dependency structure.
08/22/96 -davidx-
New binary data format for NT 5.0.
08/20/96 -davidx-
Common coding style for NT 5.0 drivers.
03/26/96 -davidx-
Created it.
--*/
#include "lib.h"
#include "ppd.h"
#include "ppdparse.h"
#include "ppdrsrc.h"
//
// Round up n to a multiple of m
//
#define ROUND_UP_MULTIPLE(n, m) ((((n) + (m) - 1) / (m)) * (m))
//
// Round up n to a multiple of sizeof(DWORD) = 4
//
#define DWORD_ALIGN(n) (((n) + 3) & ~3)
//
// Raise an exception to cause VPackBinaryData to fail
//
#define PACK_BINARY_DATA_EXCEPTION() RaiseException(0xC0000000, 0, 0, NULL);
//
// Display a semantic error message
//
#define SEMANTIC_ERROR(arg) { TERSE(arg); pParserData->bErrorFlag = TRUE; }
//
// Data structure to store meta-information about a printer feature
// Note that the default order dependency value is relative to MAX_ORDER_VALUE.
// Explicitly specified order value must be less than MAX_ORDER_VALUE.
//
// We assume all printer-sticky features have higher priority than
// all doc-sticky features. The priority values for printer-sticky
// feature must be >= PRNPROP_BASE_PRIORITY.
//
#define MAX_ORDER_VALUE 0x7fffffff
#define PRNPROP_BASE_PRIORITY 0x10000
typedef struct _FEATUREDATA {
DWORD dwFeatureID; // predefined feature ID
DWORD dwOptionSize; // size of the associated option structure
DWORD dwPriority; // feature priority
DWORD dwFlags; // feature flags
} FEATUREDATA, *PFEATUREDATA;
//
// Special code page value used internally in this file.
// Make sure they don't conflict with standard code page values.
//
#define CP_ERROR 0xffffffff
#define CP_UNICODE 0xfffffffe
PFEATUREDATA
PGetFeatureData(
DWORD dwFeatureID
)
/*++
Routine Description:
Return meta-information about the requested feature
Arguments:
dwFeatureID - Specifies what feature the caller is interested in
Return Value:
Pointer to a FEATUREDATA structure corresponding to the request feature
--*/
{
static FEATUREDATA FeatureData[] =
{
{ GID_RESOLUTION, sizeof(RESOLUTION), 10, 0},
{ GID_PAGESIZE, sizeof(PAGESIZE), 50, 0},
{ GID_PAGEREGION, sizeof(OPTION), 40, FEATURE_FLAG_NOUI},
{ GID_DUPLEX, sizeof(DUPLEX), 20, 0},
{ GID_INPUTSLOT, sizeof(INPUTSLOT), 30, 0},
{ GID_MEDIATYPE, sizeof(MEDIATYPE), 10, 0},
{ GID_COLLATE, sizeof(COLLATE), 10, 0},
{ GID_OUTPUTBIN, sizeof(OUTPUTBIN), 10, 0},
{ GID_MEMOPTION, sizeof(MEMOPTION), 10, 0},
{ GID_LEADINGEDGE, sizeof(OPTION), 25, FEATURE_FLAG_NOUI | FEATURE_FLAG_NOINVOCATION},
{ GID_USEHWMARGINS, sizeof(OPTION), 25, FEATURE_FLAG_NOUI | FEATURE_FLAG_NOINVOCATION},
{ GID_UNKNOWN, sizeof(OPTION), 0, 0},
};
DWORD dwIndex;
for (dwIndex = 0; FeatureData[dwIndex].dwFeatureID != GID_UNKNOWN; dwIndex++)
{
if (FeatureData[dwIndex].dwFeatureID == dwFeatureID)
break;
}
return &FeatureData[dwIndex];
}
VOID
VGrowPackBuffer(
PPARSERDATA pParserData,
DWORD dwBytesNeeded
)
/*++
Routine Description:
Grow the buffer used to hold packed binary data if necessary
Arguments:
pParserData - Points to parser data structure
dwBytesNeeded - Number of bytes needed
Return Value:
NONE
--*/
#define PACK_BUFFER_MAX 1024 // measured in number of pages
{
VALIDATE_PARSER_DATA(pParserData);
//
// We need to commit more memory if the number of bytes needed plus the
// number of bytes used is over the maximum number of bytes committed.
//
if ((dwBytesNeeded += pParserData->dwBufSize) > pParserData->dwCommitSize)
{
//
// Check if we're being called for the first time.
// In that case, we'll need to reserved the virtual address space.
//
if (pParserData->pubBufStart == NULL)
{
SYSTEM_INFO SystemInfo;
PBYTE pbuf;
GetSystemInfo(&SystemInfo);
pParserData->dwPageSize = SystemInfo.dwPageSize;
pbuf = VirtualAlloc(NULL,
PACK_BUFFER_MAX * SystemInfo.dwPageSize,
MEM_RESERVE,
PAGE_READWRITE);
if (pbuf == NULL)
{
ERR(("Cannot reserve memory: %d\n", GetLastError()));
PACK_BINARY_DATA_EXCEPTION();
}
pParserData->pubBufStart = pbuf;
pParserData->pInfoHdr = (PINFOHEADER) pbuf;
pParserData->pUIInfo = (PUIINFO) (pbuf + sizeof(INFOHEADER));
pParserData->pPpdData = (PPPDDATA) (pbuf + sizeof(INFOHEADER) + sizeof(UIINFO));
}
//
// Make sure we're not overflowing
//
if (dwBytesNeeded > (PACK_BUFFER_MAX * pParserData->dwPageSize))
{
ERR(("Binary printer description is too big.\n"));
PACK_BINARY_DATA_EXCEPTION();
}
//
// Commit the extra amount of memory needed (rounded up
// to the next page boundary). Note that the memory allocated
// using VirtualAlloc is zero-initialized.
//
dwBytesNeeded -= pParserData->dwCommitSize;
dwBytesNeeded = ROUND_UP_MULTIPLE(dwBytesNeeded, pParserData->dwPageSize);
pParserData->dwCommitSize += dwBytesNeeded;
if (! VirtualAlloc(pParserData->pubBufStart,
pParserData->dwCommitSize,
MEM_COMMIT,
PAGE_READWRITE))
{
ERR(("Cannot commit memory: %d\n", GetLastError()));
PACK_BINARY_DATA_EXCEPTION();
}
}
}
PVOID
PvFindListItem(
PVOID pvList,
PCSTR pstrName,
PDWORD pdwIndex
)
/*++
Routine Description:
Find a named item from a linked-list
Arguments:
pParserData - Points to parser data structure
pstrName - Specifies the item name to be found
pdwIndex - Points to a variable for returning a zero-based item index
Return Value:
Points to the named listed item, NULL if the named item is not in the list
Note:
We're not bothering with fancy data structures here because the parser
is used infrequently to convert a ASCII printer description file to its
binary version. After that, the driver will access binary data directly.
--*/
{
PLISTOBJ pItem;
DWORD dwIndex;
for (pItem = pvList, dwIndex = 0;
pItem && strcmp(pItem->pstrName, pstrName) != EQUAL_STRING;
pItem = pItem->pNext, dwIndex++)
{
}
if (pdwIndex)
*pdwIndex = dwIndex;
return pItem;
}
DWORD
DwCountListItem(
PVOID pvList
)
/*++
Routine Description:
Count the number of items in a linked-list
Arguments:
pvList - Points to a linked-list
Return Value:
Number of items in a linked-list
--*/
{
PLISTOBJ pItem;
DWORD dwCount;
for (pItem = pvList, dwCount = 0;
pItem != NULL;
pItem = pItem->pNext, dwCount++)
{
}
return dwCount;
}
VOID
VPackStringUnicode(
PPARSERDATA pParserData,
PTRREF *ploDest,
PWSTR pwstrSrc
)
/*++
Routine Description:
Pack a Unicode string into the binary data file
Arguments:
pParserData - Points to the parser data structure
ploDest - Returns the byte offset of the packed Unicode string
pwstrSrc - Specifies the source Unicode string to be packed
Return Value:
NONE
--*/
{
if (pwstrSrc == NULL)
*ploDest = 0;
else
{
DWORD dwSize = (wcslen(pwstrSrc) + 1) * sizeof(WCHAR);
VGrowPackBuffer(pParserData, dwSize);
CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize, pwstrSrc, dwSize);
*ploDest = pParserData->dwBufSize;
pParserData->dwBufSize += DWORD_ALIGN(dwSize);
}
}
VOID
VPackStringRsrc(
PPARSERDATA pParserData,
PTRREF *ploDest,
INT iStringId
)
/*++
Routine Description:
Pack a Unicode string resource into the binary data file
Arguments:
pParserData - Points to the parser data structure
ploDest - Returns the byte offset of the packed Unicode string
iStringId - Specifies the resource ID of the Unicode string to be packed
Return Value:
NONE
--*/
{
WCHAR awchBuffer[MAX_XLATION_LEN];
if (! LoadString(ghInstance, iStringId, awchBuffer, MAX_XLATION_LEN))
awchBuffer[0] = NUL;
VPackStringUnicode(pParserData, ploDest, awchBuffer);
}
VOID
VPackStringAnsi(
PPARSERDATA pParserData,
PTRREF *ploDest,
PSTR pstrSrc
)
/*++
Routine Description:
Pack an ANSI string into the binary data file
Arguments:
pParserData - Points to the parser data structure
ploDest - Returns the byte offset of the packed ANSI string
pstrSrc - Specifies the source ANSI string to be packed
Return Value:
NONE
--*/
{
if (pstrSrc == NULL)
*ploDest = 0;
else
{
DWORD dwSize = strlen(pstrSrc) + 1;
VGrowPackBuffer(pParserData, dwSize);
CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize, pstrSrc, dwSize);
*ploDest = pParserData->dwBufSize;
pParserData->dwBufSize += DWORD_ALIGN(dwSize);
}
}
INT
ITranslateToUnicodeString(
PWSTR pwstr,
PCSTR pstr,
INT iLength,
UINT uCodePage
)
/*++
Routine Description:
Translate an ANSI string to Unicode string
Arguments:
pwstr - Buffer for storing Unicode string
pstr - Pointer to ANSI string to be translated
iLength - Length of ANSI string, in bytes
uCodePage - Code page used to do the translation
Return Value:
Number of Unicode characters translated
0 if there is an error
--*/
{
ASSERT(iLength >= 0);
if (uCodePage == CP_UNICODE)
{
INT i;
//
// Make sure the Unicode translation string has even number of bytes
//
if (iLength & 1)
{
TERSE(("Odd number of bytes in Unicode translation string.\n"));
iLength--;
}
//
// We assume Unicode values are specified in big-endian format in
// the PPD file. Internally we store Unicode values in little-endian
// format. So we need to swap bytes here.
//
iLength /= sizeof(WCHAR);
for (i=iLength; i--; pstr += 2)
*pwstr++ = (pstr[0] << 8) | ((BYTE) pstr[1]);
}
else
{
if (uCodePage == CP_ERROR)
uCodePage = CP_ACP;
iLength = MultiByteToWideChar(uCodePage, 0, pstr, iLength, pwstr, iLength);
ASSERT(iLength >= 0);
}
return iLength;
}
VOID
VPackStringAnsiToUnicode(
PPARSERDATA pParserData,
PTRREF *ploDest,
PSTR pstrSrc,
INT iLength
)
/*++
Routine Description:
Convert an ANSI string to Unicode and pack it into the binary data file
Arguments:
pParserData - Points to the parser data structure
ploDest - Returns the byte offset of the packed Unicode string
pstrSrc - Specifies the source ANSI string to be packed
iLength - Specifies the byte length of the ANSI string
Return Value:
NONE
--*/
{
INT iSize;
PTSTR ptstr;
//
// Source string is NULL
//
if (pstrSrc == NULL)
{
*ploDest = 0;
return;
}
//
// If source string length is -1, it means
// the source string is null-terminated.
//
if (iLength == -1)
iLength = strlen(pstrSrc);
if (pParserData->uCodePage == CP_UNICODE)
{
//
// Source string is Unicode string
//
iSize = iLength + sizeof(WCHAR);
}
else
{
//
// Source string is ANSI string
//
iSize = (iLength + 1) * sizeof(WCHAR);
}
VGrowPackBuffer(pParserData, iSize);
ptstr = (PTSTR) (pParserData->pubBufStart + pParserData->dwBufSize);
*ploDest = pParserData->dwBufSize;
pParserData->dwBufSize += DWORD_ALIGN(iSize);
ITranslateToUnicodeString(ptstr, pstrSrc, iLength, pParserData->uCodePage);
}
VOID
VPackStringXlation(
PPARSERDATA pParserData,
PTRREF *ploDest,
PSTR pstrName,
PINVOCOBJ pXlation
)
/*++
Routine Description:
Figure out the display name of an item, convert it from ANSI
to Unicode string, and pack it into the binary data
Arguments:
pParserData - Points to the parser data structure
ploDest - Returns the byte offset of the packed Unicode string
pstrName - Specifies the name string associated with the item
pXlation - Specifies the translation string associated with the item
Return Value:
NONE
--*/
{
//
// The display name of an item is its translation string if there is one.
// Otherwise, the display name is the same as the name of the item.
//
// If the translation is present, use the current language encoding
// to convert it to Unicode. Otherwise, we always use the ISOLatin1
// encoding to convert the name of the item to Unicode.
//
if (pXlation && pXlation->pvData && pParserData->uCodePage != CP_ERROR)
VPackStringAnsiToUnicode(pParserData, ploDest, pXlation->pvData, pXlation->dwLength);
else
{
UINT uCodePage = pParserData->uCodePage;
pParserData->uCodePage = 1252;
VPackStringAnsiToUnicode(pParserData, ploDest, pstrName, -1);
pParserData->uCodePage = uCodePage;
}
}
VOID
VPackInvocation(
PPARSERDATA pParserData,
PINVOCATION pInvocation,
PINVOCOBJ pInvocObj
)
/*++
Routine Description:
Pack an invocation string into the binary data
Arguments:
pParserData - Points to the parser data structure
pInvocation - Returns information about the packed invocation string
pInvocObj - Points to the invocation string to be packed
Return Value:
NONE
--*/
{
if (IS_SYMBOL_INVOC(pInvocObj))
{
//
// The invocation is a symbol reference
//
PSYMBOLOBJ pSymbol = pInvocObj->pvData;
pInvocation->dwCount = pSymbol->Invocation.dwLength;
//
// For symbol invocation, Invocation.pvData actually stores the
// 32-bit offset value (See function VPackSymbolDefinitions), so
// it's safe to cast it into ULONG/DWORD.
//
pInvocation->loOffset = (PTRREF) PtrToUlong(pSymbol->Invocation.pvData);
}
else if (pInvocObj->dwLength == 0)
{
pInvocation->dwCount = 0;
pInvocation->loOffset = 0;
}
else
{
//
// Notice that we're always padding a zero byte at the end of
// the invocation string. This byte is not counted in dwLength.
//
VGrowPackBuffer(pParserData, pInvocObj->dwLength+1);
CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize,
pInvocObj->pvData,
pInvocObj->dwLength);
pInvocation->dwCount = pInvocObj->dwLength;
pInvocation->loOffset = pParserData->dwBufSize;
pParserData->dwBufSize += DWORD_ALIGN(pInvocObj->dwLength+1);
}
}
VOID
VPackPatch(
PPARSERDATA pParserData,
PJOBPATCHFILE pPackedPatch,
PJOBPATCHFILEOBJ pPatchObj
)
/*++
Routine Description:
Pack an job file patch invocation string into the binary data
Arguments:
pParserData - Points to the parser data structure
pInvocation - Returns information about the packed invocation string
pInvocObj - Points to the invocation string to be packed
Return Value:
NONE
--*/
{
if (pPatchObj->Invocation.dwLength == 0)
{
pPackedPatch->dwCount = 0;
pPackedPatch->loOffset = 0;
}
else
{
//
// Notice that we're always padding a zero byte at the end of
// the invocation string. This byte is not counted in dwLength.
//
VGrowPackBuffer(pParserData, pPatchObj->Invocation.dwLength+1);
CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize,
pPatchObj->Invocation.pvData,
pPatchObj->Invocation.dwLength);
pPackedPatch->loOffset = pParserData->dwBufSize;
pPackedPatch->dwCount = pPatchObj->Invocation.dwLength;
pParserData->dwBufSize += DWORD_ALIGN(pPatchObj->Invocation.dwLength+1);
}
pPackedPatch->lJobPatchNo = pPatchObj->lPatchNo;
}
VOID
VPackSymbolDefinitions(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack all symbol definitions into the binary data
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PINVOCOBJ pInvocObj;
PSYMBOLOBJ pSymbol;
VALIDATE_PARSER_DATA(pParserData);
for (pSymbol = pParserData->pSymbols;
pSymbol != NULL;
pSymbol = pSymbol->pNext)
{
pInvocObj = &pSymbol->Invocation;
ASSERT(! IS_SYMBOL_INVOC(pInvocObj));
if (pInvocObj->dwLength == 0)
pInvocObj->pvData = NULL;
else
{
//
// Notice that we're always padding a zero byte at the end of
// the invocation string. This byte is not counted in dwLength.
//
VGrowPackBuffer(pParserData, pInvocObj->dwLength+1);
CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize,
pInvocObj->pvData,
pInvocObj->dwLength);
pInvocObj->pvData = (PVOID)ULongToPtr(pParserData->dwBufSize);
pParserData->dwBufSize += DWORD_ALIGN(pInvocObj->dwLength+1);
}
}
}
VOID
VResolveSymbolInvocation(
PPARSERDATA pParserData,
PINVOCOBJ pInvocObj
)
/*++
Routine Description:
Check if an invocation string is a symbol reference and resolve it if necessary
Arguments:
pParserData - Points to the parser data structure
pInvocObj - Specifies the invocation string to be resolved
Return Value:
NONE
--*/
{
if (IS_SYMBOL_INVOC(pInvocObj))
{
PSTR pstrName;
PSYMBOLOBJ pSymbol;
pstrName = (PSTR) pInvocObj->pvData;
if ((pSymbol = PvFindListItem(pParserData->pSymbols, pstrName, NULL)) == NULL)
{
SEMANTIC_ERROR(("Undefined symbol: %s\n", pstrName));
pInvocObj->dwLength = 0;
pInvocObj->pvData = NULL;
}
else
pInvocObj->pvData = (PVOID) pSymbol;
}
}
VOID
VResolveSymbolReferences(
PPARSERDATA pParserData
)
/*++
Routine Description:
Resolve all symbol references in the parsed PPD data
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PFEATUREOBJ pFeature;
POPTIONOBJ pOption;
PJOBPATCHFILEOBJ pJobPatchFile;
VALIDATE_PARSER_DATA(pParserData);
VResolveSymbolInvocation(pParserData, &pParserData->Password);
VResolveSymbolInvocation(pParserData, &pParserData->ExitServer);
VResolveSymbolInvocation(pParserData, &pParserData->PatchFile);
VResolveSymbolInvocation(pParserData, &pParserData->JclBegin);
VResolveSymbolInvocation(pParserData, &pParserData->JclEnterPS);
VResolveSymbolInvocation(pParserData, &pParserData->JclEnd);
VResolveSymbolInvocation(pParserData, &pParserData->ManualFeedFalse);
for (pFeature = pParserData->pFeatures;
pFeature != NULL;
pFeature = pFeature->pNext)
{
VResolveSymbolInvocation(pParserData, &pFeature->QueryInvoc);
for (pOption = pFeature->pOptions;
pOption != NULL;
pOption = pOption->pNext)
{
VResolveSymbolInvocation(pParserData, &pOption->Invocation);
}
}
for (pJobPatchFile = pParserData->pJobPatchFiles;
pJobPatchFile != NULL;
pJobPatchFile = pJobPatchFile->pNext)
{
VResolveSymbolInvocation(pParserData, &pJobPatchFile->Invocation);
}
}
BOOL
BFindUIConstraintFeatureOption(
PPARSERDATA pParserData,
PCSTR pstrKeyword,
PFEATUREOBJ *ppFeature,
PDWORD pdwFeatureIndex,
PCSTR pstrOption,
POPTIONOBJ *ppOption,
PDWORD pdwOptionIndex
)
/*++
Routine Description:
Find the feature/option specified in UIConstraints and OrderDependency entries
Arguments:
pParserData - Points to the parser data structure
pstrKeyword - Specifies the feature keyword string
ppFeature - Return a pointer to the feature structure found
pdwFeatureIndex - Return the index of the feature found
pstrOption - Specifies the option keyword string
ppOption - Return a pointer to the option structure found
pdwOptionIndex - Return the index of the option found
Return Value:
TRUE if successful, FALSE if the specified feature/option is not found
--*/
{
if (! (pstrKeyword = PstrStripKeywordChar(pstrKeyword)))
return FALSE;
//
// HACK:
// replace *ManualFeed True option with *InputSlot ManualFeed option
// replace *CustomPageSize True option with *PageSize CustomPageSize option
//
if ((strcmp(pstrKeyword, gstrManualFeedKwd) == EQUAL_STRING) &&
(*pstrOption == NUL ||
strcmp(pstrOption, gstrTrueKwd) == EQUAL_STRING ||
strcmp(pstrOption, gstrOnKwd) == EQUAL_STRING))
{
pstrKeyword = gstrInputSlotKwd;
pstrOption = gstrManualFeedKwd;
}
else if ((strcmp(pstrKeyword, gstrCustomSizeKwd) == EQUAL_STRING) &&
(*pstrOption == NUL || strcmp(pstrOption, gstrTrueKwd) == EQUAL_STRING))
{
pstrKeyword = gstrPageSizeKwd;
pstrOption = gstrCustomSizeKwd;
}
else if (strcmp(pstrKeyword, gstrVMOptionKwd) == EQUAL_STRING)
pstrKeyword = gstrInstallMemKwd;
//
// Find the specified feature
//
if (! (*ppFeature = PvFindListItem(pParserData->pFeatures, pstrKeyword, pdwFeatureIndex)))
return FALSE;
//
// Find the specified option
//
if (*pstrOption)
{
return (*ppOption = PvFindListItem((*ppFeature)->pOptions,
pstrOption,
pdwOptionIndex)) != NULL;
}
else
{
*ppOption = NULL;
*pdwOptionIndex = OPTION_INDEX_ANY;
return TRUE;
}
}
VOID
VPackUIConstraints(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack UIConstraints information into binary data
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PUICONSTRAINT pPackedConstraint;
PFEATUREOBJ pFeature;
POPTIONOBJ pOption;
PLISTOBJ pConstraint;
DWORD dwConstraints, dwConstraintBufStart;
VALIDATE_PARSER_DATA(pParserData);
//
// By default, there is no constaint for all features and options
//
for (pFeature = pParserData->pFeatures;
pFeature != NULL;
pFeature = pFeature->pNext)
{
pFeature->dwConstraint = NULL_CONSTRAINT;
for (pOption = pFeature->pOptions;
pOption != NULL;
pOption = pOption->pNext)
{
pOption->dwConstraint = NULL_CONSTRAINT;
}
}
//
// Count the number of *UIConstraints entries
//
dwConstraints = DwCountListItem(pParserData->pUIConstraints);
if (dwConstraints == 0)
return;
//
// Don't yet grow the buffer, we only number the number of constraints after we
// evaluated the *ManualFeed: False constraints. pPackedConstraint points right
// after the end of the current buffer
//
pPackedConstraint = (PUICONSTRAINT) (pParserData->pubBufStart + pParserData->dwBufSize);
dwConstraintBufStart = pParserData->dwBufSize;
//
// Interpret each *UIConstraints entry
//
dwConstraints = 0;
for (pConstraint = pParserData->pUIConstraints;
pConstraint != NULL;
pConstraint = pConstraint->pNext)
{
PFEATUREOBJ pFeature2;
POPTIONOBJ pOption2;
DWORD dwFeatureIndex, dwOptionIndex, dwManFeedFalsePos = 0;
CHAR achWord1[MAX_WORD_LEN];
CHAR achWord2[MAX_WORD_LEN];
CHAR achWord3[MAX_WORD_LEN];
CHAR achWord4[MAX_WORD_LEN];
PSTR pstr = pConstraint->pstrName;
BOOL bSuccess = FALSE;
//
// The value for a UIConstraints entry consists of four separate components:
// featureName1 [optionName1] featureName2 [optionName2]
//
(VOID) BFindNextWord(&pstr, achWord1);
if (IS_KEYWORD_CHAR(*pstr))
achWord2[0] = NUL;
else
(VOID) BFindNextWord(&pstr, achWord2);
(VOID) BFindNextWord(&pstr, achWord3);
(VOID) BFindNextWord(&pstr, achWord4);
//
// hack the *ManualFeed False constraints
//
if ((IS_KEYWORD_CHAR(achWord1[0])) &&
(strcmp(&(achWord1[1]), gstrManualFeedKwd) == EQUAL_STRING) &&
(strcmp(achWord2, gstrFalseKwd) == EQUAL_STRING))
{
//
// check the validity of the constraint feature/option. Fall through if invalid
//
if (BFindUIConstraintFeatureOption(pParserData,
achWord3,
&pFeature,
&dwFeatureIndex,
achWord4,
&pOption,
&dwOptionIndex))
dwManFeedFalsePos = 1;
}
else if ((IS_KEYWORD_CHAR(achWord3[0])) &&
(strcmp(&(achWord3[1]), gstrManualFeedKwd) == EQUAL_STRING) &&
(strcmp(achWord4, gstrFalseKwd) == EQUAL_STRING))
{
//
// check the validity of the constraint feature/option. Fall through if invalid
//
if (BFindUIConstraintFeatureOption(pParserData,
achWord1,
&pFeature,
&dwFeatureIndex,
achWord2,
&pOption,
&dwOptionIndex))
dwManFeedFalsePos = 2;
}
if (dwManFeedFalsePos)
{
//
// get the index of the manual feed input slot
//
DWORD dwInputSlotFeatIndex, dwManFeedSlotIndex, dwInputSlotCount, dwSlotIndex;
PFEATUREOBJ pInputSlotFeature;
if ((pInputSlotFeature = PvFindListItem(pParserData->pFeatures, gstrInputSlotKwd, &dwInputSlotFeatIndex)) == NULL)
{
ERR(("Input slot feature not found !!!"));
continue;
}
//
// get the number of input slots. Note that this includes the dummy "*UseFormTrayTable" slot.
//
dwInputSlotCount = DwCountListItem((PVOID) pInputSlotFeature->pOptions);
if (dwInputSlotCount <= 2) // to make sense there must be at least 3 slot, incl. UseFormTrayTable+ManualFeed
{
ERR(("ManualFeed used - internally at least 3 input slots expected !"));
continue;
}
//
// grow the buffer for constraints. Two less than input slots because
// 1 input slot is the dummy UseFormTrayTable slot
// 1 input slot is the ManualFeed slot that I don't want to constraint
//
VGrowPackBuffer(pParserData, (dwInputSlotCount -2) * sizeof(UICONSTRAINT));
if (dwManFeedFalsePos == 1)
{
//
// add constraints to each input slot for the constrained feature
//
POPTIONOBJ pNextObj = pInputSlotFeature->pOptions;
ASSERT(strcmp(pNextObj->pstrName, "*UseFormTrayTable") == EQUAL_STRING); // in case we change the logic some time later...
//
// since the UseFormTrayTable is the first option, start with the second
//
pNextObj = pNextObj->pNext;
ASSERT(pNextObj != NULL);
while (pNextObj)
{
//
// skip the manual feed input slot, don't constrain that
//
if (strcmp(pNextObj->pstrName, gstrManualFeedKwd) == EQUAL_STRING)
{
pNextObj = pNextObj->pNext;
continue;
}
pPackedConstraint[dwConstraints].dwNextConstraint = pNextObj->dwConstraint;
pNextObj->dwConstraint = dwConstraints;
pPackedConstraint[dwConstraints].dwFeatureIndex = dwFeatureIndex;
pPackedConstraint[dwConstraints].dwOptionIndex = dwOptionIndex;
dwConstraints++;
pNextObj = pNextObj->pNext;
}
}
else
{
//
// find the option index of the manual feed slot
//
if (PvFindListItem(pInputSlotFeature->pOptions, gstrManualFeedKwd, &dwManFeedSlotIndex) == NULL)
{
ERR(("ManualFeed slot not found among InputSlots !!!"));
continue;
}
//
// add constraints to the affected feature for all input slots BUT the manual feed slot
// and the UseFormTrayTable slot
// start with slot index 1, because the first slot is always *UseFormTrayTable
//
for (dwSlotIndex = 1; dwSlotIndex < dwInputSlotCount; dwSlotIndex++)
{
if (dwSlotIndex == dwManFeedSlotIndex)
continue;
if (pOption == NULL)
{
//
// OptionKeyword1 field is not present
//
pPackedConstraint[dwConstraints].dwNextConstraint = pFeature->dwConstraint;
pFeature->dwConstraint = dwConstraints;
}
else
{
//
// OptionKeyword1 field is present
//
pPackedConstraint[dwConstraints].dwNextConstraint = pOption->dwConstraint;
pOption->dwConstraint = dwConstraints;
}
pPackedConstraint[dwConstraints].dwFeatureIndex = dwInputSlotFeatIndex;
pPackedConstraint[dwConstraints].dwOptionIndex = dwSlotIndex;
dwConstraints++;
}
}
//
// increase the committed buffer size so additional VGrowPackBuffer calls can allocate
// additional pages if needed for more *ManualFeed False constraints
//
pParserData->dwBufSize += DWORD_ALIGN((dwInputSlotCount -2) * sizeof(UICONSTRAINT));
continue;
} // back to the normal course of events.
if (BFindUIConstraintFeatureOption(pParserData,
achWord1,
&pFeature,
&dwFeatureIndex,
achWord2,
&pOption,
&dwOptionIndex) &&
BFindUIConstraintFeatureOption(pParserData,
achWord3,
&pFeature2,
&dwFeatureIndex,
achWord4,
&pOption2,
&dwOptionIndex))
{
VGrowPackBuffer(pParserData, sizeof(UICONSTRAINT));
if (pOption == NULL)
{
//
// OptionKeyword1 field is not present
//
pPackedConstraint[dwConstraints].dwNextConstraint = pFeature->dwConstraint;
pFeature->dwConstraint = dwConstraints;
}
else
{
//
// OptionKeyword1 field is present
//
pPackedConstraint[dwConstraints].dwNextConstraint = pOption->dwConstraint;
pOption->dwConstraint = dwConstraints;
}
pPackedConstraint[dwConstraints].dwFeatureIndex = dwFeatureIndex;
pPackedConstraint[dwConstraints].dwOptionIndex = dwOptionIndex;
dwConstraints++;
bSuccess = TRUE;
//
// increase the committed buffer size so additional VGrowPackBuffer calls can allocate
// additional pages if needed for more *ManualFeed False constraints
//
pParserData->dwBufSize += DWORD_ALIGN(sizeof(UICONSTRAINT));
}
if (! bSuccess)
SEMANTIC_ERROR(("Invalid *UIConstraints entry: %s\n", pConstraint->pstrName));
}
//
// Save the packed UIConstraints information in the binary data
//
if (dwConstraints == 0)
{
pParserData->pUIInfo->UIConstraints.dwCount = 0;
pParserData->pUIInfo->UIConstraints.loOffset = 0;
}
else
{
pParserData->pUIInfo->UIConstraints.dwCount = dwConstraints;
pParserData->pUIInfo->UIConstraints.loOffset = dwConstraintBufStart;
}
}
VOID
VPackOrderDependency(
PPARSERDATA pParserData,
PARRAYREF parefDest,
PLISTOBJ pOrderDep
)
/*++
Routine Description:
Pack OrderDependency/QueryOrderDependency information into binary data
Arguments:
pParserData - Points to the parser data structure
parefDest - Stores information about where the order dependency info is packed
pOrderDep - Specifies the list of order dependencies to be packed
Return Value:
NONE
--*/
{
static const STRTABLE SectionStrs[] =
{
{ "DocumentSetup", SECTION_DOCSETUP},
{ "AnySetup", SECTION_ANYSETUP},
{ "PageSetup", SECTION_PAGESETUP},
{ "Prolog", SECTION_PROLOG},
{ "ExitServer", SECTION_EXITSERVER},
{ "JCLSetup", SECTION_JCLSETUP},
{ NULL, SECTION_UNASSIGNED}
};
PORDERDEPEND pPackedDep;
PFEATUREOBJ pFeature;
POPTIONOBJ pOption;
DWORD dwOrderDep, dwFeatures, dwIndex;
DWORD dwFeatureIndex, dwOptionIndex, dwSection;
LONG lOrder;
VALIDATE_PARSER_DATA(pParserData);
//
// The maximum number of entries we need is:
// number of printer features + number of order dependency entries
//
dwFeatures = pParserData->pInfoHdr->RawData.dwDocumentFeatures +
pParserData->pInfoHdr->RawData.dwPrinterFeatures;
dwOrderDep = dwFeatures + DwCountListItem(pOrderDep);
VGrowPackBuffer(pParserData, dwOrderDep * sizeof(ORDERDEPEND));
pPackedDep = (PORDERDEPEND) (pParserData->pubBufStart + pParserData->dwBufSize);
//
// Create a default order dependency entry for each feature
//
for (pFeature = pParserData->pFeatures, dwFeatureIndex = 0;
pFeature != NULL;
pFeature = pFeature->pNext, dwFeatureIndex++)
{
pPackedDep[dwFeatureIndex].lOrder = MAX_ORDER_VALUE;
pPackedDep[dwFeatureIndex].dwSection = SECTION_UNASSIGNED;
pPackedDep[dwFeatureIndex].dwPPDSection = SECTION_UNASSIGNED;
pPackedDep[dwFeatureIndex].dwFeatureIndex = dwFeatureIndex;
pPackedDep[dwFeatureIndex].dwOptionIndex = OPTION_INDEX_ANY;
}
//
// Interpret each order dependency entry
//
for (dwOrderDep = dwFeatures; pOrderDep != NULL; pOrderDep = pOrderDep->pNext)
{
CHAR achWord1[MAX_WORD_LEN];
CHAR achWord2[MAX_WORD_LEN];
PSTR pstr = pOrderDep->pstrName;
BOOL bSuccess = FALSE;
//
// Each order dependency entry has the following components:
// order section mainKeyword [optionKeyword]
//
if (BGetFloatFromString(&pstr, &lOrder, FLTYPE_INT) &&
BFindNextWord(&pstr, achWord1) &&
BSearchStrTable(SectionStrs, achWord1, &dwSection) &&
BFindNextWord(&pstr, achWord1))
{
(VOID) BFindNextWord(&pstr, achWord2);
if (BFindUIConstraintFeatureOption(pParserData,
achWord1,
&pFeature,
&dwFeatureIndex,
achWord2,
&pOption,
&dwOptionIndex))
{
//
// Check if an OrderDependency for the same feature/option
// has appeared before.
//
for (dwIndex = 0; dwIndex < dwOrderDep; dwIndex++)
{
if (pPackedDep[dwIndex].dwFeatureIndex == dwFeatureIndex &&
pPackedDep[dwIndex].dwOptionIndex == dwOptionIndex)
{
break;
}
}
if (dwIndex < dwOrderDep && pPackedDep[dwIndex].lOrder < MAX_ORDER_VALUE)
{
TERSE(("Duplicate order dependency entry: %s\n", pOrderDep->pstrName));
}
else
{
if (dwIndex >= dwOrderDep)
dwIndex = dwOrderDep++;
//
// Ensure the specified order value is less than MAX_ORDER_VALUE
//
if (lOrder >= MAX_ORDER_VALUE)
{
WARNING(("Order dependency value too big: %s\n", pOrderDep->pstrName));
lOrder = MAX_ORDER_VALUE - 1;
}
pPackedDep[dwIndex].dwSection = dwSection;
pPackedDep[dwIndex].dwPPDSection = dwSection;
pPackedDep[dwIndex].lOrder = lOrder;
pPackedDep[dwIndex].dwFeatureIndex = dwFeatureIndex;
pPackedDep[dwIndex].dwOptionIndex = dwOptionIndex;
}
bSuccess = TRUE;
}
}
if (! bSuccess)
SEMANTIC_ERROR(("Invalid order dependency: %s\n", pOrderDep->pstrName));
}
//
// Tell the caller where the packed order dependency information is stored
//
if (dwOrderDep == 0)
{
parefDest->dwCount = 0;
parefDest->loOffset = 0;
return;
}
parefDest->dwCount = dwOrderDep;
parefDest->loOffset = pParserData->dwBufSize;
pParserData->dwBufSize += DWORD_ALIGN(dwOrderDep * sizeof(ORDERDEPEND));
//
// Sort order dependency information using the order value
//
for (dwIndex = 0; dwIndex+1 < dwOrderDep; dwIndex++)
{
DWORD dwMinIndex, dwLoop;
//
// Nothing fancy here - straight-forward selection sort
//
dwMinIndex = dwIndex;
for (dwLoop = dwIndex+1; dwLoop < dwOrderDep; dwLoop++)
{
if ((pPackedDep[dwLoop].lOrder < pPackedDep[dwMinIndex].lOrder) ||
(pPackedDep[dwLoop].lOrder == pPackedDep[dwMinIndex].lOrder &&
pPackedDep[dwLoop].dwSection < pPackedDep[dwMinIndex].dwSection))
{
dwMinIndex = dwLoop;
}
}
if (dwMinIndex != dwIndex)
{
ORDERDEPEND TempDep;
TempDep = pPackedDep[dwIndex];
pPackedDep[dwIndex] = pPackedDep[dwMinIndex];
pPackedDep[dwMinIndex] = TempDep;
}
}
//
// Resolve AnySetup into either DocumentSetup or PageSetup
//
dwSection = SECTION_DOCSETUP;
for (dwIndex = 0; dwIndex < dwOrderDep; dwIndex++)
{
if (pPackedDep[dwIndex].dwSection == SECTION_PAGESETUP)
dwSection = SECTION_PAGESETUP;
else if (pPackedDep[dwIndex].dwSection == SECTION_ANYSETUP)
pPackedDep[dwIndex].dwSection = dwSection;
}
//
// Maintain a linked-list of order dependency entries for each feature
// starting with the entry whose dwOptionIndex = OPTION_INDEX_ANY.
//
for (dwIndex = 0; dwIndex < dwOrderDep; dwIndex++)
pPackedDep[dwIndex].dwNextOrderDep = NULL_ORDERDEP;
for (dwIndex = 0; dwIndex < dwOrderDep; dwIndex++)
{
DWORD dwLastIndex, dwLoop;
if (pPackedDep[dwIndex].dwOptionIndex != OPTION_INDEX_ANY)
continue;
dwLastIndex = dwIndex;
for (dwLoop = 0; dwLoop < dwOrderDep; dwLoop++)
{
if (pPackedDep[dwLoop].dwFeatureIndex == pPackedDep[dwIndex].dwFeatureIndex &&
pPackedDep[dwLoop].dwOptionIndex != OPTION_INDEX_ANY)
{
pPackedDep[dwLastIndex].dwNextOrderDep = dwLoop;
dwLastIndex = dwLoop;
}
}
pPackedDep[dwLastIndex].dwNextOrderDep = NULL_ORDERDEP;
}
//
// !!!CR
// Needs to flag out-of-order OrderDependency.
//
}
VOID
VCountAndSortPrinterFeatures(
PPARSERDATA pParserData
)
/*++
Routine Description:
Count the number of doc- and printer-sticky features
and sort them into two separate groups
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PFEATUREOBJ pFeature, pNext, pDocFeatures, pPrinterFeatures;
DWORD dwDocFeatures, dwPrinterFeatures;
VALIDATE_PARSER_DATA(pParserData);
//
// Count the number of doc- and printer-sticky features
//
pDocFeatures = pPrinterFeatures = NULL;
dwDocFeatures = dwPrinterFeatures = 0;
pFeature = pParserData->pFeatures;
while (pFeature != NULL)
{
pNext = pFeature->pNext;
if (pFeature->bInstallable)
{
pFeature->pNext = pPrinterFeatures;
pPrinterFeatures = pFeature;
dwPrinterFeatures++;
}
else
{
pFeature->pNext = pDocFeatures;
pDocFeatures = pFeature;
dwDocFeatures++;
}
pFeature = pNext;
}
ASSERTMSG((dwDocFeatures + dwPrinterFeatures <= MAX_PRINTER_OPTIONS),
("Too many printer features.\n"));
//
// Rearrange the features so that all doc-sticky features
// are in front of printer-sticky features
//
pFeature = NULL;
while (pPrinterFeatures != NULL)
{
pNext = pPrinterFeatures->pNext;
pPrinterFeatures->pNext = pFeature;
pFeature = pPrinterFeatures;
pPrinterFeatures = pNext;
}
while (pDocFeatures != NULL)
{
pNext = pDocFeatures->pNext;
pDocFeatures->pNext = pFeature;
pFeature = pDocFeatures;
pDocFeatures = pNext;
}
pParserData->pFeatures = pFeature;
pParserData->pInfoHdr->RawData.dwDocumentFeatures = dwDocFeatures;
pParserData->pInfoHdr->RawData.dwPrinterFeatures = dwPrinterFeatures;
}
VOID
VProcessPrinterFeatures(
PPARSERDATA pParserData
)
/*++
Routine Description:
Process printer features and handle any special glitches
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
PFEATUREOBJ pFeature;
POPTIONOBJ pOption;
for (pFeature = pParserData->pFeatures; pFeature; pFeature = pFeature->pNext)
{
//
// If a feature has no option but has a default specified, then
// synthesize an option with empty invocation string.
//
if (pFeature->pstrDefault && pFeature->pOptions == NULL)
{
pOption = ALLOC_PARSER_MEM(pParserData, pFeature->dwOptionSize);
if (pOption == NULL)
{
ERR(("Memory allocation failed: %d\n", GetLastError()));
PACK_BINARY_DATA_EXCEPTION();
}
//
// NOTE: it's ok for both pOption->pstrName and pFeature->pstrDefault
// to point to the same string here. The memory is deallocated when
// the parser heap is destroyed.
//
pOption->pstrName = pFeature->pstrDefault;
pFeature->pOptions = pOption;
}
//
// Special handling of *InputSlot feature
// Make sure the very first option is always "*UseFormTrayTable"
//
if (pFeature->dwFeatureID == GID_INPUTSLOT)
{
pOption = ALLOC_PARSER_MEM(pParserData, pFeature->dwOptionSize);
if (pOption == NULL)
{
ERR(("Memory allocation failed: %d\n", GetLastError()));
PACK_BINARY_DATA_EXCEPTION();
}
pOption->pstrName = "*UseFormTrayTable";
pOption->pNext = pFeature->pOptions;
pFeature->pOptions = pOption;
((PTRAYOBJ) pOption)->dwTrayIndex = DMBIN_FORMSOURCE;
}
}
}
VOID
VPackPrinterFeatures(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack printer feature and option information into binary data
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PFEATUREOBJ pFeature;
PFEATURE pPackedFeature;
POPTIONOBJ pOption;
POPTION pPackedOption;
DWORD dwFeatureIndex, dwOptionIndex, dwCount;
VALIDATE_PARSER_DATA(pParserData);
//
// Reserve space in the binary data for an array of FEATURE structures
//
dwCount = pParserData->pInfoHdr->RawData.dwDocumentFeatures +
pParserData->pInfoHdr->RawData.dwPrinterFeatures;
VGrowPackBuffer(pParserData, dwCount * sizeof(FEATURE));
pPackedFeature = (PFEATURE) (pParserData->pubBufStart + pParserData->dwBufSize);
pParserData->pUIInfo->loFeatureList = pParserData->dwBufSize;
pParserData->dwBufSize += DWORD_ALIGN(dwCount * sizeof(FEATURE));
for (pFeature = pParserData->pFeatures, dwFeatureIndex = 0;
pFeature != NULL;
pFeature = pFeature->pNext, dwFeatureIndex++, pPackedFeature++)
{
PFEATUREDATA pFeatureData;
//
// Pack feature information
//
VPackStringAnsi(pParserData, &pPackedFeature->loKeywordName, pFeature->pstrName);
VPackStringXlation(pParserData,
&pPackedFeature->loDisplayName,
pFeature->pstrName,
&pFeature->Translation);
VPackInvocation(pParserData, &pPackedFeature->QueryInvocation, &pFeature->QueryInvoc);
pFeatureData = PGetFeatureData(pFeature->dwFeatureID);
pPackedFeature->dwFlags = pFeatureData->dwFlags;
pPackedFeature->dwOptionSize = pFeatureData->dwOptionSize;
pPackedFeature->dwFeatureID = pFeature->dwFeatureID;
pPackedFeature->dwUIType = pFeature->dwUIType;
pPackedFeature->dwUIConstraintList = pFeature->dwConstraint;
pPackedFeature->dwNoneFalseOptIndex = OPTION_INDEX_ANY;
if (pFeature->bInstallable)
{
pPackedFeature->dwPriority = pFeatureData->dwPriority + PRNPROP_BASE_PRIORITY;
pPackedFeature->dwFeatureType = FEATURETYPE_PRINTERPROPERTY;
}
else
{
ASSERT(pFeatureData->dwPriority < PRNPROP_BASE_PRIORITY);
pPackedFeature->dwPriority = pFeatureData->dwPriority;
pPackedFeature->dwFeatureType = FEATURETYPE_DOCPROPERTY;
}
//
// For non-PickMany features, use the very first option as the default
// if none is explicitly specified. Otherwise, default to OPTION_INDEX_ANY.
//
pPackedFeature->dwDefaultOptIndex =
(pFeature->dwUIType == UITYPE_PICKMANY) ? OPTION_INDEX_ANY : 0;
//
// If this feature is a predefined feature, save a reference to it
//
if (pFeature->dwFeatureID < MAX_GID)
{
pParserData->pUIInfo->aloPredefinedFeatures[pFeature->dwFeatureID] =
pParserData->pUIInfo->loFeatureList + (dwFeatureIndex * sizeof(FEATURE));
}
//
// Reserve space in the binary data for an array of OPTION structures
//
if ((dwCount = DwCountListItem(pFeature->pOptions)) == 0)
{
TERSE(("No options for feature: %s\n", pFeature->pstrName));
pPackedFeature->Options.loOffset = 0;
pPackedFeature->Options.dwCount = 0;
continue;
}
ASSERTMSG((dwCount < OPTION_INDEX_ANY),
("Too many options for feature: %s\n", pFeature->pstrName));
VGrowPackBuffer(pParserData, dwCount * pFeatureData->dwOptionSize);
pPackedOption = (POPTION) (pParserData->pubBufStart + pParserData->dwBufSize);
pPackedFeature->Options.loOffset = pParserData->dwBufSize;
pPackedFeature->Options.dwCount = dwCount;
pParserData->dwBufSize += DWORD_ALIGN(dwCount * pFeatureData->dwOptionSize);
for (pOption = pFeature->pOptions, dwOptionIndex = 0;
pOption != NULL;
pOption = pOption->pNext, dwOptionIndex++)
{
BOOL bIsDefaultOption = FALSE; // TRUE if current option is default
//
// Pack option information
//
VPackStringAnsi(pParserData,
&pPackedOption->loKeywordName,
pOption->pstrName);
VPackStringXlation(pParserData,
&pPackedOption->loDisplayName,
pOption->pstrName,
&pOption->Translation);
VPackInvocation(pParserData,
&pPackedOption->Invocation,
&pOption->Invocation);
pPackedOption->dwUIConstraintList = pOption->dwConstraint;
//
// Check if the current option is the default option
// or if it's the None/False option
//
if (pFeature->pstrDefault &&
strcmp(pOption->pstrName, pFeature->pstrDefault) == EQUAL_STRING)
{
pPackedFeature->dwDefaultOptIndex = dwOptionIndex;
bIsDefaultOption = TRUE;
}
if (strcmp(pOption->pstrName, gstrNoneKwd) == EQUAL_STRING ||
strcmp(pOption->pstrName, gstrFalseKwd) == EQUAL_STRING)
{
pPackedFeature->dwNoneFalseOptIndex = dwOptionIndex;
}
//
// Handle extra fields after the generic OPTION structure
//
switch (pFeature->dwFeatureID)
{
case GID_PAGESIZE:
{
PPAGESIZE pPageSize = (PPAGESIZE) pPackedOption;
PPAPEROBJ pPaper = (PPAPEROBJ) pOption;
PRECT prect;
PSIZE psize;
if (strcmp(pOption->pstrName, gstrCustomSizeKwd) == EQUAL_STRING)
{
PPPDDATA pPpdData;
LONG lMax;
//
// Special case for CustomPageSize option
//
pPpdData = pParserData->pPpdData;
psize = &pPageSize->szPaperSize;
prect = &pPageSize->rcImgArea;
pPageSize->szPaperSize = pPaper->szDimension;
pPageSize->rcImgArea = pPaper->rcImageArea;
pPageSize->dwPaperSizeID = DMPAPER_CUSTOMSIZE;
VPackStringRsrc(pParserData,
&pPackedOption->loDisplayName,
IDS_PSCRIPT_CUSTOMSIZE);
//
// If either MaxMediaWidth or MaxMediaHeight is missing,
// we'll use the max width or height values from
// ParamCustomPageSize.
//
if (psize->cx <= 0)
psize->cx = MAXCUSTOMPARAM_WIDTH(pPpdData);
if (psize->cy <= 0)
psize->cy = MAXCUSTOMPARAM_HEIGHT(pPpdData);
if (psize->cx > 0 &&
psize->cy > 0 &&
MINCUSTOMPARAM_ORIENTATION(pPpdData) <= 3)
{
pParserData->pUIInfo->dwFlags |= FLAG_CUSTOMSIZE_SUPPORT;
pParserData->pUIInfo->dwCustomSizeOptIndex = dwOptionIndex;
//
// Make sure the hardware margins are not larger than
// the maximum media width or height.
//
// This is only significant for cut-sheet device.
//
if (pParserData->dwCustomSizeFlags & CUSTOMSIZE_CUTSHEET)
{
lMax = min(psize->cx, psize->cy);
if (prect->left < 0 || prect->left >= lMax)
prect->left = 0;
if (prect->right < 0 || prect->right >= lMax)
prect->right = 0;
if (prect->top < 0 || prect->top >= lMax)
prect->top = 0;
if (prect->bottom < 0 || prect->bottom >= lMax)
prect->bottom = 0;
}
//
// Validate custom page size parameters
//
if (MAXCUSTOMPARAM_WIDTH(pPpdData) > psize->cx)
MAXCUSTOMPARAM_WIDTH(pPpdData) = psize->cx;
if (MINCUSTOMPARAM_WIDTH(pPpdData) <= MICRONS_PER_INCH)
MINCUSTOMPARAM_WIDTH(pPpdData) = MICRONS_PER_INCH;
if (MAXCUSTOMPARAM_HEIGHT(pPpdData) > psize->cy)
MAXCUSTOMPARAM_HEIGHT(pPpdData) = psize->cy;
if (MINCUSTOMPARAM_HEIGHT(pPpdData) <= MICRONS_PER_INCH)
MINCUSTOMPARAM_HEIGHT(pPpdData) = MICRONS_PER_INCH;
}
}
else
{
psize = &pPaper->szDimension;
prect = &pPaper->rcImageArea;
if (strcmp(pOption->pstrName, gstrLetterSizeKwd) == EQUAL_STRING)
{
if ((abs(psize->cx - LETTER_PAPER_WIDTH) < 1000) &&
(abs(psize->cy - LETTER_PAPER_LENGTH) < 1000))
{
pParserData->pUIInfo->dwFlags |= FLAG_LETTER_SIZE_EXISTS;
}
}
else if (strcmp(pOption->pstrName, gstrA4SizeKwd) == EQUAL_STRING)
{
if ((abs(psize->cx - A4_PAPER_WIDTH) < 1000) &&
(abs(psize->cy - A4_PAPER_LENGTH) < 1000))
{
pParserData->pUIInfo->dwFlags |= FLAG_A4_SIZE_EXISTS;
}
}
//
// Verify paper dimension
//
if (psize->cx <= 0 || psize->cy <= 0)
{
SEMANTIC_ERROR(("Invalid PaperDimension for: %s\n",
pOption->pstrName));
psize->cx = DEFAULT_PAPER_WIDTH;
psize->cy = DEFAULT_PAPER_LENGTH;
}
pPageSize->szPaperSize = pPaper->szDimension;
//
// Verify imageable area
//
if (prect->left < 0 || prect->left >= prect->right ||
prect->bottom < 0|| prect->bottom >= prect->top ||
prect->right > psize->cx ||
prect->top > psize->cy)
{
SEMANTIC_ERROR(("Invalid ImageableArea for: %s\n",
pOption->pstrName));
prect->left = prect->bottom = 0;
prect->right = psize->cx;
prect->top = psize->cy;
}
//
// Convert from PS to GDI coordinate system
//
pPageSize->rcImgArea.left = prect->left;
pPageSize->rcImgArea.right = prect->right;
pPageSize->rcImgArea.top = psize->cy - prect->top;
pPageSize->rcImgArea.bottom = psize->cy - prect->bottom;
//
// Driver paper size ID starts at DRIVER_PAPERSIZE_ID
//
pPageSize->dwPaperSizeID = dwOptionIndex + DRIVER_PAPERSIZE_ID;
}
}
break;
case GID_RESOLUTION:
{
PRESOLUTION pResolution = (PRESOLUTION) pPackedOption;
PRESOBJ pResObj = (PRESOBJ) pOption;
PSTR pstr = pOption->pstrName;
LONG lXdpi, lYdpi;
BOOL bValid;
pResolution->iXdpi = pResolution->iYdpi = DEFAULT_RESOLUTION;
pResolution->fxScreenFreq = pResObj->fxScreenFreq;
pResolution->fxScreenAngle = pResObj->fxScreenAngle;
if (BGetIntegerFromString(&pstr, &lXdpi))
{
lYdpi = lXdpi;
while (*pstr && !IS_DIGIT(*pstr))
pstr++;
if ((*pstr == NUL || BGetIntegerFromString(&pstr, &lYdpi)) &&
(lXdpi > 0 && lXdpi <= MAX_SHORT) &&
(lYdpi > 0 && lYdpi <= MAX_SHORT))
{
pResolution->iXdpi = (INT) lXdpi;
pResolution->iYdpi = (INT) lYdpi;
bValid = TRUE;
}
}
if (! bValid)
SEMANTIC_ERROR(("Invalid resolution option: %s\n", pOption->pstrName));
}
break;
case GID_DUPLEX:
{
PDUPLEX pDuplex = (PDUPLEX) pPackedOption;
if (strcmp(pOption->pstrName, gstrDuplexTumble) == EQUAL_STRING)
{
//
// Horizontal == ShortEdge == Tumble
//
pDuplex->dwDuplexID = DMDUP_HORIZONTAL;
}
else if (strcmp(pOption->pstrName, gstrDuplexNoTumble) == EQUAL_STRING)
{
//
// Vertical == LongEdge == NoTumble
//
pDuplex->dwDuplexID = DMDUP_VERTICAL;
}
else
pDuplex->dwDuplexID = DMDUP_SIMPLEX;
}
break;
case GID_COLLATE:
{
PCOLLATE pCollate = (PCOLLATE) pPackedOption;
pCollate->dwCollateID =
(strcmp(pOption->pstrName, gstrTrueKwd) == EQUAL_STRING ||
strcmp(pOption->pstrName, gstrOnKwd) == EQUAL_STRING) ?
DMCOLLATE_TRUE :
DMCOLLATE_FALSE;
}
break;
case GID_MEDIATYPE:
((PMEDIATYPE) pPackedOption)->dwMediaTypeID = dwOptionIndex + DMMEDIA_USER;
break;
case GID_INPUTSLOT:
{
PINPUTSLOT pInputSlot = (PINPUTSLOT) pPackedOption;
PTRAYOBJ pTray = (PTRAYOBJ) pOption;
DWORD dwReqPageRgn;
if ((dwReqPageRgn = pTray->dwReqPageRgn) == REQRGN_UNKNOWN)
dwReqPageRgn = pParserData->dwReqPageRgn;
if (dwReqPageRgn != REQRGN_FALSE)
pInputSlot->dwFlags |= INPUTSLOT_REQ_PAGERGN;
//
// Special handling of predefined input slots:
// ManualFeed and AutoSelect
//
switch (pTray->dwTrayIndex)
{
case DMBIN_FORMSOURCE:
pInputSlot->dwPaperSourceID = pTray->dwTrayIndex;
break;
case DMBIN_MANUAL:
pInputSlot->dwPaperSourceID = pTray->dwTrayIndex;
VPackStringRsrc(pParserData,
&pPackedOption->loDisplayName,
IDS_TRAY_MANUALFEED);
break;
default:
pInputSlot->dwPaperSourceID = dwOptionIndex + DMBIN_USER;
break;
}
}
break;
case GID_OUTPUTBIN:
{
PBINOBJ pBinObj = (PBINOBJ) pOption;
//
// if this is the default bin, set the default output order, if specified
// by the DefaultOutputOrder entry in the PPD-file
//
if (bIsDefaultOption && pParserData->bDefOutputOrderSet)
{
//
// If multiple bins: warn if different options specified
//
if ((dwCount > 1) &&
(pBinObj->bReversePrint != pParserData->bDefReversePrint))
{
TERSE(("Warning: explicit *DefaultPageOrder overwrites PageStackOrder of OutputBin\n"));
}
((POUTPUTBIN) pPackedOption)->bOutputOrderReversed = pParserData->bDefReversePrint;
}
else
{
//
// for non-default bins, the default output order has no effect - the PPD spec says
// "*DefaultOutputOrder indicates the default stacking order of the default output bin."
//
((POUTPUTBIN) pPackedOption)->bOutputOrderReversed = pBinObj->bReversePrint;
}
}
break;
case GID_MEMOPTION:
{
PMEMOPTION pMemOption = (PMEMOPTION) pPackedOption;
PMEMOBJ pMemObj = (PMEMOBJ) pOption;
DWORD dwMinFreeMem;
//
// Store PPD's original *VMOption value into dwInstalledMem.
// This is only used for the new PPD helper function GetOptionAttribute().
// (see comments in inc\parser.h)
//
pMemOption->dwInstalledMem = pMemObj->dwFreeVM;
dwMinFreeMem = pParserData->dwLangLevel <= 1 ? MIN_FREEMEM_L1 : MIN_FREEMEM_L2;
if (pMemObj->dwFreeVM < dwMinFreeMem)
{
SEMANTIC_ERROR(("Invalid memory option: %s\n", pOption->pstrName));
pMemObj->dwFreeVM = dwMinFreeMem;
}
pMemOption->dwFreeMem = pMemObj->dwFreeVM;
pMemOption->dwFreeFontMem = pMemObj->dwFontMem;
}
break;
case GID_LEADINGEDGE:
if (strcmp(pOption->pstrName, gstrLongKwd) == EQUAL_STRING)
{
pParserData->pPpdData->dwLeadingEdgeLong = dwOptionIndex;
if (dwOptionIndex == pPackedFeature->dwDefaultOptIndex)
pParserData->pPpdData->dwCustomSizeFlags &= ~CUSTOMSIZE_SHORTEDGEFEED;
}
else if (strcmp(pOption->pstrName, gstrShortKwd) == EQUAL_STRING)
{
pParserData->pPpdData->dwLeadingEdgeShort = dwOptionIndex;
if (dwOptionIndex == pPackedFeature->dwDefaultOptIndex)
pParserData->pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_SHORTEDGEFEED;
}
break;
case GID_USEHWMARGINS:
if (strcmp(pOption->pstrName, gstrTrueKwd) == EQUAL_STRING)
{
pParserData->pPpdData->dwUseHWMarginsTrue = dwOptionIndex;
pParserData->pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_CUTSHEET;
if (dwOptionIndex == pPackedFeature->dwDefaultOptIndex)
pParserData->pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_DEFAULTCUTSHEET;
}
else if (strcmp(pOption->pstrName, gstrFalseKwd) == EQUAL_STRING)
{
pParserData->pPpdData->dwUseHWMarginsFalse = dwOptionIndex;
pParserData->pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_ROLLFED;
if (dwOptionIndex == pPackedFeature->dwDefaultOptIndex)
pParserData->pPpdData->dwCustomSizeFlags &= ~CUSTOMSIZE_DEFAULTCUTSHEET;
}
break;
}
pPackedOption = (POPTION) ((PBYTE) pPackedOption + pFeatureData->dwOptionSize);
}
}
}
VOID
VPackNt4Mapping(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack NT4 feature index mapping information
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PPPDDATA pPpdData;
PFEATURE pPackedFeatures;
PBYTE pubNt4Mapping;
DWORD dwCount, dwIndex, dwNt4Index;
INT iInputSlotIndex;
BYTE ubInputSlotOld, ubInputSlotNew;
pPpdData = pParserData->pPpdData;
pPpdData->dwNt4Checksum = pParserData->wNt4Checksum;
pPpdData->dwNt4DocFeatures = pParserData->pUIInfo->dwDocumentFeatures;
pPpdData->dwNt4PrnFeatures = pParserData->pUIInfo->dwPrinterFeatures;
iInputSlotIndex = -1;
ubInputSlotNew = 0xff;
if (pParserData->iDefInstallMemIndex >= 0)
pParserData->iDefInstallMemIndex += pPpdData->dwNt4DocFeatures;
dwCount = pPpdData->dwNt4DocFeatures + pPpdData->dwNt4PrnFeatures;
pPpdData->Nt4Mapping.dwCount = dwCount;
VGrowPackBuffer(pParserData, dwCount * sizeof(BYTE));
pubNt4Mapping = (PBYTE) (pParserData->pubBufStart + pParserData->dwBufSize);
pPpdData->Nt4Mapping.loOffset = pParserData->dwBufSize;
pParserData->dwBufSize += DWORD_ALIGN(dwCount * sizeof(BYTE));
pPackedFeatures = (PFEATURE) (pParserData->pubBufStart + pParserData->pUIInfo->loFeatureList);
for (dwIndex=dwNt4Index=0; dwIndex <= dwCount; dwIndex++)
{
BOOL bMapped = TRUE;
//
// ManualFeed used to be a feature in NT4,
// but not anymore in NT5
//
if (pParserData->iReqPageRgnIndex == (INT) dwIndex)
ubInputSlotNew = (BYTE) dwNt4Index;
if (pParserData->iManualFeedIndex == (INT) dwIndex)
{
pPpdData->dwNt4DocFeatures++;
dwNt4Index++;
}
//
// DefaultInstalledMemory causes a bogus feature to be added on NT4
//
if (pParserData->iDefInstallMemIndex == (INT) dwIndex)
{
pPpdData->dwNt4PrnFeatures++;
dwNt4Index++;
}
if (dwIndex == dwCount)
break;
switch (pPackedFeatures[dwIndex].dwFeatureID)
{
case GID_MEDIATYPE:
case GID_OUTPUTBIN:
// a feature in NT4 only if within Open/CloseUI
if (pParserData->aubOpenUIFeature[pPackedFeatures[dwIndex].dwFeatureID])
break;
// fall through
case GID_PAGEREGION:
case GID_LEADINGEDGE:
case GID_USEHWMARGINS:
// not a feature in NT4
bMapped = FALSE;
break;
case GID_INPUTSLOT:
iInputSlotIndex = dwIndex;
break;
}
if (bMapped)
{
pubNt4Mapping[dwIndex] = (BYTE) dwNt4Index;
dwNt4Index++;
}
else
{
pPpdData->dwNt4DocFeatures--;
pubNt4Mapping[dwIndex] = 0xff;
}
}
//
// RequiresPageRegion causes InputSlot feature to be created on NT4
//
if (iInputSlotIndex >= 0 && pParserData->iReqPageRgnIndex >= 0)
{
ubInputSlotOld = pubNt4Mapping[iInputSlotIndex];
if (ubInputSlotOld > ubInputSlotNew)
{
for (dwIndex=0; dwIndex < dwCount; dwIndex++)
{
if (pubNt4Mapping[dwIndex] >= ubInputSlotNew &&
pubNt4Mapping[dwIndex] < ubInputSlotOld)
{
pubNt4Mapping[dwIndex]++;
}
}
}
else if (ubInputSlotOld < ubInputSlotNew)
{
for (dwIndex=0; dwIndex < dwCount; dwIndex++)
{
if (pubNt4Mapping[dwIndex] > ubInputSlotOld &&
pubNt4Mapping[dwIndex] <= ubInputSlotNew)
{
pubNt4Mapping[dwIndex]--;
}
}
}
pubNt4Mapping[iInputSlotIndex] = ubInputSlotNew;
}
}
VOID
VPackDeviceFonts(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack device font information into binary data
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PDEVFONT pDevFont;
PFONTREC pFontObj;
DWORD dwIndex, dwFonts;
VALIDATE_PARSER_DATA(pParserData);
//
// Count the number of device fonts and
// reserve enough space in the packed binary data
//
if ((dwFonts = DwCountListItem(pParserData->pFonts)) == 0)
return;
VGrowPackBuffer(pParserData, dwFonts * sizeof(DEVFONT));
pParserData->pPpdData->DeviceFonts.dwCount = dwFonts;
pParserData->pPpdData->DeviceFonts.loOffset = pParserData->dwBufSize;
pDevFont = (PDEVFONT) (pParserData->pubBufStart + pParserData->dwBufSize);
pParserData->dwBufSize += DWORD_ALIGN(dwFonts * sizeof(DEVFONT));
//
// Pack information about each device font
//
for (pFontObj = pParserData->pFonts;
pFontObj != NULL;
pFontObj = pFontObj->pNext)
{
VPackStringAnsi(pParserData, &pDevFont->loFontName, pFontObj->pstrName);
VPackStringXlation(pParserData,
&pDevFont->loDisplayName,
pFontObj->pstrName,
&pFontObj->Translation);
VPackStringAnsi(pParserData, &pDevFont->loEncoding, pFontObj->pstrEncoding);
VPackStringAnsi(pParserData, &pDevFont->loCharset, pFontObj->pstrCharset);
VPackStringAnsi(pParserData, &pDevFont->loVersion, pFontObj->pstrVersion);
pDevFont->dwStatus = pFontObj->dwStatus;
pDevFont++;
}
//
// Calculate the byte-offset to the default DEVFONT structure (if any)
//
if (pParserData->pstrDefaultFont &&
PvFindListItem(pParserData->pFonts, pParserData->pstrDefaultFont, &dwIndex))
{
pParserData->pPpdData->loDefaultFont = pParserData->pPpdData->DeviceFonts.loOffset +
(dwIndex * sizeof(DEVFONT));
}
}
VOID
VPackJobPatchFiles(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack *JobPatchFile information into binary data
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PJOBPATCHFILE pPackedPatch;
PJOBPATCHFILEOBJ pJobPatchFile;
DWORD dwJobPatchFiles;
VALIDATE_PARSER_DATA(pParserData);
//
// Count the number of *JobPatchFile entries
//
dwJobPatchFiles = DwCountListItem((PVOID) pParserData->pJobPatchFiles);
if (dwJobPatchFiles > 0)
{
//
// Reserve enough space in the packed binary data
//
VGrowPackBuffer(pParserData, dwJobPatchFiles * sizeof(JOBPATCHFILE));
pParserData->pPpdData->JobPatchFiles.dwCount = dwJobPatchFiles;
pParserData->pPpdData->JobPatchFiles.loOffset = pParserData->dwBufSize;
pPackedPatch = (PJOBPATCHFILE) (pParserData->pubBufStart + pParserData->dwBufSize);
pParserData->dwBufSize += DWORD_ALIGN(dwJobPatchFiles * sizeof(JOBPATCHFILE));
//
// Pack each *JobPatchFile invocation string
//
for (pJobPatchFile = pParserData->pJobPatchFiles;
pJobPatchFile != NULL;
pJobPatchFile = pJobPatchFile->pNext)
{
VPackPatch(pParserData, pPackedPatch, pJobPatchFile);
pPackedPatch++;
}
}
}
typedef struct _TTFSUBSTRESINFO
{
BOOL bCJK;
WORD wIDBegin;
WORD wIDEnd;
}
TTFSUBSTRESINFO;
static TTFSUBSTRESINFO TTFSubstResInfo[] =
{
{ FALSE, IDS_1252_BEGIN, IDS_1252_END},
{ TRUE, IDS_932_BEGIN, IDS_932_END},
{ TRUE, IDS_936_BEGIN, IDS_936_END},
{ TRUE, IDS_949_BEGIN, IDS_949_END},
};
VOID
VPackDefaultTrueTypeSubstTable(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack the default TrueType font substitution table into the binary data
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
#define MAX_FONT_NAME 256
{
INT iNumInfo, iInfo, iCount, iLenTT, iLenPS, i;
DWORD dwSize, dwLeft, dw;
TCHAR tchBuf[MAX_FONT_NAME];
PTSTR ptstrTable;
HRSRC hrRcData;
HGLOBAL hgRcData;
PWORD pwRcData;
VALIDATE_PARSER_DATA(pParserData);
//
// Calculate how much memory we need to hold the default TrueType to
// PostScript substitution names. The counter is initialized to 1, instead
// of 0, for the last NUL terminator. Count the names from the STRING
// resource, then from RCDATA resource.
//
//
dwSize = 1;
iNumInfo = sizeof(TTFSubstResInfo) / sizeof(TTFSUBSTRESINFO);
for (iInfo = 0; iInfo < iNumInfo; iInfo++)
{
iCount = TTFSubstResInfo[iInfo].wIDEnd - TTFSubstResInfo[iInfo].wIDBegin + 1;
for (i = 0; i < iCount; i++)
{
iLenTT = LoadString(ghInstance,
TTFSubstResInfo[iInfo].wIDBegin + i,
tchBuf, MAX_FONT_NAME);
if (iLenTT == 0)
{
ERR(("VPackDefaultTrueTypeSubstTable: load TT string failed: %d\n", GetLastError()));
return;
}
iLenPS = LoadString(ghInstance,
TTFSubstResInfo[iInfo].wIDBegin + i + TT2PS_INTERVAL,
tchBuf, MAX_FONT_NAME);
if (iLenPS == 0)
{
ERR(("VPackDefaultTrueTypeSubstTable: load PS string failed: %d\n", GetLastError()));
return;
}
dwSize += (iLenTT + 1) + (iLenPS + 1);
if (TTFSubstResInfo[iInfo].bCJK == TRUE)
{
// We need names beginning with '@' too for CJK.
dwSize += (1 + iLenTT + 1) + (1 + iLenPS + 1);
}
}
if (TTFSubstResInfo[iInfo].bCJK == TRUE)
{
hrRcData = FindResource(ghInstance, (LPCTSTR)TTFSubstResInfo[iInfo].wIDBegin, RT_RCDATA);
if (hrRcData == NULL)
{
ERR(("VPackDefaultTrueTypeSubstTable: find RCDATA failed: %d\n", GetLastError()));
return;
}
// Load the resource and get its size.
hgRcData = LoadResource(ghInstance, hrRcData);
if (hgRcData == NULL)
{
ERR(("VPackDefaultTrueTypeSubstTable: load RCDATA failed: %d\n", GetLastError()));
return;
}
// The first WORD of the IDR resource tells the size of the strings.
pwRcData = (PWORD)LockResource(hgRcData);
if (pwRcData == NULL)
{
ERR(("VPackDefaultTrueTypeSubstTable: lock RCDATA failed: %d\n", GetLastError()));
return;
}
dw = *pwRcData;
if (dw % 2)
{
ERR(("VPackDefaultTrueTypeSubstTable: RCDATA size is odd.\n"));
return;
}
dwSize += dw / 2;
}
}
//
// Reserve enough space in the packed binary data
//
dwSize *= sizeof(TCHAR);
VGrowPackBuffer(pParserData, dwSize);
ptstrTable = (PTSTR) (pParserData->pubBufStart + pParserData->dwBufSize);
pParserData->pUIInfo->loFontSubstTable = pParserData->dwBufSize;
pParserData->pUIInfo->dwFontSubCount = dwSize;
pParserData->dwBufSize += DWORD_ALIGN(dwSize);
//
// Save the default substitution table in the binary data
//
dwLeft = dwSize;
for (iInfo = 0; iInfo < iNumInfo; iInfo++)
{
iCount = TTFSubstResInfo[iInfo].wIDEnd - TTFSubstResInfo[iInfo].wIDBegin + 1;
for (i = 0; i < iCount; i++)
{
iLenTT = LoadString(ghInstance,
TTFSubstResInfo[iInfo].wIDBegin + i,
ptstrTable, dwLeft);
if (iLenTT == 0)
{
ERR(("VPackDefaultTrueTypeSubstTable: load TT string failed: %d\n", GetLastError()));
goto fail_cleanup;
}
ptstrTable += iLenTT + 1;
dwLeft -= (iLenTT + 1) * sizeof (TCHAR);
iLenPS = LoadString(ghInstance,
TTFSubstResInfo[iInfo].wIDBegin + i + TT2PS_INTERVAL,
ptstrTable, dwLeft);
if (iLenPS == 0)
{
ERR(("VPackDefaultTrueTypeSubstTable: load PS string failed: %d\n", GetLastError()));
goto fail_cleanup;
}
ptstrTable += iLenPS + 1;
dwLeft -= (iLenPS + 1) * sizeof (TCHAR);
if (TTFSubstResInfo[iInfo].bCJK == TRUE)
{
// We need names beginning with '@' too for CJK.
*ptstrTable++ = L'@';
dwLeft -= sizeof (TCHAR);
if (!LoadString(ghInstance, TTFSubstResInfo[iInfo].wIDBegin + i,
ptstrTable, dwLeft))
{
ERR(("VPackDefaultTrueTypeSubstTable: load TT string failed: %d\n", GetLastError()));
goto fail_cleanup;
}
ptstrTable += iLenTT + 1;
dwLeft -= (iLenTT + 1) * sizeof (TCHAR);
*ptstrTable++ = L'@';
dwLeft -= sizeof (TCHAR);
if (!LoadString(ghInstance, TTFSubstResInfo[iInfo].wIDBegin + i + TT2PS_INTERVAL,
ptstrTable, dwLeft))
{
ERR(("VPackDefaultTrueTypeSubstTable: load PS string failed: %d\n", GetLastError()));
goto fail_cleanup;
}
ptstrTable += iLenPS + 1;
dwLeft -= (iLenPS + 1) * sizeof (TCHAR);
}
}
if (TTFSubstResInfo[iInfo].bCJK == TRUE)
{
hrRcData = FindResource(ghInstance, (LPCTSTR)TTFSubstResInfo[iInfo].wIDBegin, RT_RCDATA);
if (hrRcData == NULL)
{
ERR(("VPackDefaultTrueTypeSubstTable: find RCDATA failed: %d\n", GetLastError()));
goto fail_cleanup;
}
hgRcData = LoadResource(ghInstance, hrRcData);
if (hgRcData == NULL)
{
ERR(("VPackDefaultTrueTypeSubstTable: load RCDATA failed: %d\n", GetLastError()));
goto fail_cleanup;
}
pwRcData = (PWORD)LockResource(hgRcData);
if (pwRcData == NULL)
{
ERR(("VPackDefaultTrueTypeSubstTable: lock RCDATA failed: %d\n", GetLastError()));
goto fail_cleanup;
}
dw = *pwRcData++;
if (dw % 2)
{
ERR(("VPackDefaultTrueTypeSubstTable: RCDATA size is odd.\n"));
goto fail_cleanup;
}
memcpy(ptstrTable, pwRcData, dw);
ptstrTable += dw / 2;
dwLeft -= dw;
}
}
//
// Succeed
//
return;
//
// Fail
//
fail_cleanup:
pParserData->pUIInfo->loFontSubstTable = 0;
pParserData->pUIInfo->dwFontSubCount = 0;
}
VOID
VPackTrueTypeSubstTable(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack the TrueType font substitution table into the binary data
Arguments:
pParserData - Points to the parser data structure
Return Value:
NONE
--*/
{
PTTFONTSUB pTTFontSub;
DWORD dwSize;
PTSTR ptstrTable, ptstrStart;
//
// Figure out how much space we'll need to store the font substitution table.
// This is an estimate and may be a little higher than what we actually need.
//
ASSERT(pParserData->pTTFontSubs != NULL);
for (pTTFontSub = pParserData->pTTFontSubs, dwSize = 1;
pTTFontSub != NULL;
pTTFontSub = pTTFontSub->pNext)
{
if (pTTFontSub->Translation.dwLength)
dwSize += pTTFontSub->Translation.dwLength + 1;
else
dwSize += strlen(pTTFontSub->pstrName) + 1;
dwSize += pTTFontSub->PSName.dwLength + 1;
}
//
// Reserve enough space in the packed binary data
//
dwSize *= sizeof(TCHAR);
VGrowPackBuffer(pParserData, dwSize);
ptstrStart = ptstrTable = (PTSTR) (pParserData->pubBufStart + pParserData->dwBufSize);
pParserData->pUIInfo->loFontSubstTable = pParserData->dwBufSize;
pParserData->dwBufSize += DWORD_ALIGN(dwSize);
for (pTTFontSub = pParserData->pTTFontSubs;
pTTFontSub != NULL;
pTTFontSub = pTTFontSub->pNext)
{
INT iChars;
//
// TrueType font family name
//
if (pTTFontSub->Translation.dwLength)
{
iChars = ITranslateToUnicodeString(
ptstrTable,
pTTFontSub->Translation.pvData,
pTTFontSub->Translation.dwLength,
pParserData->uCodePage);
}
else
{
iChars = ITranslateToUnicodeString(
ptstrTable,
pTTFontSub->pstrName,
strlen(pTTFontSub->pstrName),
1252);
}
if (iChars <= 0)
break;
ptstrTable += iChars + 1;
//
// PS font family name
//
iChars = ITranslateToUnicodeString(
ptstrTable,
pTTFontSub->PSName.pvData,
pTTFontSub->PSName.dwLength,
pParserData->uCodePage);
if (iChars <= 0)
break;
ptstrTable += iChars + 1;
}
if (pTTFontSub != NULL)
{
ERR(("Error packing font substitution table\n"));
ptstrTable = ptstrStart;
}
*ptstrTable++ = NUL;
pParserData->pUIInfo->dwFontSubCount = (DWORD)(ptstrTable - ptstrStart) * sizeof(TCHAR);
}
VOID
VPackFileDateInfo(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack source PPD filenames and dates
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
PRAWBINARYDATA pRawData;
DWORD dwCount;
PFILEDATEINFO pFileDateInfo;
PTSTR ptstrFullname;
PLISTOBJ pItem;
HANDLE hFile;
pRawData = &pParserData->pInfoHdr->RawData;
dwCount = DwCountListItem(pParserData->pPpdFileNames);
if (pRawData->FileDateInfo.dwCount = dwCount)
{
VGrowPackBuffer(pParserData, dwCount * sizeof(FILEDATEINFO));
pRawData->FileDateInfo.loOffset = pParserData->dwBufSize;
pFileDateInfo = (PFILEDATEINFO) (pParserData->pubBufStart + pParserData->dwBufSize);
pParserData->dwBufSize += DWORD_ALIGN(dwCount * sizeof(FILEDATEINFO));
for (pItem = pParserData->pPpdFileNames; pItem; pItem = pItem->pNext)
{
dwCount--;
ptstrFullname = (PTSTR) pItem->pstrName;
VPackStringUnicode(pParserData,
&pFileDateInfo[dwCount].loFileName,
ptstrFullname);
hFile = CreateFile(ptstrFullname,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
NULL);
if ((hFile == INVALID_HANDLE_VALUE) ||
!GetFileTime(hFile, NULL, NULL, &pFileDateInfo[dwCount].FileTime))
{
ERR(("GetFileTime '%ws' failed: %d\n", ptstrFullname, GetLastError()));
GetSystemTimeAsFileTime(&pFileDateInfo[dwCount].FileTime);
}
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
}
}
}
VOID
VMapLangEncodingToCodePage(
PPARSERDATA pParserData
)
/*++
Routine Description:
Map LanguageEncoding to code page
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
UINT uCodePage = CP_ACP;
CPINFO cpinfo;
switch (pParserData->dwLangEncoding)
{
case LANGENC_ISOLATIN1:
uCodePage = 1252;
break;
case LANGENC_JIS83_RKSJ:
uCodePage = 932;
break;
case LANGENC_UNICODE:
uCodePage = CP_UNICODE;
break;
case LANGENC_NONE:
break;
default:
RIP(("Unknown language encoding: %d\n", pParserData->dwLangEncoding));
break;
}
//
// Make sure the requested code page is available
//
if (uCodePage != CP_UNICODE &&
uCodePage != CP_ACP &&
!GetCPInfo(uCodePage, &cpinfo))
{
WARNING(("Code page %d is not available\n", uCodePage));
uCodePage = CP_ERROR;
}
pParserData->uCodePage = uCodePage;
}
BOOL
BPackBinaryData(
PPARSERDATA pParserData
)
/*++
Routine Description:
Pack the parsed PPD information into binary format
Arguments:
pParserData - Points to parser data structure
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
DWORD dwSize;
DWORD dwMinFreeMem;
BOOL bResult = FALSE;
VALIDATE_PARSER_DATA(pParserData);
__try
{
//
// Quick-access pointers to various data structures.
//
PINFOHEADER pInfoHdr;
PUIINFO pUIInfo;
PPPDDATA pPpdData;
//
// Pack fixed header data structures
//
dwSize = sizeof(INFOHEADER) + sizeof(UIINFO) + sizeof(PPDDATA);
VGrowPackBuffer(pParserData, dwSize);
pParserData->dwBufSize = DWORD_ALIGN(dwSize);
pInfoHdr = pParserData->pInfoHdr;
pUIInfo = pParserData->pUIInfo;
pPpdData = pParserData->pPpdData;
pInfoHdr->RawData.dwParserSignature = PPD_PARSER_SIGNATURE;
pInfoHdr->RawData.dwParserVersion = PPD_PARSER_VERSION;
#if 0
pInfoHdr->RawData.dwChecksum32 = pParserData->dwChecksum32;
#endif
pInfoHdr->loUIInfoOffset = sizeof(INFOHEADER);
pInfoHdr->loDriverOffset = sizeof(INFOHEADER) + sizeof(UIINFO);
//
// Pack source PPD filenames and dates
//
VPackFileDateInfo(pParserData);
//
// Perform a few miscellaneous checks
//
if (pParserData->pOpenFeature)
SEMANTIC_ERROR(("Missing CloseUI for: %s\n", pParserData->pOpenFeature->pstrName));
if (pParserData->bInstallableGroup)
SEMANTIC_ERROR(("Missing CloseGroup: InstallableOptions\n"));
if (pParserData->NickName.dwLength == 0)
SEMANTIC_ERROR(("Missing *NickName and *ShortNickName entry\n"));
if (pParserData->Product.dwLength == 0)
SEMANTIC_ERROR(("Missing *Product entry\n"));
if (pParserData->dwSpecVersion == 0)
SEMANTIC_ERROR(("Missing *PPD-Adobe and *FormatVersion entry\n"));
if (pParserData->dwLangLevel == 0)
{
SEMANTIC_ERROR(("Missing *LanguageLevel entry\n"));
pParserData->dwLangLevel = 1;
}
dwMinFreeMem = pParserData->dwLangLevel <= 1 ? MIN_FREEMEM_L1 : MIN_FREEMEM_L2;
if (pParserData->dwFreeMem < dwMinFreeMem)
{
SEMANTIC_ERROR(("Invalid *FreeVM entry\n"));
pParserData->dwFreeMem = dwMinFreeMem;
}
//
// Map LanguageEncoding to code page
//
VMapLangEncodingToCodePage(pParserData);
//
// Count the number of doc- and printer-sticky features
// and sort them into two separate groups
//
VCountAndSortPrinterFeatures(pParserData);
//
// Fill out fields in the UIINFO structure
//
pUIInfo->dwSize = sizeof(UIINFO);
pUIInfo->dwDocumentFeatures = pInfoHdr->RawData.dwDocumentFeatures;
pUIInfo->dwPrinterFeatures = pInfoHdr->RawData.dwPrinterFeatures;
pUIInfo->dwTechnology = DT_RASPRINTER;
pUIInfo->dwMaxCopies = MAX_COPIES;
pUIInfo->dwMinScale = MIN_SCALE;
pUIInfo->dwMaxScale = MAX_SCALE;
pUIInfo->dwSpecVersion = pParserData->dwSpecVersion;
pUIInfo->dwLangEncoding = pParserData->dwLangEncoding;
pUIInfo->dwLangLevel = pParserData->dwLangLevel;
pUIInfo->dwPrintRate = pUIInfo->dwPrintRatePPM = pParserData->dwThroughput;
#ifndef WINNT_40
pUIInfo->dwPrintRateUnit = PRINTRATEUNIT_PPM;
#endif
//
// Note: We assume all printers can support binary protocol
//
pUIInfo->dwProtocols = pParserData->dwProtocols | PROTOCOL_BINARY;
pUIInfo->dwJobTimeout = pParserData->dwJobTimeout;
pUIInfo->dwWaitTimeout = pParserData->dwWaitTimeout;
pUIInfo->dwTTRasterizer = pParserData->dwTTRasterizer;
pUIInfo->dwFreeMem = pParserData->dwFreeMem;
pUIInfo->fxScreenAngle = pParserData->fxScreenAngle;
pUIInfo->fxScreenFreq = pParserData->fxScreenFreq;
pUIInfo->dwCustomSizeOptIndex = OPTION_INDEX_ANY;
pPpdData->dwPpdFilever = pParserData->dwPpdFilever;
pPpdData->dwFlags = pParserData->dwPpdFlags;
//
// Our internal unit is microns, thus 25400 units per inch.
//
pUIInfo->ptMasterUnits.x =
pUIInfo->ptMasterUnits.y = 25400;
pUIInfo->dwFlags = FLAG_FONT_DOWNLOADABLE |
FLAG_ORIENT_SUPPORT;
if (pParserData->dwColorDevice)
pUIInfo->dwFlags |= FLAG_COLOR_DEVICE;
if (pParserData->dwLSOrientation != LSO_MINUS90)
pUIInfo->dwFlags |= FLAG_ROTATE90;
if (PvFindListItem(pParserData->pFeatures, "StapleLocation", NULL) ||
PvFindListItem(pParserData->pFeatures, "StapleX", NULL) &&
PvFindListItem(pParserData->pFeatures, "StapleY", NULL))
{
pUIInfo->dwFlags |= FLAG_STAPLE_SUPPORT;
}
if (pParserData->bDefReversePrint)
pUIInfo->dwFlags |= FLAG_REVERSE_PRINT;
if (pParserData->dwLangLevel > 1)
{
if (pParserData->bEuroInformationSet)
{
if (!pParserData->bHasEuro)
pUIInfo->dwFlags |= FLAG_ADD_EURO;
}
else if (pParserData->dwPSVersion < 3011)
pUIInfo->dwFlags |= FLAG_ADD_EURO;
}
if (pParserData->bTrueGray)
pUIInfo->dwFlags |= FLAG_TRUE_GRAY;
VPackStringAnsiToUnicode(
pParserData,
&pUIInfo->loNickName,
pParserData->NickName.pvData,
pParserData->NickName.dwLength);
//
// Pack symbol definitions and resolve symbol references
//
VPackSymbolDefinitions(pParserData);
VResolveSymbolReferences(pParserData);
VPackInvocation(pParserData, &pUIInfo->Password, &pParserData->Password);
VPackInvocation(pParserData, &pUIInfo->ExitServer, &pParserData->ExitServer);
//
// Copy and validate custom page size parameters
//
pPpdData->dwUseHWMarginsTrue =
pPpdData->dwUseHWMarginsFalse =
pPpdData->dwLeadingEdgeLong =
pPpdData->dwLeadingEdgeShort = OPTION_INDEX_ANY;
pPpdData->dwCustomSizeFlags = pParserData->dwCustomSizeFlags;
CopyMemory(pPpdData->CustomSizeParams,
pParserData->CustomSizeParams,
sizeof(pPpdData->CustomSizeParams));
//
// Process the printer features and handle any special glitches
//
VProcessPrinterFeatures(pParserData);
//
// Pack UIConstraints information
//
VPackUIConstraints(pParserData);
//
// Pack OrderDependency and QueryOrderDependency information
//
VPackOrderDependency(pParserData, &pPpdData->OrderDeps, pParserData->pOrderDep);
VPackOrderDependency(pParserData, &pPpdData->QueryOrderDeps, pParserData->pQueryOrderDep);
//
// Pack printer features and options
//
VPackPrinterFeatures(pParserData);
//
// Fill out fields in PPDDATA structure
//
pPpdData->dwSizeOfStruct = sizeof(PPDDATA);
pPpdData->dwExtensions = pParserData->dwExtensions;
pPpdData->dwSetResType = pParserData->dwSetResType;
pPpdData->dwPSVersion = pParserData->dwPSVersion;
//
// Scan the document-sticky feature list to check if "OutputOrder" is available.
// If it is, remember its feature index, which will be used by UI code.
//
{
PFEATURE pFeature;
DWORD dwIndex;
PCSTR pstrKeywordName;
pPpdData->dwOutputOrderIndex = INVALID_FEATURE_INDEX;
pFeature = OFFSET_TO_POINTER(pInfoHdr, pUIInfo->loFeatureList);
ASSERT(pFeature != NULL);
for (dwIndex = 0; dwIndex < pUIInfo->dwDocumentFeatures; dwIndex++, pFeature++)
{
if ((pstrKeywordName = OFFSET_TO_POINTER(pInfoHdr, pFeature->loKeywordName)) &&
strcmp(pstrKeywordName, "OutputOrder") == EQUAL_STRING)
{
pPpdData->dwOutputOrderIndex = dwIndex;
break;
}
}
}
VPackInvocation(pParserData, &pPpdData->PSVersion, &pParserData->PSVersion);
VPackInvocation(pParserData, &pPpdData->Product, &pParserData->Product);
if (SUPPORT_CUSTOMSIZE(pUIInfo))
{
//
// If neither roll-fed nor cut-sheet flag is set, assume to be roll-fed
//
if (! (pPpdData->dwCustomSizeFlags & (CUSTOMSIZE_CUTSHEET|CUSTOMSIZE_ROLLFED)))
pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_ROLLFED;
//
// If roll-fed flag is not set, default must be cut-sheet
//
if (! (pPpdData->dwCustomSizeFlags & CUSTOMSIZE_ROLLFED))
pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_DEFAULTCUTSHEET;
}
VPackInvocation(pParserData, &pPpdData->PatchFile, &pParserData->PatchFile);
VPackInvocation(pParserData, &pPpdData->JclBegin, &pParserData->JclBegin);
VPackInvocation(pParserData, &pPpdData->JclEnterPS, &pParserData->JclEnterPS);
VPackInvocation(pParserData, &pPpdData->JclEnd, &pParserData->JclEnd);
VPackInvocation(pParserData, &pPpdData->ManualFeedFalse, &pParserData->ManualFeedFalse);
//
// Pack NT4 feature index mapping information
//
VPackNt4Mapping(pParserData);
//
// Pack device font information
//
VPackDeviceFonts(pParserData);
//
// Pack JobPatchFile information
//
VPackJobPatchFiles(pParserData);
//
// Pack default TrueType font substitution table
//
if (pParserData->pTTFontSubs == NULL || pParserData->uCodePage == CP_ERROR)
VPackDefaultTrueTypeSubstTable(pParserData);
else
VPackTrueTypeSubstTable(pParserData);
pInfoHdr->RawData.dwFileSize = pParserData->dwBufSize;
bResult = TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
ERR(("PackBinaryData failed.\n"));
}
return bResult;
}
BOOL
BSaveBinaryDataToFile(
PPARSERDATA pParserData,
PTSTR ptstrPpdFilename
)
/*++
Routine Description:
Cache the binary PPD data in a file
Arguments:
pParserData - Points to parser data structure
ptstrPpdFilename - Specifies the PPD filename
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PTSTR ptstrBpdFilename;
HANDLE hFile;
DWORD dwBytesWritten;
BOOL bResult = FALSE;
VALIDATE_PARSER_DATA(pParserData);
//
// Generate a binary file name based the original filename
// Create a file and write data to it
//
if ((ptstrBpdFilename = GenerateBpdFilename(ptstrPpdFilename)) != NULL &&
(hFile = CreateFile(ptstrBpdFilename,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
NULL)) != INVALID_HANDLE_VALUE)
{
bResult = WriteFile(hFile,
pParserData->pubBufStart,
pParserData->dwBufSize,
&dwBytesWritten,
NULL) &&
(pParserData->dwBufSize == dwBytesWritten);
CloseHandle(hFile);
}
if (! bResult)
ERR(("Couldn't cache binary PPD data: %d\n", GetLastError()));
MemFree(ptstrBpdFilename);
return bResult;
}
VOID
VFreeParserData(
PPARSERDATA pParserData
)
/*++
Routine Description:
Free up memory used to hold parser data structure
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
VALIDATE_PARSER_DATA(pParserData);
if (pParserData->pubBufStart)
VirtualFree(pParserData->pubBufStart, 0, MEM_RELEASE);
MemFree(pParserData->Value.pbuf);
HeapDestroy(pParserData->hHeap);
}
PPARSERDATA
PAllocParserData(
VOID
)
/*++
Routine Description:
Allocate memory to hold PPD parser data
Arguments:
NONE
Return Value:
Pointer to allocated parser data structure
NULL if there is an error
--*/
{
PPARSERDATA pParserData;
HANDLE hHeap;
//
// Create a heap and allocate memory space from it
//
if (! (hHeap = HeapCreate(0, 16*1024, 0)) ||
! (pParserData = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(PARSERDATA))))
{
ERR(("Memory allocation failed: %d\n", GetLastError()));
if (hHeap)
HeapDestroy(hHeap);
return NULL;
}
pParserData->hHeap = hHeap;
pParserData->pvStartSig = pParserData->pvEndSig = pParserData;
//
// Initialize the parser data structure - we only need to worry
// about non-zero fields here.
//
pParserData->dwChecksum32 = 0xFFFFFFFF;
pParserData->dwFreeMem = min(MIN_FREEMEM_L1, MIN_FREEMEM_L2);
pParserData->dwJobTimeout = DEFAULT_JOB_TIMEOUT;
pParserData->dwWaitTimeout = DEFAULT_WAIT_TIMEOUT;
pParserData->iManualFeedIndex =
pParserData->iReqPageRgnIndex =
pParserData->iDefInstallMemIndex = -1;
pParserData->wNt4Checksum = 0;
pParserData->dwPpdFlags = PPDFLAG_PRINTPSERROR;
//
// Initialize buffers for storing keyword, option, translation, and value.
// Build up data structures to speed up keyword lookup
//
SET_BUFFER(&pParserData->Keyword, pParserData->achKeyword);
SET_BUFFER(&pParserData->Option, pParserData->achOption);
SET_BUFFER(&pParserData->Xlation, pParserData->achXlation);
if (IGrowValueBuffer(&pParserData->Value) != PPDERR_NONE ||
! BInitKeywordLookup(pParserData))
{
VFreeParserData(pParserData);
return NULL;
}
return pParserData;
}
BOOL
BRememberSourceFilename(
PPARSERDATA pParserData,
PTSTR ptstrFilename
)
/*++
Routine Description:
Remember the full pathname to the source PPD file
Arguments:
pParserData - Points to parser data structure
ptstrFilename - Specifies the source PPD filename
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PLISTOBJ pItem;
TCHAR ptstrFullname[MAX_PATH];
PTSTR ptstrFilePart;
DWORD dwSizeChars, dwSizeChars2;
DWORD dwSizeBytes; // size of buffer to hold pathname
//
// Get the full pathname to the specified source PPD file
//
dwSizeChars = GetFullPathName(ptstrFilename, MAX_PATH, ptstrFullname, &ptstrFilePart);
if (dwSizeChars == 0)
{
ERR(("GetFullPathName failed: %d\n", GetLastError()));
return FALSE;
}
//
// Remember the source PPD filenames
//
dwSizeBytes = (dwSizeChars + 1) * sizeof(TCHAR);
if (! (pItem = ALLOC_PARSER_MEM(pParserData, sizeof(LISTOBJ) + dwSizeBytes)))
return FALSE;
pItem->pstrName = (PSTR) ((PBYTE) pItem + sizeof(LISTOBJ));
// let GetFullPathName write directly into the real buffer!
dwSizeChars2 = GetFullPathName(ptstrFilename, dwSizeChars + 1, (PTSTR)pItem->pstrName, &ptstrFilePart);
if((dwSizeChars2 == 0) || (dwSizeChars2 > dwSizeChars))
{
ERR(("GetFullPathName failed: %d\n", GetLastError()));
return FALSE; // no need to free pItem since Heap is destroyed automatically.
}
pItem->pNext = pParserData->pPpdFileNames;
pParserData->pPpdFileNames = pItem;
return TRUE;
}
// 16-bit crc checksum table - copied from win95
static const WORD Crc16Table[] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
WORD
WComputeCrc16Checksum(
IN PBYTE pbuf,
IN DWORD dwCount,
IN WORD wChecksum
)
/*++
Routine Description:
Compute the 16-bit CRC checksum on a buffer of data
Arguments:
pbuf - Points to a data buffer
dwCount - Number of bytes in the data buffer
wChecksum - Initial checksum value
Return Value:
Resulting checksum value
--*/
{
while (dwCount--)
wChecksum = Crc16Table[(wChecksum >> 8) ^ *pbuf++] ^ (wChecksum << 8);
return wChecksum;
}
DWORD
dwComputeFeatureOptionChecksum(
PPARSERDATA pParserData
)
/*++
Routine Description:
Compute checksum for only feature/option keyword strings.
Arguments:
pParserData - Points to parser data structure
Return Value:
32bit checksum value
--*/
{
PINFOHEADER pInfoHdr;
PUIINFO pUIInfo;
PFEATURE pFeature;
POPTION pOption;
DWORD dwFeatureCount, dwFeatureIndex, dwOptionCount, dwOptionIndex;
PBYTE pBuf;
DWORD dwBufSize;
VALIDATE_PARSER_DATA(pParserData);
pInfoHdr = pParserData->pInfoHdr;
pUIInfo = (PUIINFO)((PBYTE)pInfoHdr + sizeof(INFOHEADER));
dwFeatureCount = pInfoHdr->RawData.dwDocumentFeatures + pInfoHdr->RawData.dwPrinterFeatures;
pFeature = OFFSET_TO_POINTER(pInfoHdr, pUIInfo->loFeatureList);
ASSERT(dwFeatureCount == 0 || pFeature != NULL);
for (dwFeatureIndex = 0; dwFeatureIndex < dwFeatureCount; dwFeatureIndex++, pFeature++)
{
pBuf = OFFSET_TO_POINTER(pInfoHdr, pFeature->loKeywordName);
ASSERT(pBuf != NULL);
dwBufSize = strlen((PSTR)pBuf) + 1;
pParserData->dwChecksum32 = ComputeCrc32Checksum(pBuf, dwBufSize, pParserData->dwChecksum32);
if (dwOptionCount = pFeature->Options.dwCount)
{
pOption = OFFSET_TO_POINTER(pInfoHdr, pFeature->Options.loOffset);
ASSERT(pOption != NULL);
for (dwOptionIndex = 0; dwOptionIndex < dwOptionCount; dwOptionIndex++)
{
pBuf = OFFSET_TO_POINTER(pInfoHdr, pOption->loKeywordName);
dwBufSize = strlen((PSTR)pBuf) + 1;
pParserData->dwChecksum32 = ComputeCrc32Checksum(pBuf, dwBufSize, pParserData->dwChecksum32);
pOption = (POPTION)((PBYTE)pOption + pFeature->dwOptionSize);
}
}
}
return pParserData->dwChecksum32;
}
DWORD
dwCalcMaxKeywordSize(
IN PPARSERDATA pParserData,
IN INT iMode
)
/*++
Routine Description:
Calculate the maximum buffer size for storing feature/option
keyword pairs in Registry.
Arguments:
pParserData - Points to parser data structure
iMode - For either doc- or printer- sticky features
Return Value:
The maximum buffer size needed for storing feature/option keyword paris.
--*/
{
PINFOHEADER pInfoHdr;
PUIINFO pUIInfo;
PFEATURE pFeature;
POPTION pOption;
DWORD dwStart, dwFeatureCount, dwFeatureIndex, dwOptionCount, dwOptionIndex;
PSTR pBuf;
DWORD dwMaxSize, dwOptionSize, dwOptionMax;
VALIDATE_PARSER_DATA(pParserData);
dwMaxSize = 0;
pInfoHdr = pParserData->pInfoHdr;
pUIInfo = pParserData->pUIInfo;
if (iMode == MODE_DOCUMENT_STICKY)
{
dwStart = 0;
dwFeatureCount = pUIInfo->dwDocumentFeatures;
}
else
{
ASSERT(iMode == MODE_PRINTER_STICKY);
dwStart = pUIInfo->dwDocumentFeatures;
dwFeatureCount = pUIInfo->dwPrinterFeatures;
}
pFeature = OFFSET_TO_POINTER(pInfoHdr, pUIInfo->loFeatureList);
ASSERT(dwFeatureCount == 0 || pFeature != NULL);
pFeature += dwStart;
for (dwFeatureIndex = 0; dwFeatureIndex < dwFeatureCount; dwFeatureIndex++, pFeature++)
{
pBuf = OFFSET_TO_POINTER(pInfoHdr, pFeature->loKeywordName);
ASSERT(pBuf != NULL);
dwMaxSize += strlen(pBuf) + 1;
dwOptionMax = 0;
if (dwOptionCount = pFeature->Options.dwCount)
{
pOption = OFFSET_TO_POINTER(pInfoHdr, pFeature->Options.loOffset);
ASSERT(pOption != NULL);
for (dwOptionIndex = 0; dwOptionIndex < dwOptionCount; dwOptionIndex++)
{
pBuf = OFFSET_TO_POINTER(pInfoHdr, pOption->loKeywordName);
dwOptionSize = strlen(pBuf) + 1;
if (pFeature->dwUIType != UITYPE_PICKMANY)
{
if (dwOptionMax < dwOptionSize)
dwOptionMax = dwOptionSize;
}
else // count all options for PickMany feature
dwMaxSize += dwOptionSize;
pOption = (POPTION)((PBYTE)pOption + pFeature->dwOptionSize);
}
}
//
// Add the max option keyword size here for non-PickMany feature
//
if (pFeature->dwUIType != UITYPE_PICKMANY)
dwMaxSize += dwOptionMax;
//
// One extra byte for the \0x0A delimiter between features
//
dwMaxSize += 1;
}
dwMaxSize += KEYWORD_SIZE_EXTRA;
return dwMaxSize;
}
PPDERROR
IParseFile(
PPARSERDATA pParserData,
PTSTR ptstrFilename
)
/*++
Routine Description:
Parse a PPD file
Arguments:
pParserData - Points to parser data structure
ptstrFilename - Specifies the name of the file to be parsed
Return Value:
PPDERR_NONE if successful, error code otherwise
--*/
{
PPDERROR iStatus;
PFILEOBJ pFile;
INT iSyntaxErrors = 0;
//
// Map the file into memory for read-only access
//
VALIDATE_PARSER_DATA(pParserData);
ASSERT(ptstrFilename != NULL);
if (! BRememberSourceFilename(pParserData, ptstrFilename) ||
! (pFile = PCreateFileObj(ptstrFilename)))
{
return PPDERR_FILE;
}
pParserData->pFile = pFile;
#if 0
//
// Compute the 32-bit CRC checksum of the file content
//
pParserData->dwChecksum32 =
ComputeCrc32Checksum(pFile->pubStart, pFile->dwFileSize, pParserData->dwChecksum32);
#endif
//
// Compute the 16-bit CRC checksum as well for PS4 compatibility
//
pParserData->wNt4Checksum =
WComputeCrc16Checksum(pFile->pubStart, pFile->dwFileSize, pParserData->wNt4Checksum);
//
// Process entries in the file
//
while ((iStatus = IParseEntry(pParserData)) != PPDERR_EOF)
{
if (iStatus == PPDERR_SYNTAX)
iSyntaxErrors++;
else if (iStatus != PPDERR_NONE)
{
VDeleteFileObj(pFile);
return iStatus;
}
}
if (END_OF_FILE(pFile) && !END_OF_LINE(pFile))
TERSE(("Incomplete last line ignored.\n"));
//
// Unmap the file and return to the caller
//
VDeleteFileObj(pFile);
return (iSyntaxErrors > 0) ? PPDERR_SYNTAX : PPDERR_NONE;
}
PRAWBINARYDATA
PpdParseTextFile(
PTSTR ptstrPpdFilename
)
/*++
Routine Description:
PPD parser main entry point
Arguments:
ptstrPpdFilename - Specifies the PPD file to be parsed
Return Value:
Pointer to parsed binary PPD data, NULL if there is an error
--*/
{
PPARSERDATA pParserData;
PPDERROR iStatus;
PRAWBINARYDATA pRawData = NULL;
//
// Allocate parser data structure
//
ASSERT(ptstrPpdFilename != NULL);
if (! (pParserData = PAllocParserData()))
return NULL;
//
// Parse the PPD file
//
iStatus = IParseFile(pParserData, ptstrPpdFilename);
if (iStatus == PPDERR_NONE || iStatus == PPDERR_SYNTAX)
{
//
// Pack the parsed information into binary format
//
pParserData->bErrorFlag = FALSE;
if (BPackBinaryData(pParserData))
{
//
// After binary data is packed, we calculate the 32bit checksum
// for only feature/option keyword strings (instead of for the
// whole PPD file). Doing this will enable us to retain option
// selections when the PPD file is modified without feature/option
// changes.
//
pParserData->pInfoHdr->RawData.dwChecksum32 = dwComputeFeatureOptionChecksum(pParserData);
//
// Calculate the maximum buffer sizes for storing feature/option
// keyword pairs in Registry
//
pParserData->pUIInfo->dwMaxDocKeywordSize = dwCalcMaxKeywordSize(pParserData, MODE_DOCUMENT_STICKY);
pParserData->pUIInfo->dwMaxPrnKeywordSize = dwCalcMaxKeywordSize(pParserData, MODE_PRINTER_STICKY);
#ifndef WINNT_40
pParserData->pPpdData->dwUserDefUILangID = (DWORD)GetUserDefaultUILanguage();
#else
pParserData->pPpdData->dwUserDefUILangID = 0;
#endif
//
// Save binary data to a file
//
(VOID) BSaveBinaryDataToFile(pParserData, ptstrPpdFilename);
//
// Here we'll copy the packed binary data to a different buffer.
// This is necessary because the packed data buffer was allocated
// using VirtualAlloc. If we return that pointer back to the caller,
// the caller would need to call VirtualFree to release it.
//
if (pRawData = MemAlloc(pParserData->dwBufSize))
{
CopyMemory(pRawData, pParserData->pubBufStart, pParserData->dwBufSize);
}
else
ERR(("Memory allocation failed: %d\n", GetLastError()));
}
}
if (iStatus == PPDERR_SYNTAX || pParserData->bErrorFlag)
WARNING(("Errors found in %ws\n", ptstrPpdFilename));
VFreeParserData(pParserData);
return pRawData;
}
PPDERROR
IGrowValueBuffer(
PBUFOBJ pBufObj
)
/*++
Routine Description:
Grow the buffer used for holding the entry value
Arguments:
pBufObj - Specifies the buffer to be enlarged
Return Value:
PPDERR_NONE if successful, error code otherwise
--*/
#define VALUE_BUFFER_INCREMENT (1*KBYTES)
{
DWORD dwNewLen = pBufObj->dwMaxLen + VALUE_BUFFER_INCREMENT;
PBYTE pbuf;
if (! IS_BUFFER_FULL(pBufObj))
WARNING(("Trying to grow buffer while it's not yet full.\n"));
if (! (pbuf = MemAllocZ(dwNewLen)))
{
ERR(("Memory allocation failed: %d\n", GetLastError()));
return PPDERR_MEMORY;
}
if (pBufObj->pbuf)
{
CopyMemory(pbuf, pBufObj->pbuf, pBufObj->dwSize);
MemFree(pBufObj->pbuf);
}
pBufObj->pbuf = pbuf;
pBufObj->dwMaxLen = dwNewLen;
return PPDERR_NONE;
}