|
|
/*++
Copyright (c) 1996-1997 Microsoft Corporation
Module Name:
ppdkwd.c
Abstract:
Functions for interpreting the semantics elements of a PPD file
Environment:
PostScript driver, PPD parser
Revision History:
09/30/96 -davidx- Cleaner handling of ManualFeed and AutoSelect feature.
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 <math.h>
//
// Data structure for representing entries in a keyword table
//
typedef PPDERROR (*KWDPROC)(PPARSERDATA);
typedef struct _KWDENTRY {
PCSTR pstrKeyword; // keyword name
KWDPROC pfnProc; // keyword handler function
DWORD dwFlags; // misc. flag bits
} KWDENTRY, *PKWDENTRY;
//
// Constants for KWDENTRY.flags field. The low order byte is used to indicate value types.
//
#define REQ_OPTION 0x0100
#define ALLOW_MULTI 0x0200
#define ALLOW_HEX 0x0400
#define DEFAULT_PROC 0x0800
#define INVOCA_VALUE (VALUETYPE_QUOTED | VALUETYPE_SYMBOL)
#define QUOTED_VALUE (VALUETYPE_QUOTED | ALLOW_HEX)
#define QUOTED_NOHEX VALUETYPE_QUOTED
#define STRING_VALUE VALUETYPE_STRING
#define GENERIC_ENTRY(featureId) ((featureId) << 16)
//
// Give a warning when there are duplicate entries for the same option
//
#define WARN_DUPLICATE() \
TERSE(("%ws: Duplicate entries of '*%s %s' on line %d\n", \ pParserData->pFile->ptstrFileName, \ pParserData->achKeyword, \ pParserData->achOption, \ pParserData->pFile->iLineNumber))
//
// Default keyword prefix string
//
#define HAS_DEFAULT_PREFIX(pstr) \
(strncmp((pstr), gstrDefault, strlen(gstrDefault)) == EQUAL_STRING)
//
// Determine whether a string starts with JCL prefix
//
#define HAS_JCL_PREFIX(pstr) (strncmp((pstr), "JCL", 3) == EQUAL_STRING)
//
// Forward declaration of local functions
//
PPDERROR IVerifyValueType(PPARSERDATA, DWORD); PPDERROR IGenericOptionProc(PPARSERDATA, PFEATUREOBJ); PPDERROR IGenericDefaultProc(PPARSERDATA, PFEATUREOBJ); PPDERROR IGenericQueryProc(PPARSERDATA, PFEATUREOBJ); PFEATUREOBJ PCreateFeatureItem(PPARSERDATA, DWORD); PKWDENTRY PSearchKeywordTable(PPARSERDATA, PSTR, PINT);
PPDERROR IInterpretEntry( PPARSERDATA pParserData )
/*++
Routine Description:
Interpret an entry parsed from a printer description file
Arguments:
pParserData - Points to parser data structure
Return Value:
Status code
--*/
{ PSTR pstrKeyword, pstrRealKeyword; PPDERROR iStatus; PKWDENTRY pKwdEntry; INT iIndex; BOOL bQuery, bDefault;
//
// Get a pointer to the keyword string and look for
// *? and *Default prefix in front of the keyword.
//
pstrRealKeyword = pstrKeyword = pParserData->achKeyword; bQuery = bDefault = FALSE;
// NOTE: We don't have any use for query entries so don't parse them here.
// This helps us somewhat to preserve the feature index from NT4.
if (FALSE && *pstrKeyword == QUERY_CHAR) { bQuery = TRUE; pstrRealKeyword++; } else if (HAS_DEFAULT_PREFIX(pstrKeyword)) { bDefault = TRUE; pstrRealKeyword += strlen(gstrDefault); }
//
// Set up a convenient pointer to the entry value
//
pParserData->pstrValue = (PSTR) pParserData->Value.pbuf;
//
// If we're within an OpenUI/CloseUI pair and the keyword
// in the current entry matches what's in OpenUI, then we
// will handle the current entry using a generic procedure.
//
if (pParserData->pOpenFeature && pParserData->pOpenFeature->dwFeatureID == GID_UNKNOWN && strcmp(pstrRealKeyword, pParserData->pOpenFeature->pstrName) == EQUAL_STRING) { pKwdEntry = NULL; } else { //
// Find out if the keyword has built-in support
//
pKwdEntry = PSearchKeywordTable(pParserData, pstrRealKeyword, &iIndex);
//
// For *Default keywords, if we failed to find the keyword without
// the prefix, try it again with the prefix.
//
if (bDefault && (pKwdEntry == NULL || pKwdEntry->pfnProc != NULL) && (pKwdEntry = PSearchKeywordTable(pParserData, pstrKeyword, &iIndex))) { bDefault = FALSE; }
//
// Ignore unsupported keywords
//
if ((pKwdEntry == NULL) || ((bQuery || bDefault) && (pKwdEntry->pfnProc != NULL))) { VERBOSE(("Keyword not supported: *%s\n", pstrKeyword)); return PPDERR_NONE; } }
//
// Determine if the entry should be handle by the generic procedure
//
if (pKwdEntry == NULL || pKwdEntry->pfnProc == NULL) { PFEATUREOBJ pFeature; DWORD dwValueType; PPDERROR (*pfnGenericProc)(PPARSERDATA, PFEATUREOBJ);
//
// Make sure the value type matches what's expected
//
if (bQuery) { pfnGenericProc = IGenericQueryProc; dwValueType = INVOCA_VALUE; } else if (bDefault) { pfnGenericProc = IGenericDefaultProc; dwValueType = STRING_VALUE; } else { pfnGenericProc = IGenericOptionProc; dwValueType = INVOCA_VALUE | REQ_OPTION; }
if ((iStatus = IVerifyValueType(pParserData, dwValueType)) != PPDERR_NONE) return iStatus;
//
// Call the appropriate generic procedure
//
pFeature = (pKwdEntry == NULL) ? pParserData->pOpenFeature : PCreateFeatureItem(pParserData, HIWORD(pKwdEntry->dwFlags));
return pfnGenericProc(pParserData, pFeature); } else { //
// Screen out duplicate keyword entries
//
if (! (pKwdEntry->dwFlags & (ALLOW_MULTI|REQ_OPTION))) { if (pParserData->pubKeywordCounts[iIndex]) { WARN_DUPLICATE(); return PPDERR_NONE; }
pParserData->pubKeywordCounts[iIndex]++; }
//
// Make sure the value type matches what's expected
// Take care of embedded hexdecimal strings if necessary
//
if ((iStatus = IVerifyValueType(pParserData, pKwdEntry->dwFlags)) != PPDERR_NONE) return iStatus;
//
// Invoke the specific procedure to handle built-in keywords
//
return (pKwdEntry->pfnProc)(pParserData); } }
PPDERROR IVerifyValueType( PPARSERDATA pParserData, DWORD dwExpectedType )
/*++
Routine Description:
Verify the value type of the current entry matches what's expected
Arguments:
pParserData - Points to parser data structure dwExpectedType - Expected value type
Return Value:
Status code
--*/
{ DWORD dwValueType;
//
// Check for following syntax error conditions:
// 1. The entry requires an option keyword but no option keyword is present
// 2. The entry doesn't require an option keyword but an option keyword is present
//
if ((dwExpectedType & REQ_OPTION) && IS_BUFFER_EMPTY(&pParserData->Option)) { return ISyntaxError(pParserData->pFile, "Missing option keyword"); }
if (! (dwExpectedType & REQ_OPTION) && ! IS_BUFFER_EMPTY(&pParserData->Option)) { return ISyntaxError(pParserData->pFile, "Extra option keyword"); }
//
// Tolerate the following syntax error conditions:
// 1. The entry requires a quoted value but a string value is provided.
// 2. The entry requires a string value but a quoted value is provided.
//
switch (dwValueType = pParserData->dwValueType) { case VALUETYPE_STRING:
if (dwExpectedType & VALUETYPE_QUOTED) { TERSE(("%ws: Expect QuotedValue instead of StringValue on line %d\n", pParserData->pFile->ptstrFileName, pParserData->pFile->iLineNumber));
dwValueType = VALUETYPE_QUOTED; } break;
case VALUETYPE_QUOTED:
if (dwExpectedType & VALUETYPE_STRING) { TERSE(("%ws: Expect StringValue instead of QuotedValue on line %d\n", pParserData->pFile->ptstrFileName, pParserData->pFile->iLineNumber));
if (IS_BUFFER_EMPTY(&pParserData->Value)) return ISyntaxError(pParserData->pFile, "Empty string value");
dwValueType = VALUETYPE_STRING; } break; }
//
// Return syntax error if the provided value type doesn't match what's expected
//
if ((dwExpectedType & dwValueType) == 0) return ISyntaxError(pParserData->pFile, "Value type mismatch");
//
// If the value field is a quoted string and one of the following conditions
// is true, then we need to process any embedded hexdecimal strings within
// the quoted string:
// 1. The entry expects a QuotedValue.
// 2. The entry expects an InvocationValue and appears inside JCLOpenUI/JCLCloseUI
//
if (dwValueType == VALUETYPE_QUOTED) { if ((dwExpectedType & ALLOW_HEX) || ((dwExpectedType & VALUETYPE_MASK) == INVOCA_VALUE && pParserData->bJclFeature)) { if (! BConvertHexString(&pParserData->Value)) return ISyntaxError(pParserData->pFile, "Invalid embedded hexdecimal string"); } else if (! BIs7BitAscii(pParserData->pstrValue)) { //
// Only allow 7-bit ASCII characters inside invocation string
//
return ISyntaxError(pParserData->pFile, "Non-printable ASCII character"); } }
return PPDERR_NONE; }
BOOL BGetIntegerFromString( PSTR *ppstr, LONG *plValue )
/*++
Routine Description:
Parse an unsigned decimal integer value from a character string
Arguments:
ppstr - Points to a string pointer. On entry, it contains a pointer to the beginning of the number string. On exit, it points to the first non-space character after the number string. plValue - Points to a variable for storing parsed number
Return Value:
TRUE if a number is successfully parsed, FALSE if there is an error
--*/
{ LONG lValue; PSTR pstr = *ppstr; BOOL bNegative = FALSE;
//
// Skip any leading space characters and
// look for the sign character (if any)
//
while (IS_SPACE(*pstr)) pstr++;
if (*pstr == '-') { bNegative = TRUE; pstr++; }
if (! IS_DIGIT(*pstr)) { TERSE(("Invalid integer number: %s\n", pstr)); return FALSE; }
//
// NOTE: Overflow conditions are ignored.
//
lValue = 0;
while (IS_DIGIT(*pstr)) lValue = lValue * 10 + (*pstr++ - '0');
//
// Skip any trailing space characters
//
while (IS_SPACE(*pstr)) pstr++;
*ppstr = pstr; *plValue = bNegative ? -lValue : lValue; return TRUE; }
BOOL BGetFloatFromString( PSTR *ppstr, PLONG plValue, INT iType )
/*++
Routine Description:
Parse an unsigned floating-point number from a character string
Arguments:
ppstr - Points to a string pointer. On entry, it contains a pointer to the beginning of the number string. On exit, it points to the first non-space character after the number string. plValue - Points to a variable for storing the parsed number iType - How to convert the floating-point number before returning FLTYPE_FIX - convert it to 24.8 format fixed-point number FLTYPE_INT - convert it to integer FLTYPE_POINT - convert it from point to micron FLTYPE_POINT_ROUNDUP - round it up and convert it from point to micron FLTYPE_POINT_ROUNDDOWN - round it down and convert it from point to micron
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ double value, scale; PSTR pstr = *ppstr; BOOL bNegative = FALSE, bFraction = FALSE;
//
// Skip any leading space characters and
// look for the sign character (if any)
//
while (IS_SPACE(*pstr)) pstr++;
if (*pstr == '-') { bNegative = TRUE; pstr++; }
if (!IS_DIGIT(*pstr) && *pstr != '.') { TERSE(("Invalid floating-point number\n")); return FALSE; }
//
// Integer portion
//
value = 0.0;
while (IS_DIGIT(*pstr)) value = value * 10.0 + (*pstr++ - '0');
//
// Fractional portion
//
if (*pstr == '.') { bFraction = TRUE; pstr++;
if (! IS_DIGIT(*pstr)) { TERSE(("Invalid floating-point number\n")); return FALSE; }
scale = 0.1;
while (IS_DIGIT(*pstr)) { value += scale * (*pstr++ - '0'); scale *= 0.1; } }
//
// Skip any trailing space characters
//
while (IS_SPACE(*pstr)) pstr++;
//
// Perform requested round up or round down only if
// fractional portion is present.
//
if (bFraction) { if (iType == FLTYPE_POINT_ROUNDUP) value = ceil(value); else if (iType == FLTYPE_POINT_ROUNDDOWN) value = (LONG)value; }
//
// Convert the return value to the specified format
//
switch (iType) { case FLTYPE_POINT: case FLTYPE_POINT_ROUNDUP: case FLTYPE_POINT_ROUNDDOWN:
value = (value * 25400.0) / 72.0; break;
case FLTYPE_FIX:
value *= FIX_24_8_SCALE; break;
default:
ASSERT(iType == FLTYPE_INT); break; }
//
// Guard against overflow conditions
//
if (value >= MAX_LONG) { TERSE(("Floating-point number overflow\n")); return FALSE; }
*ppstr = pstr; *plValue = (LONG) (value + 0.5);
if (bNegative) { TERSE(("Negative number treated as 0\n")); *plValue = 0; }
return TRUE; }
BOOL BSearchStrTable( PCSTRTABLE pTable, PSTR pstrKeyword, DWORD *pdwValue )
/*++
Routine Description:
Search for a keyword from a string table
Arguments:
pTable - Specifies the string table to be search pstrKeyword - Specifies the keyword we're interested in pdwValue - Points to a variable for storing value corresponding to the given keyword
Return Value:
TRUE if the given keyword is found in the table, FALSE otherwise
--*/
{ ASSERT(pstrKeyword != NULL);
while (pTable->pstrKeyword != NULL && strcmp(pTable->pstrKeyword, pstrKeyword) != EQUAL_STRING) { pTable++; }
*pdwValue = pTable->dwValue; return (pTable->pstrKeyword != NULL); }
PSTR PstrParseString( PPARSERDATA pParserData, PBUFOBJ pBufObj )
/*++
Routine Description:
Duplicate a character string from a buffer object
Arguments:
pParserData - Points to parser data structure pBufObj - Specifies the buffer object containing the character string to be duplicated
Return Value:
Pointer to a copy of the specified string NULL if there is an error
--*/
{ PSTR pstr;
ASSERT(! IS_BUFFER_EMPTY(pBufObj));
if (pstr = ALLOC_PARSER_MEM(pParserData, pBufObj->dwSize + 1)) CopyMemory(pstr, pBufObj->pbuf, pBufObj->dwSize + 1); else ERR(("Memory allocation failed: %d\n", GetLastError()));
return pstr; }
PPDERROR IParseInvocation( PPARSERDATA pParserData, PINVOCOBJ pInvocation )
/*++
Routine Description:
Parse the content of value buffer to an invocation string
Arguments:
pParserData - Points to parser data structure pInvocation - Specifies a buffer for storing the parsed invocation string
Return Value:
Status code
--*/
{ ASSERT(pInvocation->pvData == NULL);
//
// Determine if the invocation is a quoted string or a symbol reference.
// In case of symbol reference, we save the name of the symbol in pvData
// field (including the leading ^ character).
//
if (pParserData->dwValueType == VALUETYPE_SYMBOL) { PSTR pstrSymbolName;
if (! (pstrSymbolName = PstrParseString(pParserData, &pParserData->Value))) return PPDERR_MEMORY;
pInvocation->pvData = pstrSymbolName; MARK_SYMBOL_INVOC(pInvocation); } else { PVOID pvData;
if (! (pvData = ALLOC_PARSER_MEM(pParserData, pParserData->Value.dwSize + 1))) { ERR(("Memory allocation failed\n")); return PPDERR_MEMORY; }
pInvocation->pvData = pvData; pInvocation->dwLength = pParserData->Value.dwSize; ASSERT(! IS_SYMBOL_INVOC(pInvocation));
CopyMemory(pvData, pParserData->Value.pbuf, pInvocation->dwLength + 1); }
return PPDERR_NONE; }
PPDERROR IParseInteger( PPARSERDATA pParserData, PDWORD pdwValue )
/*++
Routine Description:
Intrepret the value field of an entry as unsigned integer
Arguments:
pParserData - Points to parser data structure pdwValue - Points to a variable for storing parsed integer value
Return Value:
Status code
--*/
{ PSTR pstr = pParserData->pstrValue; LONG lValue;
if (BGetIntegerFromString(&pstr, &lValue)) { if (lValue >= 0) { *pdwValue = lValue; return PPDERR_NONE;
} else TERSE(("Negative integer value not allowed: %s.\n", pParserData->pstrValue)); }
*pdwValue = 0; return PPDERR_SYNTAX; }
PPDERROR IParseBoolean( PPARSERDATA pParserData, DWORD *pdwValue )
/*++
Routine Description:
Interpret the value of an entry as a boolen, i.e. True or False
Arguments:
pParserData - Points to parser data structure pdwValue - Points to a variable for storing the parsed boolean value
Return Value:
Status code
--*/
{ static const STRTABLE BooleanStrs[] = { gstrTrueKwd, TRUE, gstrFalseKwd, FALSE, NULL, FALSE };
if (! BSearchStrTable(BooleanStrs, pParserData->pstrValue, pdwValue)) return ISyntaxError(pParserData->pFile, "Invalid boolean constant");
return PPDERR_NONE; }
BOOL BFindNextWord( PSTR *ppstr, PSTR pstrWord )
/*++
Routine Description:
Find the next word in a character string. Words are separated by spaces.
Arguments:
ppstr - Points to a string pointer. On entry, it contains a pointer to the beginning of the word string. On exit, it points to the first non-space character after the word string. pstrWord - Points to a buffer for storing characters from the next word The size of this buffer must be at least MAX_WORD_LEN characters
Return Value:
TRUE if next word is found, FALSE otherwise
--*/
{ PSTR pstr = *ppstr;
pstrWord[0] = NUL;
//
// Skip any leading spaces
//
while (IS_SPACE(*pstr)) pstr++;
if (*pstr != NUL) { PSTR pstrStart; INT iWordLen;
//
// Go to the end of the word
//
pstrStart = pstr;
while (*pstr && !IS_SPACE(*pstr)) pstr++;
//
// Copy the word into the specified buffer
//
if ((iWordLen = (INT)(pstr - pstrStart)) < MAX_WORD_LEN) { CopyMemory(pstrWord, pstrStart, iWordLen); pstrWord[iWordLen] = NUL; }
//
// Skip to the next non-space character
//
while (IS_SPACE(*pstr)) pstr++; }
*ppstr = pstr; return (*pstrWord != NUL); }
PPDERROR IParseVersionNumber( PPARSERDATA pParserData, PDWORD pdwVersion )
/*++
Routine Description:
Parse a version number. The format of a version number is Version[.Revision] where both Version and Revision are integers.
Arguments:
pParserData - Points to parser data structure pdwVersion - Points to a variable for storing the parsed version number
Return Value:
Status code
--*/
{ PSTR pstr; LONG lVersion, lRevision = 0;
//
// Parse the major version number followed by minor revision number
//
pstr = pParserData->pstrValue;
if (! BGetIntegerFromString(&pstr, &lVersion)) return ISyntaxError(pParserData->pFile, "Invalid version number");
if (*pstr == '.') { pstr++;
if (! BGetIntegerFromString(&pstr, &lRevision)) return ISyntaxError(pParserData->pFile, "Invalid revision number"); }
//
// High-order word contains version number and
// low-order word contains revision number
//
if (lVersion < 0 || lVersion > MAX_WORD || lRevision < 0 || lRevision > MAX_WORD) { return ISyntaxError(pParserData->pFile, "Version number out-of-range"); }
*pdwVersion = (lVersion << 16) | lRevision; return PPDERR_NONE; }
PPDERROR IParseXlation( PPARSERDATA pParserData, PINVOCOBJ pXlation )
/*++
Routine Description:
Parse the information in the translation string field to an INVOCOBJ
Arguments:
pParserData - Points to parser data structure pXlation - Returns information about parsed translation string
Return Value:
Status code
--*/
{ PBUFOBJ pBufObj = &pParserData->Xlation;
//
// Allocate memory to hold the translation string (plus a null terminator)
//
pXlation->pvData = ALLOC_PARSER_MEM(pParserData, pBufObj->dwSize + 1);
if (pXlation->pvData == NULL) { ERR(("Memory allocation failed\n")); return PPDERR_MEMORY; }
pXlation->dwLength = pBufObj->dwSize; ASSERT(! IS_SYMBOL_INVOC(pXlation)); CopyMemory(pXlation->pvData, pBufObj->pbuf, pBufObj->dwSize);
return PPDERR_NONE; }
PCSTR PstrStripKeywordChar( PCSTR pstrKeyword )
/*++
Routine Description:
Strip off the keyword prefix character from the input string
Arguments:
pstrKeyword - Points to a string prefixed by the keyword character
Return Value:
Pointer to the keyword string after the keyword character is stripped NULL if the keyword string is empty
--*/
{ if (IS_KEYWORD_CHAR(*pstrKeyword)) pstrKeyword++;
return *pstrKeyword ? pstrKeyword : NULL; }
PVOID PvCreateListItem( PPARSERDATA pParserData, PLISTOBJ *ppList, DWORD dwItemSize, PSTR pstrListTag )
/*++
Routine Description:
Create a new item in the specified linked-list Make sure no existing item has the same name
Arguments:
pParserData - Points to parser data structure ppList - Specifies the linked-list dwItemSize - Linked-list item size pListTag - Specifies the name of the linked-list (for debugging purpose)
Return Value:
Pointer to newly created linked-list item NULL if there is an error
--*/
{ PLISTOBJ pItem; PSTR pstrItemName;
//
// Check if the item appeared in the list already
// Create a new item data structure if not
//
pItem = PvFindListItem(*ppList, pParserData->Option.pbuf, NULL);
if (pItem != NULL) { if (pstrListTag) TERSE(("%s %s redefined\n", pstrListTag, pItem->pstrName)); } else { if (! (pItem = ALLOC_PARSER_MEM(pParserData, dwItemSize)) || ! (pstrItemName = PstrParseString(pParserData, &pParserData->Option))) { ERR(("Memory allocation failed: %d\n", GetLastError())); return NULL; }
pItem->pstrName = pstrItemName; pItem->pNext = NULL;
//
// Put the newly created item at the end of the linked-list
//
while (*ppList != NULL) ppList = (PLISTOBJ *) &((*ppList)->pNext);
*ppList = pItem; }
return pItem; }
PFEATUREOBJ PCreateFeatureItem( PPARSERDATA pParserData, DWORD dwFeatureID )
/*++
Routine Description:
Create a new printer feature structure or find an existing one
Arguments:
pParserData - Points to parser data structure dwFeatureID - Printer feature identifier
Return Value:
Pointer to a newly created or an existing printer feature structure NULL if there is an error
--*/
{ static struct {
PCSTR pstrKeyword; DWORD dwFeatureID; DWORD dwOptionSize;
} FeatureInfo[] = {
gstrPageSizeKwd, GID_PAGESIZE, sizeof(PAPEROBJ), "PageRegion", GID_PAGEREGION, sizeof(OPTIONOBJ), "Duplex", GID_DUPLEX, sizeof(OPTIONOBJ), gstrInputSlotKwd, GID_INPUTSLOT, sizeof(TRAYOBJ), "Resolution", GID_RESOLUTION, sizeof(RESOBJ), "JCLResolution", GID_RESOLUTION, sizeof(RESOBJ), "OutputBin", GID_OUTPUTBIN, sizeof(BINOBJ), "MediaType", GID_MEDIATYPE, sizeof(OPTIONOBJ), "Collate", GID_COLLATE, sizeof(OPTIONOBJ), "InstalledMemory",GID_MEMOPTION, sizeof(MEMOBJ), "LeadingEdge", GID_LEADINGEDGE, sizeof(OPTIONOBJ), "UseHWMargins", GID_USEHWMARGINS, sizeof(OPTIONOBJ), NULL, GID_UNKNOWN, sizeof(OPTIONOBJ) };
PFEATUREOBJ pFeature; PCSTR pstrKeyword; BUFOBJ SavedBuffer; INT iIndex = 0;
if (dwFeatureID == GID_UNKNOWN) { //
// Given a feature name, first find out if it refers to
// one of the predefined features
//
pstrKeyword = PstrStripKeywordChar(pParserData->achOption); ASSERT(pstrKeyword != NULL);
while (FeatureInfo[iIndex].pstrKeyword && strcmp(FeatureInfo[iIndex].pstrKeyword, pstrKeyword) != EQUAL_STRING) { iIndex++; }
if (FeatureInfo[iIndex].pstrKeyword) pParserData->aubOpenUIFeature[FeatureInfo[iIndex].dwFeatureID] = 1; } else { //
// We're given a predefined feature identifier.
// Map to its corresponding feature name.
//
while (FeatureInfo[iIndex].pstrKeyword && dwFeatureID != FeatureInfo[iIndex].dwFeatureID) { iIndex++; }
pstrKeyword = FeatureInfo[iIndex].pstrKeyword; ASSERT(pstrKeyword != NULL); }
//
// If we're dealing with a predefined feature, the first search the current
// list of printer features based on the predefined feature identifier.
//
pFeature = NULL;
if (FeatureInfo[iIndex].dwFeatureID != GID_UNKNOWN) { for (pFeature = pParserData->pFeatures; pFeature && pFeature->dwFeatureID != FeatureInfo[iIndex].dwFeatureID; pFeature = pFeature->pNext) { } }
//
// Create a new printer feature item or find an existing printer feature item
// based on the feature name.
//
if (pFeature == NULL) { SavedBuffer = pParserData->Option; pParserData->Option.pbuf = (PBYTE) pstrKeyword; pParserData->Option.dwSize = strlen(pstrKeyword);
pFeature = PvCreateListItem(pParserData, (PLISTOBJ *) &pParserData->pFeatures, sizeof(FEATUREOBJ), NULL);
pParserData->Option = SavedBuffer; }
if (pFeature) { //
// Parse the translation string for the feature name
//
if (dwFeatureID == GID_UNKNOWN && ! IS_BUFFER_EMPTY(&pParserData->Xlation) && ! pFeature->Translation.pvData && IParseXlation(pParserData, &pFeature->Translation) != PPDERR_NONE) { ERR(("Failed to parse feature name translation string\n")); return NULL; }
if (pFeature->dwOptionSize == 0) { //
// Store information about newly created feature item
//
pFeature->dwOptionSize = FeatureInfo[iIndex].dwOptionSize; pFeature->dwFeatureID = FeatureInfo[iIndex].dwFeatureID;
//
// All predefined features are doc-sticky except for InstalledMemory/VMOption
//
if (pFeature->dwFeatureID == GID_MEMOPTION || pFeature->dwFeatureID == GID_UNKNOWN && pParserData->bInstallableGroup) { pFeature->bInstallable = TRUE; } } } else { ERR(("Couldn't create printer feature item for: %s\n", pstrKeyword)); }
return pFeature; }
PVOID PvCreateXlatedItem( PPARSERDATA pParserData, PVOID ppList, DWORD dwItemSize )
/*++
Routine Description:
Create a feature option item and parse the associated translation string
Arguments:
pParserData - Points to parser data structure ppList - Points to the list of feature option items dwItemSize - Size of a feature option item
Return Value:
Pointer to newly created feature option item NULL if there is an error
--*/
{ POPTIONOBJ pOption;
if (! (pOption = PvCreateListItem(pParserData, ppList, dwItemSize, NULL)) || (! IS_BUFFER_EMPTY(&pParserData->Xlation) && ! pOption->Translation.pvData && IParseXlation(pParserData, &pOption->Translation) != PPDERR_NONE)) { ERR(("Couldn't process entry: *%s %s\n", pParserData->achKeyword, pParserData->achOption));
return NULL; }
return pOption; }
PVOID PvCreateOptionItem( PPARSERDATA pParserData, DWORD dwFeatureID )
/*++
Routine Description:
Create a feature option item for a predefined printer feature
Arguments:
pParserData - Points to parser data structure dwFeatureID - Specifies a predefined feature identifier
Return Value:
Pointer to an existing feature option item or a newly created one if none exists NULL if there is an error
--*/
{ PFEATUREOBJ pFeature;
ASSERT(dwFeatureID != GID_UNKNOWN);
if (! (pFeature = PCreateFeatureItem(pParserData, dwFeatureID))) return NULL;
return PvCreateXlatedItem(pParserData, &pFeature->pOptions, pFeature->dwOptionSize); }
INT ICountFeatureList( PFEATUREOBJ pFeature, BOOL bInstallable )
{ INT i = 0;
//
// Count the number of features of the specified type
//
while (pFeature != NULL) { if (pFeature->bInstallable == bInstallable) i++;
pFeature = pFeature->pNext; }
return i; }
PPDERROR IGenericOptionProc( PPARSERDATA pParserData, PFEATUREOBJ pFeature )
/*++
Routine Description:
Function for handling a generic feature option entry
Arguments:
pParserData - Points to parser data structure pFeature - Points to feature data structure
Return Value:
Status code
--*/
{ POPTIONOBJ pOption;
//
// Handle special case
//
if (pFeature == NULL) return PPDERR_MEMORY;
//
// Create a feature option item and parse the option name and translation string
//
if (! (pOption = PvCreateXlatedItem(pParserData, &pFeature->pOptions, pFeature->dwOptionSize))) return PPDERR_MEMORY;
if (pOption->Invocation.pvData) { WARN_DUPLICATE(); return PPDERR_NONE; }
//
// Parse the invocation string
//
return IParseInvocation(pParserData, &pOption->Invocation); }
PPDERROR IGenericDefaultProc( PPARSERDATA pParserData, PFEATUREOBJ pFeature )
/*++
Routine Description:
Function for handling a generic default option entry
Arguments:
pParserData - Points to parser data structure pFeature - Points to feature data structure
Return Value:
Status code
--*/
{ //
// Check if there is a memory error before this function is called
//
if (pFeature == NULL) return PPDERR_MEMORY;
//
// Watch out for duplicate *Default entries for the same feature
//
if (pFeature->pstrDefault) { WARN_DUPLICATE(); return PPDERR_NONE; }
//
// NOTE: Hack to take in account of a bug in NT4 driver.
// This is used to build up NT4-NT5 feature index mapping.
//
if (pFeature->dwFeatureID == GID_MEMOPTION && pParserData->iDefInstallMemIndex < 0) { pParserData->iDefInstallMemIndex = ICountFeatureList(pParserData->pFeatures, TRUE); }
//
// Remember the default option keyword
//
if (pFeature->pstrDefault = PstrParseString(pParserData, &pParserData->Value)) return PPDERR_NONE; else return PPDERR_MEMORY; }
PPDERROR IGenericQueryProc( PPARSERDATA pParserData, PFEATUREOBJ pFeature )
/*++
Routine Description:
Function for handling a generic query invocation entry
Arguments:
pParserData - Points to parser data structure pFeature - Points to feature data structure
Return Value:
Status code
--*/
{ //
// Check if there is a memory error before this function is called
//
if (pFeature == NULL) return PPDERR_MEMORY;
//
// Watch out for duplicate *Default entries for the same feature
//
if (pFeature->QueryInvoc.pvData) { WARN_DUPLICATE(); return PPDERR_NONE; }
//
// Parse the query invocation string
//
return IParseInvocation(pParserData, &pFeature->QueryInvoc); }
//
// Functions for handling predefined PPD keywords
//
//
// Specifies the imageable area of a media option
//
PPDERROR IImageAreaProc( PPARSERDATA pParserData )
{ PPAPEROBJ pOption; PSTR pstr; RECT *pRect;
if (! (pOption = PvCreateOptionItem(pParserData, GID_PAGESIZE))) return PPDERR_MEMORY;
pRect = &pOption->rcImageArea;
if (pRect->top > 0 || pRect->right > 0) { WARN_DUPLICATE(); return PPDERR_NONE; }
//
// Parse imageable area: left, bottom, right, top
//
pstr = pParserData->pstrValue;
if (! BGetFloatFromString(&pstr, &pRect->left, FLTYPE_POINT_ROUNDUP) || ! BGetFloatFromString(&pstr, &pRect->bottom, FLTYPE_POINT_ROUNDUP) || ! BGetFloatFromString(&pstr, &pRect->right, FLTYPE_POINT_ROUNDDOWN) || ! BGetFloatFromString(&pstr, &pRect->top, FLTYPE_POINT_ROUNDDOWN) || pRect->left >= pRect->right || pRect->bottom >= pRect->top) { return ISyntaxError(pParserData->pFile, "Invalid imageable area"); }
return PPDERR_NONE; }
//
// Specifies the paper dimension of a media option
//
PPDERROR IPaperDimProc( PPARSERDATA pParserData )
{ PPAPEROBJ pOption; PSTR pstr;
if (! (pOption = PvCreateOptionItem(pParserData, GID_PAGESIZE))) return PPDERR_MEMORY;
if (pOption->szDimension.cx > 0 || pOption->szDimension.cy > 0) { WARN_DUPLICATE(); return PPDERR_NONE; }
//
// Parse paper width and height
//
pstr = pParserData->pstrValue;
if (! BGetFloatFromString(&pstr, &pOption->szDimension.cx, FLTYPE_POINT) || ! BGetFloatFromString(&pstr, &pOption->szDimension.cy, FLTYPE_POINT)) { return ISyntaxError(pParserData->pFile, "Invalid paper dimension"); }
return PPDERR_NONE; }
//
// Interpret PageStackOrder and OutputOrder options
//
BOOL BParseOutputOrder( PSTR pstr, PBOOL pbValue )
{ static const STRTABLE OutputOrderStrs[] = { "Normal", FALSE, "Reverse", TRUE, NULL, FALSE };
DWORD dwValue; BOOL bResult;
bResult = BSearchStrTable(OutputOrderStrs, pstr, &dwValue);
*pbValue = dwValue; return bResult; }
//
// Specifies the page stack order for an output bin
//
PPDERROR IPageStackOrderProc( PPARSERDATA pParserData )
{ PFEATUREOBJ pFeature; PBINOBJ pOutputBin;
//
// Have we seen the OutputBin feature yet?
//
for (pFeature = pParserData->pFeatures; pFeature && pFeature->dwFeatureID != GID_OUTPUTBIN; pFeature = pFeature->pNext) { }
//
// If PageStackOrder entry appears before OutputBin feature, ignore it
//
if (pFeature == NULL) { BOOL bReverse; if (!BParseOutputOrder(pParserData->pstrValue, &bReverse)) return ISyntaxError(pParserData->pFile, "Invalid PageStackOrder option"); if (bReverse) TERSE(("%ws: Ignored *PageStackOrder: Reverse on line %d because OutputBin not yet defined\n", pParserData->pFile->ptstrFileName, pParserData->pFile->iLineNumber));
return PPDERR_NONE; }
//
// Add an option for OutputBin feature
//
pOutputBin = PvCreateXlatedItem(pParserData, &pFeature->pOptions, pFeature->dwOptionSize);
if (pOutputBin == NULL) return PPDERR_MEMORY;
return BParseOutputOrder(pParserData->pstrValue, &pOutputBin->bReversePrint) ? PPDERR_NONE : ISyntaxError(pParserData->pFile, "Invalid PageStackOrder option"); }
//
// Specifies the default page output order
// NOTE: This function gets called only if *DefaultOutputOrder
// entry appears outside of OpenUI/CloseUI.
//
PPDERROR IDefOutputOrderProc( PPARSERDATA pParserData )
{ pParserData->bDefOutputOrderSet = BParseOutputOrder(pParserData->pstrValue, &pParserData->bDefReversePrint);
return pParserData->bDefOutputOrderSet ? PPDERR_NONE : ISyntaxError(pParserData->pFile, "Invalid DefaultOutputOrder option"); }
//
// Specifies whether an input slot requires page region specification
//
PPDERROR IReqPageRgnProc( PPARSERDATA pParserData )
{ PTRAYOBJ pOption; DWORD dwValue;
//
// NOTE: Hack for doing NT4-NT5 feature index conversion
//
if (pParserData->iReqPageRgnIndex < 0) { PFEATUREOBJ pFeature = pParserData->pFeatures;
while (pFeature && pFeature->dwFeatureID != GID_INPUTSLOT) pFeature = pFeature->pNext;
if (pFeature == NULL) pParserData->iReqPageRgnIndex = ICountFeatureList(pParserData->pFeatures, FALSE); }
//
// The value should be either True or False
//
if (IParseBoolean(pParserData, &dwValue) != PPDERR_NONE) return PPDERR_SYNTAX;
dwValue = dwValue ? REQRGN_TRUE : REQRGN_FALSE;
//
// *RequiresPageRegion All: entry has special meaning
//
if (strcmp(pParserData->achOption, "All") == EQUAL_STRING) { if (pParserData->dwReqPageRgn == REQRGN_UNKNOWN) pParserData->dwReqPageRgn = dwValue; else WARN_DUPLICATE(); } else { if (! (pOption = PvCreateOptionItem(pParserData, GID_INPUTSLOT))) return PPDERR_MEMORY;
if (pOption->dwReqPageRgn == REQRGN_UNKNOWN) pOption->dwReqPageRgn = dwValue; else WARN_DUPLICATE(); }
return PPDERR_NONE; }
//
// Specifies Duplex feature options
//
PPDERROR IDefaultDuplexProc( PPARSERDATA pParserData )
{ return IGenericDefaultProc(pParserData, PCreateFeatureItem(pParserData, GID_DUPLEX)); }
PPDERROR IDuplexProc( PPARSERDATA pParserData )
{ if (strcmp(pParserData->achOption, gstrNoneKwd) != EQUAL_STRING && strcmp(pParserData->achOption, gstrDuplexTumble) != EQUAL_STRING && strcmp(pParserData->achOption, gstrDuplexNoTumble) != EQUAL_STRING) { return ISyntaxError(pParserData->pFile, "Invalid Duplex option"); }
return IGenericOptionProc(pParserData, PCreateFeatureItem(pParserData, GID_DUPLEX)); }
//
// Specifies ManualFeed True/False invocation strings
//
PPDERROR IDefManualFeedProc( PPARSERDATA pParserData )
{ //
// NOTE: Hack for doing NT4-NT5 feature index conversion
//
if (pParserData->iManualFeedIndex < 0) pParserData->iManualFeedIndex = ICountFeatureList(pParserData->pFeatures, FALSE);
return PPDERR_NONE; }
PPDERROR IManualFeedProc( PPARSERDATA pParserData )
{ POPTIONOBJ pOption; INT iResult = PPDERR_NONE;
//
// NOTE: Hack for doing NT4-NT5 feature index conversion
//
if (pParserData->iManualFeedIndex < 0) pParserData->iManualFeedIndex = ICountFeatureList(pParserData->pFeatures, FALSE);
if (strcmp(pParserData->achOption, gstrTrueKwd) == EQUAL_STRING || strcmp(pParserData->achOption, gstrOnKwd) == EQUAL_STRING) { //
// The way manual feed is handled in PPD spec is incredibly klugy.
// Hack here to treat *ManualFeed True as one of the input slot
// selections so that downstream component can handle it uniformly.
//
StringCchCopyA(pParserData->achOption, CCHOF(pParserData->achOption), gstrManualFeedKwd);
pParserData->Option.dwSize = strlen(gstrManualFeedKwd);
StringCchCopyA(pParserData->achXlation, CCHOF(pParserData->achXlation), "");
pParserData->Xlation.dwSize = 0;
if (! (pOption = PvCreateOptionItem(pParserData, GID_INPUTSLOT))) { iResult = PPDERR_MEMORY; } else if (pOption->Invocation.pvData) { TERSE(("%ws: Duplicate entries of '*ManualFeed True' on line %d\n", pParserData->pFile->ptstrFileName, pParserData->pFile->iLineNumber)); } else { ((PTRAYOBJ) pOption)->dwTrayIndex = DMBIN_MANUAL; iResult = IParseInvocation(pParserData, &pOption->Invocation); } } else if (strcmp(pParserData->achOption, gstrFalseKwd) == EQUAL_STRING || strcmp(pParserData->achOption, gstrNoneKwd) == EQUAL_STRING || strcmp(pParserData->achOption, gstrOffKwd) == EQUAL_STRING) { //
// Save *ManualFeed False invocation string separately.
// It's always emitted before any tray invocation string.
//
if (pParserData->ManualFeedFalse.pvData) { WARN_DUPLICATE(); } else { iResult = IParseInvocation(pParserData, &pParserData->ManualFeedFalse); } } else { iResult = ISyntaxError(pParserData->pFile, "Unrecognized ManualFeed option"); }
return iResult; }
//
// Specifies JCLResolution invocation string
//
PPDERROR IJCLResProc( PPARSERDATA pParserData )
{ POPTIONOBJ pOption;
if (! (pOption = PvCreateOptionItem(pParserData, GID_RESOLUTION))) return PPDERR_MEMORY;
if (pOption->Invocation.pvData) { WARN_DUPLICATE(); return PPDERR_NONE; }
pParserData->dwSetResType = RESTYPE_JCL; return IParseInvocation(pParserData, &pOption->Invocation); }
//
// Specifies the default JCLResolution option
//
PPDERROR IDefaultJCLResProc( PPARSERDATA pParserData )
{ return IGenericDefaultProc(pParserData, PCreateFeatureItem(pParserData, GID_RESOLUTION)); }
//
// Specifies SetResolution invocation string
//
PPDERROR ISetResProc( PPARSERDATA pParserData )
{ POPTIONOBJ pOption;
if (! (pOption = PvCreateOptionItem(pParserData, GID_RESOLUTION))) return PPDERR_MEMORY;
if (pOption->Invocation.pvData) { WARN_DUPLICATE(); return PPDERR_NONE; }
pParserData->dwSetResType = RESTYPE_EXITSERVER; return IParseInvocation(pParserData, &pOption->Invocation); }
//
// Specifies default halftone screen angle
//
PPDERROR IScreenAngleProc( PPARSERDATA pParserData )
{ PSTR pstr = pParserData->pstrValue;
if (! BGetFloatFromString(&pstr, &pParserData->fxScreenAngle, FLTYPE_FIX)) return ISyntaxError(pParserData->pFile, "Invalid screen angle");
return PPDERR_NONE; }
//
// Specifies default halftone screen frequency
//
PPDERROR IScreenFreqProc( PPARSERDATA pParserData )
{ PSTR pstr = pParserData->pstrValue;
if (! BGetFloatFromString(&pstr, &pParserData->fxScreenFreq, FLTYPE_FIX) || pParserData->fxScreenFreq <= 0) { return ISyntaxError(pParserData->pFile, "Invalid screen frequency"); } else return PPDERR_NONE; }
//
// Specifies default halftone screen angle for a resolution option
//
PPDERROR IResScreenAngleProc( PPARSERDATA pParserData )
{ PRESOBJ pOption; PSTR pstr = pParserData->pstrValue;
if (! (pOption = PvCreateOptionItem(pParserData, GID_RESOLUTION))) return PPDERR_MEMORY;
if (! BGetFloatFromString(&pstr, &pOption->fxScreenAngle, FLTYPE_FIX)) return ISyntaxError(pParserData->pFile, "Invalid screen angle");
return PPDERR_NONE; }
//
// Specifies default halftone screen frequency for a resolution option
//
PPDERROR IResScreenFreqProc( PPARSERDATA pParserData )
{ PRESOBJ pOption; PSTR pstr = pParserData->pstrValue;
if (! (pOption = PvCreateOptionItem(pParserData, GID_RESOLUTION))) return PPDERR_MEMORY;
if (! BGetFloatFromString(&pstr, &pOption->fxScreenFreq, FLTYPE_FIX) || pOption->fxScreenFreq <= 0) { return ISyntaxError(pParserData->pFile, "Invalid screen frequency"); } else return PPDERR_NONE; }
//
// Specifies device font information
//
PPDERROR IFontProc( PPARSERDATA pParserData )
{ static const STRTABLE FontStatusStrs[] = { "ROM", FONTSTATUS_ROM, "Disk", FONTSTATUS_DISK, NULL, FONTSTATUS_UNKNOWN };
PFONTREC pFont; PSTR pstr; CHAR achWord[MAX_WORD_LEN]; DWORD cbSize;
//
// Create a new device font item
//
if (! (pFont = PvCreateXlatedItem(pParserData, &pParserData->pFonts, sizeof(FONTREC)))) return PPDERR_MEMORY;
if (pFont->pstrEncoding != NULL) { WARN_DUPLICATE(); return PPDERR_NONE; }
//
// encoding
//
pstr = pParserData->pstrValue;
if (! BFindNextWord(&pstr, achWord)) return ISyntaxError(pParserData->pFile, "Invalid *Font entry");
cbSize = strlen(achWord) + 1; if (! (pFont->pstrEncoding = ALLOC_PARSER_MEM(pParserData, cbSize))) return PPDERR_MEMORY;
StringCchCopyA(pFont->pstrEncoding, cbSize / sizeof(char), achWord);
//
// version
//
(VOID) BFindNextWord(&pstr, achWord);
{ PSTR pstrStart, pstrEnd;
if (pstrStart = strchr(achWord, '(')) pstrStart++; else pstrStart = achWord;
if (pstrEnd = strrchr(pstrStart, ')')) *pstrEnd = NUL;
cbSize = strlen(pstrStart) + 1; if (! (pFont->pstrVersion = ALLOC_PARSER_MEM(pParserData, cbSize))) return PPDERR_MEMORY;
StringCchCopyA(pFont->pstrVersion, cbSize / sizeof(char), pstrStart); }
//
// charset
//
(VOID) BFindNextWord(&pstr, achWord);
cbSize = strlen(achWord) + 1; if (! (pFont->pstrCharset = ALLOC_PARSER_MEM(pParserData, cbSize))) return PPDERR_MEMORY;
StringCchCopyA(pFont->pstrCharset, cbSize / sizeof(char), achWord);
//
// status
//
(VOID) BFindNextWord(&pstr, achWord); (VOID) BSearchStrTable(FontStatusStrs, achWord, &pFont->dwStatus);
return PPDERR_NONE; }
//
// Specifies the default device font
//
PPDERROR IDefaultFontProc( PPARSERDATA pParserData )
{ if (strcmp(pParserData->pstrValue, "Error") == EQUAL_STRING) pParserData->pstrDefaultFont = NULL; else if (! (pParserData->pstrDefaultFont = PstrParseString(pParserData, &pParserData->Value))) return PPDERR_MEMORY;
return PPDERR_NONE; }
//
// Mark the beginning of a new printer feature section
//
PPDERROR IOpenUIProc( PPARSERDATA pParserData )
{ static const STRTABLE UITypeStrs[] = { "PickOne", UITYPE_PICKONE, "PickMany", UITYPE_PICKMANY, "Boolean", UITYPE_BOOLEAN, NULL, UITYPE_PICKONE };
PCSTR pstrKeyword;
//
// Guard against nested or unbalanced OpenUI
//
if (pParserData->pOpenFeature != NULL) { TERSE(("Missing CloseUI for *%s\n", pParserData->pOpenFeature->pstrName)); pParserData->pOpenFeature = NULL; }
//
// Make sure the keyword is well-formed
//
if (! (pstrKeyword = PstrStripKeywordChar(pParserData->achOption))) return ISyntaxError(pParserData->pFile, "Empty keyword");
//
// HACK: special-case handling of "*OpenUI: *ManualFeed" entry
//
if (strcmp(pstrKeyword, gstrManualFeedKwd) == EQUAL_STRING) return PPDERR_NONE;
if (! (pParserData->pOpenFeature = PCreateFeatureItem(pParserData, GID_UNKNOWN))) return PPDERR_MEMORY;
//
// Determine the type of feature option list
//
if (! BSearchStrTable(UITypeStrs, pParserData->pstrValue, &pParserData->pOpenFeature->dwUIType)) { ISyntaxError(pParserData->pFile, "Unrecognized UI type"); }
//
// Are we dealing with JCLOpenUI?
//
pParserData->bJclFeature = HAS_JCL_PREFIX(pstrKeyword); return PPDERR_NONE; }
//
// Mark the end of a new printer feature section
//
PPDERROR ICloseUIProc( PPARSERDATA pParserData )
{ PCSTR pstrKeyword; PFEATUREOBJ pOpenFeature;
//
// Make sure the CloseUI entry is balanced with a previous OpenUI entry
//
pOpenFeature = pParserData->pOpenFeature; pParserData->pOpenFeature = NULL; pstrKeyword = PstrStripKeywordChar(pParserData->pstrValue);
//
// HACK: special-case handling of "*CloseUI: *ManualFeed" entry
//
if (pstrKeyword && strcmp(pstrKeyword, gstrManualFeedKwd) == EQUAL_STRING) return PPDERR_NONE;
if (pOpenFeature == NULL || pstrKeyword == NULL || strcmp(pstrKeyword, pOpenFeature->pstrName) != EQUAL_STRING || pParserData->bJclFeature != HAS_JCL_PREFIX(pstrKeyword)) { return ISyntaxError(pParserData->pFile, "Invalid CloseUI entry"); }
return PPDERR_NONE; }
//
// Process OpenGroup and CloseGroup entries
//
// !!! OpenGroup, CloseGroup, OpenSubGroup, and CloseSubGroup
// keywords are not completely supported. Currently, we
// only pay specific attention to the InstallableOptions group.
//
// If the group information is needed in the future by the
// user interface, the following functions should be beefed up.
//
PPDERROR IOpenCloseGroupProc( PPARSERDATA pParserData, BOOL bOpenGroup )
{ PSTR pstrGroupName = pParserData->pstrValue;
//
// We're only interested in the InstallableOptions group
//
if (strcmp(pstrGroupName, "InstallableOptions") == EQUAL_STRING) { if (pParserData->bInstallableGroup == bOpenGroup) return ISyntaxError(pParserData->pFile, "Unbalanced OpenGroup/CloseGroup");
pParserData->bInstallableGroup = bOpenGroup; } else { VERBOSE(("Group %s ignored\n", pstrGroupName)); }
return PPDERR_NONE; }
//
// Process OpenGroup entries
//
PPDERROR IOpenGroupProc( PPARSERDATA pParserData )
{ return IOpenCloseGroupProc(pParserData, TRUE); }
//
// Process CloseGroup entries
//
PPDERROR ICloseGroupProc( PPARSERDATA pParserData )
{ return IOpenCloseGroupProc(pParserData, FALSE); }
//
// Handle OpenSubGroup entries
//
PPDERROR IOpenSubGroupProc( PPARSERDATA pParserData )
{ return PPDERR_NONE; }
//
// Handle CloseSubGroup entries
//
PPDERROR ICloseSubGroupProc( PPARSERDATA pParserData )
{ return PPDERR_NONE; }
//
// Parse a UIConstraints entry
//
PPDERROR IUIConstraintsProc( PPARSERDATA pParserData )
{ PLISTOBJ pItem;
if (! (pItem = ALLOC_PARSER_MEM(pParserData, sizeof(LISTOBJ))) || ! (pItem->pstrName = PstrParseString(pParserData, &pParserData->Value))) { ERR(("Memory allocation failed\n")); return PPDERR_MEMORY; }
pItem->pNext = pParserData->pUIConstraints; pParserData->pUIConstraints = pItem; return PPDERR_NONE; }
//
// Parse an OrderDependency entry
//
PPDERROR IOrderDepProc( PPARSERDATA pParserData )
{ PLISTOBJ pItem;
if (! (pItem = ALLOC_PARSER_MEM(pParserData, sizeof(LISTOBJ))) || ! (pItem->pstrName = PstrParseString(pParserData, &pParserData->Value))) { ERR(("Memory allocation failed\n")); return PPDERR_MEMORY; }
pItem->pNext = pParserData->pOrderDep; pParserData->pOrderDep = pItem; return PPDERR_NONE; }
//
// Parse QueryOrderDependency entries
//
PPDERROR IQueryOrderDepProc( PPARSERDATA pParserData )
{ PLISTOBJ pItem;
if (! (pItem = ALLOC_PARSER_MEM(pParserData, sizeof(LISTOBJ))) || ! (pItem->pstrName = PstrParseString(pParserData, &pParserData->Value))) { ERR(("Memory allocation failed\n")); return PPDERR_MEMORY; }
pItem->pNext = pParserData->pQueryOrderDep; pParserData->pQueryOrderDep = pItem; return PPDERR_NONE; }
//
// Specifies memory configuration information
//
PPDERROR IVMOptionProc( PPARSERDATA pParserData )
{ PMEMOBJ pOption;
if (! (pOption = PvCreateOptionItem(pParserData, GID_MEMOPTION))) return PPDERR_MEMORY;
if (pOption->dwFreeVM) { WARN_DUPLICATE(); return PPDERR_NONE; }
return IParseInteger(pParserData, &pOption->dwFreeVM); }
//
// Specifies font cache size information
//
PPDERROR IFCacheSizeProc( PPARSERDATA pParserData )
{ PMEMOBJ pOption;
if (! (pOption = PvCreateOptionItem(pParserData, GID_MEMOPTION))) return PPDERR_MEMORY;
if (pOption->dwFontMem) { WARN_DUPLICATE(); return PPDERR_NONE; }
return IParseInteger(pParserData, &pOption->dwFontMem); }
//
// Specifies the minimum amount of free VM
//
PPDERROR IFreeVMProc( PPARSERDATA pParserData )
{ return IParseInteger(pParserData, &pParserData->dwFreeMem); }
//
// Include another file
//
PPDERROR IIncludeProc( PPARSERDATA pParserData )
#define MAX_INCLUDE_LEVEL 10
{ WCHAR awchFilename[MAX_PATH]; PFILEOBJ pPreviousFile; PPDERROR iStatus;
if (pParserData->iIncludeLevel >= MAX_INCLUDE_LEVEL) { ERR(("There appears to be recursive *Include.\n")); return PPDERR_FILE; }
if (! MultiByteToWideChar(CP_ACP, 0, pParserData->pstrValue, -1, awchFilename, MAX_PATH)) return ISyntaxError(pParserData->pFile, "Invalid include filename");
VERBOSE(("Including file %ws ...\n", awchFilename));
pPreviousFile = pParserData->pFile; pParserData->iIncludeLevel++;
iStatus = IParseFile(pParserData, awchFilename);
pParserData->iIncludeLevel--; pParserData->pFile = pPreviousFile;
return iStatus; }
//
// Specifies the printer description file format version number
//
PPDERROR IPPDAdobeProc( PPARSERDATA pParserData )
{ return IParseVersionNumber(pParserData, &pParserData->dwSpecVersion); }
//
// Specifies the printer description file format version number
//
PPDERROR IFormatVersionProc( PPARSERDATA pParserData )
{ if (pParserData->dwSpecVersion != 0) return PPDERR_NONE;
return IParseVersionNumber(pParserData, &pParserData->dwSpecVersion); }
//
// Specifies the PPD file version number
//
PPDERROR IFileVersionProc( PPARSERDATA pParserData )
{ return IParseVersionNumber(pParserData, &pParserData->dwPpdFilever); }
//
// Specifies the protocols supported by the device
//
PPDERROR IProtocolsProc( PPARSERDATA pParserData )
{ static const STRTABLE ProtocolStrs[] = { "PJL", PROTOCOL_PJL, "BCP", PROTOCOL_BCP, "TBCP", PROTOCOL_TBCP, "SIC", PROTOCOL_SIC, NULL, 0 };
CHAR achWord[MAX_WORD_LEN]; DWORD dwProtocol; PSTR pstr = pParserData->pstrValue;
while (BFindNextWord(&pstr, achWord)) { if (BSearchStrTable(ProtocolStrs, achWord, &dwProtocol)) pParserData->dwProtocols |= dwProtocol; else TERSE(("Unknown protocol: %s\n", achWord)); }
return PPDERR_NONE; }
//
// Specifies whether the device supports color output
//
PPDERROR IColorDeviceProc( PPARSERDATA pParserData )
{ return IParseBoolean(pParserData, &pParserData->dwColorDevice); }
//
// Specifies whether the device fonts already have the Euro
//
PPDERROR IHasEuroProc( PPARSERDATA pParserData )
{ PPDERROR rc;
if (rc = IParseBoolean(pParserData, &pParserData->bHasEuro) != PPDERR_NONE) return rc;
pParserData->bEuroInformationSet = TRUE;
return PPDERR_NONE; }
//
// Specifies whether the device fonts already have the Euro
//
PPDERROR ITrueGrayProc( PPARSERDATA pParserData )
{ return IParseBoolean(pParserData, &pParserData->bTrueGray); }
//
// Specifies the language extensions supported by the device
//
PPDERROR IExtensionsProc( PPARSERDATA pParserData )
{ static const STRTABLE ExtensionStrs[] = { "DPS", LANGEXT_DPS, "CMYK", LANGEXT_CMYK, "Composite", LANGEXT_COMPOSITE, "FileSystem", LANGEXT_FILESYSTEM, NULL, 0 };
CHAR achWord[MAX_WORD_LEN]; INT dwExtension; PSTR pstr = pParserData->pstrValue;
while (BFindNextWord(&pstr, achWord)) { if (BSearchStrTable(ExtensionStrs, achWord, &dwExtension)) pParserData->dwExtensions |= dwExtension; else TERSE(("Unknown extension: %s\n", achWord)); }
return PPDERR_NONE; }
//
// Specifies whether the device has a file system on disk
//
PPDERROR IFileSystemProc( PPARSERDATA pParserData )
{ DWORD dwFileSystem; PPDERROR iStatus;
if ((iStatus = IParseBoolean(pParserData, &dwFileSystem)) == PPDERR_NONE) { if (dwFileSystem) pParserData->dwExtensions |= LANGEXT_FILESYSTEM; else pParserData->dwExtensions &= ~LANGEXT_FILESYSTEM; }
return iStatus; }
//
// Specifies the device name
//
PPDERROR INickNameProc( PPARSERDATA pParserData )
{ //
// Use NickName only if ShortNickName entry is not present
//
if (pParserData->NickName.pvData == NULL) return IParseInvocation(pParserData, &pParserData->NickName); else return PPDERR_NONE; }
//
// Specifies the short device name
//
PPDERROR IShortNameProc( PPARSERDATA pParserData )
{ pParserData->NickName.dwLength = 0; pParserData->NickName.pvData = NULL;
return IParseInvocation(pParserData, &pParserData->NickName); }
//
// Specifies the PostScript language level
//
PPDERROR ILangLevelProc( PPARSERDATA pParserData )
{ return IParseInteger(pParserData, &pParserData->dwLangLevel); }
//
// Specifies PPD language encoding options
//
PPDERROR ILangEncProc( PPARSERDATA pParserData )
{ //
// NOTE: Only the following two language encodings are supported because
// the rest of them are not used (according to our discussions with Adobe).
// In any case, we don't have any direct way of translating ANSI strings
// in other encodings to Unicode.
//
// A possible future PPD extension is to allow Unicode encoding directly
// in translation strings.
//
static const STRTABLE LangEncStrs[] = { "ISOLatin1", LANGENC_ISOLATIN1, "WindowsANSI", LANGENC_ISOLATIN1, // WindowsANSI means CharSet=0, which is now page 1252->ISO Latin1
"None", LANGENC_NONE, "Unicode", LANGENC_UNICODE, "JIS83-RKSJ", LANGENC_JIS83_RKSJ, NULL, LANGENC_NONE };
if (! BSearchStrTable(LangEncStrs, pParserData->pstrValue, &pParserData->dwLangEncoding)) return ISyntaxError(pParserData->pFile, "Unsupported LanguageEncoding keyword"); else return PPDERR_NONE; }
//
// Identifies the natural language used in the PPD file
//
PPDERROR ILangVersProc( PPARSERDATA pParserData )
{ static const STRTABLE LangVersionStrs[] = {
"English", LANGENC_ISOLATIN1, "Danish", LANGENC_ISOLATIN1, "Dutch", LANGENC_ISOLATIN1, "Finnish", LANGENC_ISOLATIN1, "French", LANGENC_ISOLATIN1, "German", LANGENC_ISOLATIN1, "Italian", LANGENC_ISOLATIN1, "Norwegian", LANGENC_ISOLATIN1, "Portuguese", LANGENC_ISOLATIN1, "Spanish", LANGENC_ISOLATIN1, "Swedish", LANGENC_ISOLATIN1, "Japanese", LANGENC_JIS83_RKSJ, "Chinese", LANGENC_NONE, "Russian", LANGENC_NONE,
NULL, LANGENC_NONE };
if (pParserData->dwLangEncoding == LANGENC_NONE && ! BSearchStrTable(LangVersionStrs, pParserData->pstrValue, &pParserData->dwLangEncoding)) { return ISyntaxError(pParserData->pFile, "Unsupported LanguageVersion keyword"); }
return PPDERR_NONE; }
//
// Specifies the available TrueType rasterizer options
//
PPDERROR ITTRasterizerProc( PPARSERDATA pParserData )
{ static const STRTABLE RasterizerStrs[] = { "None", TTRAS_NONE, "Accept68K", TTRAS_ACCEPT68K, "Type42", TTRAS_TYPE42, "TrueImage", TTRAS_TRUEIMAGE, NULL, TTRAS_NONE };
if (! BSearchStrTable(RasterizerStrs, pParserData->pstrValue, &pParserData->dwTTRasterizer)) return ISyntaxError(pParserData->pFile, "Unknown TTRasterizer option"); else return PPDERR_NONE; }
//
// Specifies the exitserver invocation string
//
PPDERROR IExitServerProc( PPARSERDATA pParserData )
{ return IParseInvocation(pParserData, &pParserData->ExitServer); }
//
// Specifies the password string
//
PPDERROR IPasswordProc( PPARSERDATA pParserData )
{ return IParseInvocation(pParserData, &pParserData->Password); }
//
// Specifies the PatchFile invocation string
//
PPDERROR IPatchFileProc( PPARSERDATA pParserData )
{ return IParseInvocation(pParserData, &pParserData->PatchFile); }
//
// Specifies JobPatchFile invocation strings
//
PPDERROR IJobPatchFileProc( PPARSERDATA pParserData )
{ PJOBPATCHFILEOBJ pItem; PSTR pTmp;
//
// Create a new job patch file item
//
if (! (pItem = PvCreateListItem(pParserData, (PLISTOBJ *) &pParserData->pJobPatchFiles, sizeof(JOBPATCHFILEOBJ), "JobPatchFile"))) { return PPDERR_MEMORY; }
//
// Parse the job patch file invocation string
//
if (pItem->Invocation.pvData) { WARN_DUPLICATE(); return PPDERR_NONE; }
//
// warn if number of patch file is invalid
//
pTmp = pItem->pstrName;
if (!BGetIntegerFromString(&pTmp, &pItem->lPatchNo)) { TERSE(("Warning: invalid JobPatchFile number '%s' on line %d\n", pParserData->achOption, pParserData->pFile->iLineNumber)); pItem->lPatchNo = 0; }
return IParseInvocation(pParserData, &pItem->Invocation); }
//
// Specifies PostScript interpreter version and revision number
//
PPDERROR IPSVersionProc( PPARSERDATA pParserData )
{ PSTR pstr = pParserData->Value.pbuf; DWORD dwVersion; PPDERROR status;
//
// Save the first PSVersion string
//
if ((pParserData->PSVersion.pvData == NULL) && ((status = IParseInvocation(pParserData, &pParserData->PSVersion)) != PPDERR_NONE)) { return status; }
//
// Skip non-digit characters
//
while (*pstr && !IS_DIGIT(*pstr)) pstr++;
//
// Extract the PS interpreter version number
//
dwVersion = 0;
while (*pstr && IS_DIGIT(*pstr)) dwVersion = dwVersion * 10 + (*pstr++ - '0');
if (dwVersion > 0) { //
// Remember the lowest PSVersion number
//
if (pParserData->dwPSVersion == 0 || pParserData->dwPSVersion > dwVersion) pParserData->dwPSVersion = dwVersion;
return PPDERR_NONE; } else return ISyntaxError(pParserData->pFile, "Invalid PSVersion entry"); }
//
// Specifies the Product string
//
PPDERROR IProductProc( PPARSERDATA pParserData )
{ //
// only store the first *Product entry, though there may be multiple
//
if (pParserData->Product.dwLength != 0) return PPDERR_NONE;
return IParseInvocation(pParserData, &pParserData->Product); }
//
// Specifies the default job timeout value
//
PPDERROR IJobTimeoutProc( PPARSERDATA pParserData )
{ return IParseInteger(pParserData, &pParserData->dwJobTimeout); }
//
// Specifies the default wait timeout value
//
PPDERROR IWaitTimeoutProc( PPARSERDATA pParserData )
{ return IParseInteger(pParserData, &pParserData->dwWaitTimeout); }
//
// Specifies whether error handler should be enabled by default
//
PPDERROR IPrintPSErrProc( PPARSERDATA pParserData )
{ DWORD dwValue;
if (IParseBoolean(pParserData, &dwValue) != PPDERR_NONE) return PPDERR_SYNTAX;
if (dwValue) pParserData->dwPpdFlags |= PPDFLAG_PRINTPSERROR; else pParserData->dwPpdFlags &= ~PPDFLAG_PRINTPSERROR;
return PPDERR_NONE; }
//
// Specifies PJL commands to start a job
//
PPDERROR IJCLBeginProc( PPARSERDATA pParserData )
{ pParserData->dwPpdFlags |= PPDFLAG_HAS_JCLBEGIN; return IParseInvocation(pParserData, &pParserData->JclBegin); }
//
// Specifies PJL commands to switch into PostScript language
//
PPDERROR IJCLToPSProc( PPARSERDATA pParserData )
{ pParserData->dwPpdFlags |= PPDFLAG_HAS_JCLENTERPS; return IParseInvocation(pParserData, &pParserData->JclEnterPS); }
//
// Specifies PJL commands to end a job
//
PPDERROR IJCLEndProc( PPARSERDATA pParserData )
{ pParserData->dwPpdFlags |= PPDFLAG_HAS_JCLEND; return IParseInvocation(pParserData, &pParserData->JclEnd); }
//
// Specifies the default landscape orientation mode
//
PPDERROR ILSOrientProc( PPARSERDATA pParserData )
{ static const STRTABLE LsoStrs[] = { "Any", LSO_ANY, "Plus90", LSO_PLUS90, "Minus90", LSO_MINUS90, NULL, LSO_ANY };
if (! BSearchStrTable(LsoStrs, pParserData->pstrValue, &pParserData->dwLSOrientation)) return ISyntaxError(pParserData->pFile, "Unrecognized landscape orientation"); else return PPDERR_NONE; }
PPAPEROBJ PCreateCustomSizeOption( PPARSERDATA pParserData )
/*++
Routine Description:
Create a CustomPageSize option for PageSize feature (if necessary)
Arguments:
pParserData - Points to parser data structure
Return Value:
Pointer to newly created CustomPageSize option item or the existing CustomPageSize option item if it already exists.
NULL if there is an error.
--*/
{ PPAPEROBJ pCustomSize; BUFOBJ SavedBuffer;
//
// Create an item corresponding to *PageSize feature if needed
//
SavedBuffer = pParserData->Option; pParserData->Option.pbuf = (PBYTE) gstrCustomSizeKwd; pParserData->Option.dwSize = strlen(gstrCustomSizeKwd);
pCustomSize = PvCreateOptionItem(pParserData, GID_PAGESIZE);
pParserData->Option = SavedBuffer;
return pCustomSize;; }
//
// Specifies custom paper size invocation string
//
PPDERROR ICustomSizeProc( PPARSERDATA pParserData )
{ PPAPEROBJ pCustomSize;
if (strcmp(pParserData->achOption, gstrTrueKwd) != EQUAL_STRING) { ISyntaxError(pParserData->pFile, "Invalid *CustomPageSize option"); return PPDERR_NONE; }
if (! (pCustomSize = PCreateCustomSizeOption(pParserData))) return PPDERR_MEMORY;
if (pCustomSize->Option.Invocation.pvData) { WARN_DUPLICATE(); return PPDERR_NONE; }
return IParseInvocation(pParserData, &pCustomSize->Option.Invocation); }
//
// Specifies custom paper size parameters
//
PPDERROR IParamCustomProc( PPARSERDATA pParserData )
{ static const STRTABLE CustomParamStrs[] = { "Width", CUSTOMPARAM_WIDTH, "Height", CUSTOMPARAM_HEIGHT, "WidthOffset", CUSTOMPARAM_WIDTHOFFSET, "HeightOffset", CUSTOMPARAM_HEIGHTOFFSET, "Orientation", CUSTOMPARAM_ORIENTATION, NULL, 0 };
CHAR achWord[MAX_WORD_LEN]; LONG lMinVal, lMaxVal; INT iType; DWORD dwParam; LONG lOrder; PSTR pstr = pParserData->pstrValue;
//
// The format for a ParamCustomPageSize entry:
// ParameterName Order Type MinVal MaxVal
//
if (! BSearchStrTable(CustomParamStrs, pParserData->achOption, &dwParam) || ! BGetIntegerFromString(&pstr, &lOrder) || ! BFindNextWord(&pstr, achWord) || lOrder <= 0 || lOrder > CUSTOMPARAM_MAX) { return ISyntaxError(pParserData->pFile, "Bad *ParamCustomPageSize entry"); }
//
// Expected type is "int" for Orientation parameter and "points" for other parameters
//
iType = (dwParam == CUSTOMPARAM_ORIENTATION) ? ((strcmp(achWord, "int") == EQUAL_STRING) ? FLTYPE_INT : FLTYPE_ERROR) : ((strcmp(achWord, "points") == EQUAL_STRING) ? FLTYPE_POINT : FLTYPE_ERROR);
if (iType == FLTYPE_ERROR || ! BGetFloatFromString(&pstr, &lMinVal, iType) || ! BGetFloatFromString(&pstr, &lMaxVal, iType) || lMinVal > lMaxVal) { return ISyntaxError(pParserData->pFile, "Bad *ParamCustomPageSize entry"); }
pParserData->CustomSizeParams[dwParam].dwOrder = lOrder; pParserData->CustomSizeParams[dwParam].lMinVal = lMinVal; pParserData->CustomSizeParams[dwParam].lMaxVal = lMaxVal;
return PPDERR_NONE; }
//
// Specifies the maximum height of custom paper size
//
PPDERROR IMaxWidthProc( PPARSERDATA pParserData )
{ PPAPEROBJ pCustomSize; LONG lValue; PSTR pstr = pParserData->pstrValue;
if (! BGetFloatFromString(&pstr, &lValue, FLTYPE_POINT) || lValue <= 0) return ISyntaxError(pParserData->pFile, "Invalid media width");
if (! (pCustomSize = PCreateCustomSizeOption(pParserData))) return PPDERR_MEMORY;
pCustomSize->szDimension.cx = lValue; return PPDERR_NONE; }
//
// Specifies the maximum height of custom paper size
//
PPDERROR IMaxHeightProc( PPARSERDATA pParserData )
{ PPAPEROBJ pCustomSize; LONG lValue; PSTR pstr = pParserData->pstrValue;
if (! BGetFloatFromString(&pstr, &lValue, FLTYPE_POINT) || lValue <= 0) return ISyntaxError(pParserData->pFile, "Invalid media height");
if (! (pCustomSize = PCreateCustomSizeOption(pParserData))) return PPDERR_MEMORY;
pCustomSize->szDimension.cy = lValue; return PPDERR_NONE; }
//
// Specifies the hardware margins on cut-sheet devices
//
PPDERROR IHWMarginsProc( PPARSERDATA pParserData )
{ PPAPEROBJ pCustomSize; RECT rc; PSTR pstr = pParserData->pstrValue;
//
// Parse hardware margins: left, bottom, right, top
//
if (! BGetFloatFromString(&pstr, &rc.left, FLTYPE_POINT) || ! BGetFloatFromString(&pstr, &rc.bottom, FLTYPE_POINT) || ! BGetFloatFromString(&pstr, &rc.right, FLTYPE_POINT) || ! BGetFloatFromString(&pstr, &rc.top, FLTYPE_POINT)) { return ISyntaxError(pParserData->pFile, "Invalid HWMargins"); }
if (! (pCustomSize = PCreateCustomSizeOption(pParserData))) return PPDERR_MEMORY;
pCustomSize->rcImageArea = rc;
//
// The presence of HWMargins entry indicates the device supports cut-sheet
//
pParserData->dwCustomSizeFlags |= CUSTOMSIZE_CUTSHEET; return PPDERR_NONE; }
//
// Function to process *CenterRegistered entry
//
PPDERROR ICenterRegProc( PPARSERDATA pParserData )
{ DWORD dwValue;
if (IParseBoolean(pParserData, &dwValue) != PPDERR_NONE) return PPDERR_SYNTAX;
if (dwValue) pParserData->dwCustomSizeFlags |= CUSTOMSIZE_CENTERREG; else pParserData->dwCustomSizeFlags &= ~CUSTOMSIZE_CENTERREG;
return PPDERR_NONE; }
//
// Function to process *ADORequiresEExec entry
//
PPDERROR IReqEExecProc( PPARSERDATA pParserData )
{ DWORD dwValue;
if (IParseBoolean(pParserData, &dwValue) != PPDERR_NONE) return PPDERR_SYNTAX;
if (dwValue) pParserData->dwPpdFlags |= PPDFLAG_REQEEXEC; else pParserData->dwPpdFlags &= ~PPDFLAG_REQEEXEC;
return PPDERR_NONE; }
//
// Function to process *ADOTTFontSub entry
//
PPDERROR ITTFontSubProc( PPARSERDATA pParserData )
{ PTTFONTSUB pTTFontSub;
//
// Create a new font substitution item
//
if (! (pTTFontSub = PvCreateXlatedItem( pParserData, &pParserData->pTTFontSubs, sizeof(TTFONTSUB)))) { return PPDERR_MEMORY; }
//
// Parse the PS family name
//
if (pTTFontSub->PSName.pvData) { WARN_DUPLICATE(); return PPDERR_NONE; }
if (*pParserData->pstrValue == NUL) return ISyntaxError(pParserData->pFile, "Missing TrueType font family name");
return IParseInvocation(pParserData, &pTTFontSub->PSName); }
//
// Function to process *Throughput entry
//
PPDERROR IThroughputProc( PPARSERDATA pParserData )
{ return IParseInteger(pParserData, &pParserData->dwThroughput); }
//
// Function to ignore the current entry
//
PPDERROR INullProc( PPARSERDATA pParserData )
{ return PPDERR_NONE; }
//
// Define a named symbol
//
PPDERROR ISymbolValueProc( PPARSERDATA pParserData )
{ PSYMBOLOBJ pSymbol;
if (pParserData->dwValueType == VALUETYPE_SYMBOL) return ISyntaxError(pParserData->pFile, "Symbol value cannot be another symbol");
//
// Create a new symbol item
//
if (! (pSymbol = PvCreateListItem(pParserData, (PLISTOBJ *) &pParserData->pSymbols, sizeof(SYMBOLOBJ), "Symbol"))) { return PPDERR_MEMORY; }
//
// Parse the symbol value
//
if (pSymbol->Invocation.pvData) { WARN_DUPLICATE(); return PPDERR_NONE; }
return IParseInvocation(pParserData, &pSymbol->Invocation); }
//
// Built-in keyword table
//
const CHAR gstrDefault[] = "Default"; const CHAR gstrPageSizeKwd[] = "PageSize"; const CHAR gstrInputSlotKwd[] = "InputSlot"; const CHAR gstrManualFeedKwd[] = "ManualFeed"; const CHAR gstrCustomSizeKwd[] = "CustomPageSize"; const CHAR gstrLetterSizeKwd[] = "Letter"; const CHAR gstrA4SizeKwd[] = "A4"; const CHAR gstrLongKwd[] = "Long"; const CHAR gstrShortKwd[] = "Short"; const CHAR gstrTrueKwd[] = "True"; const CHAR gstrFalseKwd[] = "False"; const CHAR gstrOnKwd[] = "On"; const CHAR gstrOffKwd[] = "Off"; const CHAR gstrNoneKwd[] = "None"; const CHAR gstrVMOptionKwd[] = "VMOption"; const CHAR gstrInstallMemKwd[] = "InstalledMemory"; const CHAR gstrDuplexTumble[] = "DuplexTumble"; const CHAR gstrDuplexNoTumble[] = "DuplexNoTumble";
const KWDENTRY gPpdBuiltInKeywordTable[] = { { gstrPageSizeKwd, NULL, GENERIC_ENTRY(GID_PAGESIZE) }, { "PageRegion", NULL, GENERIC_ENTRY(GID_PAGEREGION) }, { gstrInputSlotKwd, NULL, GENERIC_ENTRY(GID_INPUTSLOT) }, { "MediaType", NULL, GENERIC_ENTRY(GID_MEDIATYPE) }, { "OutputBin", NULL, GENERIC_ENTRY(GID_OUTPUTBIN) }, { "Collate", NULL, GENERIC_ENTRY(GID_COLLATE) }, { "Resolution", NULL, GENERIC_ENTRY(GID_RESOLUTION) }, { "InstalledMemory", NULL, GENERIC_ENTRY(GID_MEMOPTION) }, { "LeadingEdge", NULL, GENERIC_ENTRY(GID_LEADINGEDGE) }, { "UseHWMargins", NULL, GENERIC_ENTRY(GID_USEHWMARGINS) },
{ "Duplex", IDuplexProc, INVOCA_VALUE | REQ_OPTION }, { "DefaultDuplex", IDefaultDuplexProc, STRING_VALUE }, { "PaperDimension", IPaperDimProc, QUOTED_NOHEX | REQ_OPTION }, { "ImageableArea", IImageAreaProc, QUOTED_NOHEX | REQ_OPTION }, { "RequiresPageRegion", IReqPageRgnProc, STRING_VALUE | REQ_OPTION }, { gstrManualFeedKwd, IManualFeedProc, INVOCA_VALUE | REQ_OPTION }, { "DefaultManualFeed", IDefManualFeedProc, STRING_VALUE }, { "PageStackOrder", IPageStackOrderProc, STRING_VALUE | REQ_OPTION }, { "DefaultOutputOrder", IDefOutputOrderProc, STRING_VALUE }, { "JCLResolution", IJCLResProc, INVOCA_VALUE | REQ_OPTION | ALLOW_HEX }, { "DefaultJCLResolution", IDefaultJCLResProc, STRING_VALUE }, { "SetResolution", ISetResProc, INVOCA_VALUE | REQ_OPTION }, { "ScreenAngle", IScreenAngleProc, QUOTED_VALUE }, { "ScreenFreq", IScreenFreqProc, QUOTED_VALUE }, { "ResScreenAngle", IResScreenAngleProc, QUOTED_NOHEX | REQ_OPTION }, { "ResScreenFreq", IResScreenFreqProc, QUOTED_NOHEX | REQ_OPTION }, { "Font", IFontProc, STRING_VALUE | REQ_OPTION }, { "DefaultFont", IDefaultFontProc, STRING_VALUE }, { "OpenUI", IOpenUIProc, STRING_VALUE | REQ_OPTION }, { "CloseUI", ICloseUIProc, STRING_VALUE | ALLOW_MULTI }, { "JCLOpenUI", IOpenUIProc, STRING_VALUE | REQ_OPTION }, { "JCLCloseUI", ICloseUIProc, STRING_VALUE | ALLOW_MULTI }, { "OrderDependency", IOrderDepProc, STRING_VALUE | ALLOW_MULTI }, { "UIConstraints", IUIConstraintsProc, STRING_VALUE | ALLOW_MULTI }, { "QueryOrderDependency", IQueryOrderDepProc, STRING_VALUE | ALLOW_MULTI }, { "NonUIOrderDependency", IOrderDepProc, STRING_VALUE | ALLOW_MULTI }, { "NonUIConstraints", IUIConstraintsProc, STRING_VALUE | ALLOW_MULTI }, { "VMOption", IVMOptionProc, QUOTED_NOHEX | REQ_OPTION }, { "FCacheSize", IFCacheSizeProc, STRING_VALUE | REQ_OPTION }, { "FreeVM", IFreeVMProc, QUOTED_VALUE }, { "OpenGroup", IOpenGroupProc, STRING_VALUE | ALLOW_MULTI }, { "CloseGroup", ICloseGroupProc, STRING_VALUE | ALLOW_MULTI }, { "OpenSubGroup", IOpenSubGroupProc, STRING_VALUE | ALLOW_MULTI }, { "CloseSubGroup", ICloseSubGroupProc, STRING_VALUE | ALLOW_MULTI }, { "Include", IIncludeProc, QUOTED_VALUE | ALLOW_MULTI }, { "PPD-Adobe", IPPDAdobeProc, QUOTED_VALUE }, { "FormatVersion", IFormatVersionProc, QUOTED_VALUE }, { "FileVersion", IFileVersionProc, QUOTED_VALUE }, { "ColorDevice", IColorDeviceProc, STRING_VALUE }, { "Protocols", IProtocolsProc, STRING_VALUE | ALLOW_MULTI }, { "Extensions", IExtensionsProc, STRING_VALUE | ALLOW_MULTI }, { "FileSystem", IFileSystemProc, STRING_VALUE }, { "NickName", INickNameProc, QUOTED_VALUE }, { "ShortNickName", IShortNameProc, QUOTED_VALUE }, { "LanguageLevel", ILangLevelProc, QUOTED_NOHEX }, { "LanguageEncoding", ILangEncProc, STRING_VALUE }, { "LanguageVersion", ILangVersProc, STRING_VALUE }, { "TTRasterizer", ITTRasterizerProc, STRING_VALUE }, { "ExitServer", IExitServerProc, INVOCA_VALUE }, { "Password", IPasswordProc, INVOCA_VALUE }, { "PatchFile", IPatchFileProc, INVOCA_VALUE }, { "JobPatchFile", IJobPatchFileProc, INVOCA_VALUE | REQ_OPTION }, { "PSVersion", IPSVersionProc, QUOTED_NOHEX | ALLOW_MULTI }, { "ModelName", INullProc, QUOTED_VALUE }, { "Product", IProductProc, QUOTED_NOHEX | ALLOW_MULTI }, { "SuggestedJobTimeout", IJobTimeoutProc, QUOTED_VALUE }, { "SuggestedWaitTimeout", IWaitTimeoutProc, QUOTED_VALUE }, { "PrintPSErrors", IPrintPSErrProc, STRING_VALUE }, { "JCLBegin", IJCLBeginProc, QUOTED_VALUE }, { "JCLToPSInterpreter", IJCLToPSProc, QUOTED_VALUE }, { "JCLEnd", IJCLEndProc, QUOTED_VALUE }, { "LandscapeOrientation", ILSOrientProc, STRING_VALUE }, { gstrCustomSizeKwd, ICustomSizeProc, INVOCA_VALUE | REQ_OPTION }, { "ParamCustomPageSize", IParamCustomProc, STRING_VALUE | REQ_OPTION }, { "MaxMediaWidth", IMaxWidthProc, QUOTED_VALUE }, { "MaxMediaHeight", IMaxHeightProc, QUOTED_VALUE }, { "HWMargins", IHWMarginsProc, STRING_VALUE }, { "CenterRegistered", ICenterRegProc, STRING_VALUE }, { "ADORequiresEExec", IReqEExecProc, STRING_VALUE }, { "ADOTTFontSub", ITTFontSubProc, QUOTED_VALUE | REQ_OPTION }, { "ADTrueGray", ITrueGrayProc, STRING_VALUE }, { "ADHasEuro", IHasEuroProc, STRING_VALUE }, { "Throughput", IThroughputProc, QUOTED_NOHEX }, { "SymbolValue", ISymbolValueProc, INVOCA_VALUE | REQ_OPTION }, { "Status", INullProc, QUOTED_VALUE | ALLOW_MULTI }, { "PrinterError", INullProc, QUOTED_VALUE | ALLOW_MULTI }, { "SymbolLength", INullProc, STRING_VALUE | REQ_OPTION }, { "SymbolEnd", INullProc, STRING_VALUE | ALLOW_MULTI }, { "End", INullProc, VALUETYPE_NONE | ALLOW_MULTI }, };
#define NUM_BUILTIN_KEYWORDS (sizeof(gPpdBuiltInKeywordTable) / sizeof(KWDENTRY))
DWORD DwHashKeyword( PSTR pstrKeyword )
/*++
Routine Description:
Compute the hash value for the specified keyword string
Arguments:
pstrKeyword - Pointer to the keyword string to be hashed
Return Value:
Hash value computed using the specified keyword string
--*/
{ PBYTE pub = (PBYTE) pstrKeyword; DWORD dwHashValue = 0;
while (*pub) dwHashValue = (dwHashValue << 1) ^ *pub++;
return dwHashValue; }
PKWDENTRY PSearchKeywordTable( PPARSERDATA pParserData, PSTR pstrKeyword, INT *piIndex )
/*++
Routine Description:
Check if a keyword appears in the built-in keyword table
Arguments:
pParserData - Points to parser data structure pstrKeyword - Specifies the keyword to be searched piIndex - Returns the index of the entry in the built-in keyword table corresponding to the specified keyword.
Return Value:
Pointer to the entry in the built-in table corresponding to the specified keyword. NULL if the specified keyword is not supported.
--*/
{ DWORD dwHashValue; INT iIndex;
ASSERT(pstrKeyword != NULL); dwHashValue = DwHashKeyword(pstrKeyword);
for (iIndex = 0; iIndex < NUM_BUILTIN_KEYWORDS; iIndex++) { if (pParserData->pdwKeywordHashs[iIndex] == dwHashValue && strcmp(gPpdBuiltInKeywordTable[iIndex].pstrKeyword, pstrKeyword) == EQUAL_STRING) { *piIndex = iIndex; return (PKWDENTRY) &gPpdBuiltInKeywordTable[iIndex]; } }
return NULL; }
BOOL BInitKeywordLookup( PPARSERDATA pParserData )
/*++
Routine Description:
Build up data structures to speed up keyword lookup
Arguments:
pParserData - Points to parser data structure
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ DWORD iIndex, iCount;
//
// Allocate memory to hold extra data structures
//
iCount = NUM_BUILTIN_KEYWORDS; pParserData->pdwKeywordHashs = ALLOC_PARSER_MEM(pParserData, iCount * sizeof(DWORD)); pParserData->pubKeywordCounts = ALLOC_PARSER_MEM(pParserData, iCount * sizeof(BYTE));
if (!pParserData->pdwKeywordHashs || !pParserData->pubKeywordCounts) { ERR(("Memory allocation failed: %d\n", GetLastError())); return FALSE; }
//
// Precompute the hash values for built-in keywords
//
for (iIndex = 0; iIndex < iCount; iIndex++) { pParserData->pdwKeywordHashs[iIndex] = DwHashKeyword((PSTR) gPpdBuiltInKeywordTable[iIndex].pstrKeyword); }
return TRUE; }
|