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
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;
|
|
}
|
|
|