/*++ 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; }