Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2631 lines
56 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
semantic.c
Abstract:
Functions for interpreting the semantics elements of a printer description file
Environment:
PCL-XL driver, XLD parser
Revision History:
12/01/95 -davidx-
Created it.
mm/dd/yy -author-
description
--*/
#include "parser.h"
// Data structure for representing entries in a keyword table
typedef STATUSCODE (*KWDPROC)(PPARSERDATA);
typedef struct {
PSTR pKeyword; // keyword name
KWDPROC proc; // keyword handler function
DWORD flags; // 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 INVOC_VALUE (QUOTED_VALUE|SYMBOL_VALUE)
// Built-in keyword table
extern KWDENTRY BuiltInKeywordTable[];
// Data structure for representing a string table entry
typedef struct {
PSTR pKeyword; // keyword name
INT value; // corresponding value
} STRTABLE, *PSTRTABLE;
// Give a warning when ignoring extra characters at the end of an entry
#define WarnExtraChar(pFile) \
Warning(("Ignore extra character(s) at end of line %d\n", (pFile)->lineNumber))
// Give a warning when ignoring unnecessary translation string
#define WarnExtraXlation(pParserData) \
if (!BufferIsEmpty(&(pParserData)->xlation)) {\
Warning(("Ignore translation string on line %d\n", (pParserData)->pFile->lineNumber));\
}
// Forward declaration of local functions
PKWDENTRY SearchBuiltInKeyword(PSTR);
STATUSCODE VerifyValueType(PPARSERDATA, DWORD);
STATUSCODE GenericFeatureProc(PPARSERDATA, PFEATUREOBJ);
STATUSCODE
InterpretEntry(
PPARSERDATA pParserData
)
/*++
Routine Description:
Interpret an entry parsed from a printer description file
Arguments:
pParserData - Points to parser data structure
Return Value:
Status code
--*/
{
PKWDENTRY pKwdEntry;
PSTR pKeyword;
STATUSCODE status;
//
// Get a pointer to the keyword string
//
pKeyword = (PSTR) pParserData->keyword.pBuffer;
//
// Check if we're within a BeginFeature/EndFeature pair
//
if (pParserData->pOpenFeature &&
pParserData->pOpenFeature->groupId == GID_UNKNOWN &&
strcmp(pKeyword, pParserData->pOpenFeature->pName) == EQUAL_STRING)
{
if ((status = VerifyValueType(pParserData, INVOC_VALUE|REQ_OPTION)) != ERR_NONE)
return status;
return GenericFeatureProc(pParserData, pParserData->pOpenFeature);
}
//
// Handle built-in keywords
//
if (! (pKwdEntry = SearchBuiltInKeyword(pKeyword))) {
Verbose(("Unsupported keyword: %s\n", pKeyword));
return ERR_NONE;
}
if ((status = VerifyValueType(pParserData, pKwdEntry->flags)) != ERR_NONE)
return status;
return (pKwdEntry->proc)(pParserData);
}
PKWDENTRY
SearchBuiltInKeyword(
PSTR pKeyword
)
/*++
Routine Description:
Determine whether the specified keyword is built-in
Arguments:
pKeyword - Specifies a keyword name
Return Value:
Pointer to an entry in the built-in keyword table
NULL if the specified keyword is not built-in
Note:
Since the parser is only invoked to compile ASCII printer description file
to binary version, speed is not a concern here. So we'll bypass hashing
and use the brute-force search algorithm.
--*/
{
PKWDENTRY pKwdEntry = BuiltInKeywordTable;
while (pKwdEntry->pKeyword && strcmp(pKwdEntry->pKeyword, pKeyword) != EQUAL_STRING)
pKwdEntry++;
return pKwdEntry->pKeyword ? pKwdEntry : NULL;
}
STATUSCODE
VerifyValueType(
PPARSERDATA pParserData,
DWORD expectedType
)
/*++
Routine Description:
Verify the value type of the current entry matches what's expected
Arguments:
pParserData - Points to parser data structure
expectedType - Expected value type
Return Value:
Status code
--*/
{
DWORD valueType;
if ((expectedType & REQ_OPTION) && BufferIsEmpty(&pParserData->option))
return SyntaxError(pParserData->pFile, "Missing option field");
if (!(expectedType & REQ_OPTION) && !BufferIsEmpty(&pParserData->option))
return SyntaxError(pParserData->pFile, "Extra option field");
expectedType &= VALUE_TYPE_MASK;
switch (valueType = pParserData->valueType) {
case STRING_VALUE:
if (expectedType & QUOTED_VALUE) {
Warning(("Expect QuotedValue instead of StringValue on line %d\n",
pParserData->pFile->lineNumber));
valueType = QUOTED_VALUE;
}
break;
case QUOTED_VALUE:
if (expectedType & STRING_VALUE) {
Warning(("Expect StringValue instead of QuotedValue on line %d\n",
pParserData->pFile->lineNumber));
if (BufferIsEmpty(&pParserData->value))
return SyntaxError(pParserData->pFile, "Empty string value");
valueType = STRING_VALUE;
}
break;
}
if ((expectedType & valueType) == 0) {
Error(("Expected value type: %s\n",
(expectedType == INVOC_VALUE) ? "InvocationValue" :
(expectedType == QUOTED_VALUE) ? "QuotedValue" :
(expectedType == STRING_VALUE) ? "StringValue" : "NullValue"));
return SyntaxError(pParserData->pFile, "Value type mismatch");
}
return ERR_NONE;
}
BOOL
ParseInteger(
PSTR *ppStr,
PDWORD pVal
)
/*++
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.
pVal - Points to a variable for storing parsed number
Return Value:
TRUE if a number is successfully parsed, FALSE if there is an error
--*/
{
DWORD value;
PSTR pStr = *ppStr;
//
// Skip any leading space characters
//
while (IsSpace(*pStr))
pStr++;
if (! IsDigit(*pStr)) {
Error(("Invalid integer\n"));
return FALSE;
}
//
// NOTE: Overflow conditions are ignored.
// Negative numbers are not allowed.
//
value = 0;
while (IsDigit(*pStr))
value = value * 10 + (*pStr++ - '0');
//
// Skip any trailing space characters
//
while (IsSpace(*pStr))
pStr++;
*ppStr = pStr;
*pVal = value;
return TRUE;
}
BOOL
ParseFloat(
PSTR *ppStr,
double *pVal
)
/*++
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.
pVal - Points to a variable for storing parsed number
Return Value:
TRUE if successful, FALSE if there is an error
Note:
Notations such as .5 and 1. are not allowed.
--*/
{
double value, scale;
PSTR pStr = *ppStr;
//
// Skip any leading space characters
//
while (IsSpace(*pStr))
pStr++;
if (!IsDigit(*pStr)) {
Error(("Invalid floating-point number\n"));
return FALSE;
}
//
// Integer portion
//
value = 0.0;
while (IsDigit(*pStr))
value = value * 10.0 + (*pStr++ - '0');
//
// Fractional portion
//
if (*pStr == '.') {
pStr++;
if (!IsDigit(*pStr)) {
Error(("Invalid floating-point number\n"));
return FALSE;
}
scale = 0.1;
while (IsDigit(*pStr)) {
value += (*pStr++ - '0') * scale;
scale *= 0.1;
}
}
//
// Skip any trailing space characters
//
while (IsSpace(*pStr))
pStr++;
*ppStr = pStr;
*pVal = value;
return TRUE;
}
LONG
UnitToMicron(
WORD unit,
double value
)
/*++
Routine Description:
Convert a measurement from the specified unit to micron
Arguments:
unit - Specifies the unit to be converted from
value - Value measured in the specified unit
Return Value:
Value converted to micron
--*/
{
if (value < MAX_LONG) {
switch (unit) {
case UNIT_INCH:
value *= 25400.0;
break;
case UNIT_POINT:
value *= (25400.0 / 72.0);
break;
case UNIT_MM:
value *= 1000.0;
break;
default:
Assert(FALSE);
}
}
if ((value += 0.5) < MAX_LONG)
return (LONG) value;
Error(("Paper measurement overflow!\n"));
return 0;
}
PSTR
ParseString(
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(!BufferIsEmpty(pBufObj));
if (! (pStr = AllocParserMem(pParserData, pBufObj->size+1))) {
Error(("Memory allocation failed\n"));
} else {
memcpy(pStr, pBufObj->pBuffer, pBufObj->size+1);
}
return pStr;
}
STATUSCODE
ParseInvocation(
PPARSERDATA pParserData,
PINVOCATION 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
--*/
{
if (pParserData->valueType == SYMBOL_VALUE) {
PSTR pSymbolName;
if (! (pSymbolName = ParseString(pParserData, &pParserData->value)))
return ERR_MEMORY;
pInvocation->pData = (PBYTE) pSymbolName;
MarkSymbolInvocation(pInvocation);
} else {
PBYTE pData;
if (! (pData = AllocParserMem(pParserData, pParserData->value.size+1))) {
Error(("Memory allocation failed\n"));
return ERR_MEMORY;
}
pInvocation->pData = pData;
pInvocation->length = pParserData->value.size;
Assert(!IsSymbolInvocation(pInvocation));
memcpy(pData, pParserData->value.pBuffer, pInvocation->length+1);
}
return ERR_NONE;
}
PSTR
FindNextWord(
PSTR *ppStr
)
/*++
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.
Return Value:
Pointer to the next non-space character in a character string
NULL if no word is found
--*/
{
PSTR pWord, pStr = *ppStr;
while (IsSpace(*pStr))
pStr++;
if (*pStr == NUL)
pWord = NULL;
else {
pWord = pStr;
while (*pStr && !IsSpace(*pStr))
pStr++;
if (*pStr != NUL) {
*pStr++ = NUL;
while (IsSpace(*pStr))
pStr++;
}
}
*ppStr = pStr;
return pWord;
}
BOOL
SearchStrTable(
STRTABLE *pTable,
PSTR pKeyword,
INT *pValue
)
/*++
Routine Description:
Search for a keyword from a string table
Arguments:
pTable - Specifies the string table to be search
pKeyword - Specifies the keyword we're interested in
pValue - Points to a variable for stroing value corresponding to the given keyword
Return Value:
TRUE if the given keyword is found in the table, FALSE otherwise
--*/
{
while (pTable->pKeyword && strcmp(pTable->pKeyword, pKeyword) != EQUAL_STRING)
pTable++;
*pValue = pTable->value;
return (pTable->pKeyword != NULL);
}
STATUSCODE
VersionNumberProc(
PPARSERDATA pParserData,
PDWORD pVersion
)
/*++
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
pVersion - Points to a variable for storing the parsed version number
Return Value:
Status code
--*/
{
STATUSCODE status;
PSTR pStr;
DWORD version, revision = 0;
//
// Parse the major version number followed by minor revision number
//
pStr = (PSTR) pParserData->value.pBuffer;
if (! ParseInteger(&pStr, &version))
return SyntaxError(pParserData->pFile, INVALID_VERSION_NUMBER);
if (*pStr == '.') {
pStr++;
if (! ParseInteger(&pStr, &revision))
return SyntaxError(pParserData->pFile, INVALID_VERSION_NUMBER);
}
//
// High-order word contains version number and
// low-order word contains revision number
//
if (version > MAX_WORD || revision > MAX_WORD)
return SyntaxError(pParserData->pFile, INVALID_VERSION_NUMBER);
*pVersion = (version << 16) | revision;
if (*pStr != NUL) {
WarnExtraChar(pParserData->pFile);
}
return ERR_NONE;
}
PVOID
FindListItem(
PVOID pList,
PSTR pName,
PWORD pIndex
)
/*++
Routine Description:
Find a named item from a linked-list
Arguments:
pParserData - Points to parser data structure
pName - Specifies the item name to be found
pIndex - 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 = pList;
WORD index = 0;
while (pItem && strcmp(pItem->pName, pName) != EQUAL_STRING) {
index++;
pItem = pItem->pNext;
}
if (pIndex)
*pIndex = pItem ? index : SELIDX_NONE;
return pItem;
}
WORD
CountListItem(
PVOID pList
)
/*++
Routine Description:
Count the number of items in a linked-list
Arguments:
pList - Points to a linked-list
Return Value:
Number of items in a linked-list
--*/
{
WORD count = 0;
PLISTOBJ pItem = pList;
while (pItem != NULL) {
count++;
pItem = pItem->pNext;
}
return count;
}
PVOID
CreateListItem(
PPARSERDATA pParserData,
PLISTOBJ *ppList,
DWORD itemSize,
PSTR pListTag
)
/*++
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
itemSize - Linked-list item size
pListTag - Specifies the name of the linked-list
Return Value:
Pointer to newly created linked-list item
NULL if there is an error
--*/
{
PLISTOBJ pItem;
PSTR pItemName;
//
// Check if the item appeared in the list already
// Create a new item data structure if not
//
pItem = FindListItem(*ppList, (PSTR) pParserData->option.pBuffer, NULL);
if (pItem != NULL) {
if (pListTag) {
Warning(("%s '%s' redefined\n", pListTag, pItem->pName));
}
} else {
if (!(pItem = AllocParserMem(pParserData, itemSize)) ||
!(pItemName = ParseString(pParserData, &pParserData->option)))
{
Error(("Memory allocation failed\n"));
return NULL;
}
//
// Put the newly created item at the front of the linked-list
//
memset(pItem, 0, itemSize);
pItem->pName = pItemName;
pItem->pNext = *ppList;
*ppList = pItem;
}
return pItem;
}
PFEATUREOBJ
CreateFeatureItem(
PPARSERDATA pParserData,
WORD groupId
)
/*++
Routine Description:
Create a new printer feature structure or find an existing one
Arguments:
pParserData - Points to parser data structure
groupId - Printer feature group identifier
Return Value:
Pointer to a newly created or an existing printer feature structure
NULL if there is an error
--*/
{
static struct {
PSTR pKeyword;
WORD groupId;
WORD itemSize;
} featureInfo[] = {
"PageSize", GID_PAPERSIZE, sizeof(PAPEROBJ),
"InputSlot", GID_INPUTSLOT, sizeof(OPTIONOBJ),
"OutputBin", GID_OUTPUTBIN, sizeof(OPTIONOBJ),
"MediaType", GID_MEDIATYPE, sizeof(OPTIONOBJ),
"Duplex", GID_DUPLEX, sizeof(OPTIONOBJ),
"Collate", GID_COLLATE, sizeof(OPTIONOBJ),
"Resolution", GID_RESOLUTION, sizeof(RESOBJ),
"MemoryOption", GID_MEMOPTION, sizeof(MEMOBJ),
NULL, GID_UNKNOWN, sizeof(OPTIONOBJ)
};
PFEATUREOBJ pFeature;
PSTR pKeyword;
INT index = 0;
if (groupId == GID_UNKNOWN) {
//
// Given a feature name, first find out if it refers to
// one of the predefined features
//
pKeyword = (PSTR) pParserData->option.pBuffer;
while (featureInfo[index].pKeyword &&
strcmp(featureInfo[index].pKeyword, pKeyword) != EQUAL_STRING)
{
index++;
}
if (!(pFeature = CreateListItem(pParserData,
(PLISTOBJ *) &pParserData->pFeatures,
sizeof(FEATUREOBJ),
NULL)) ||
(!BufferIsEmpty(&pParserData->xlation) &&
!(pFeature->pXlation = ParseString(pParserData, &pParserData->xlation))))
{
return NULL;
}
} else {
BUFOBJ savedBuffer;
//
// We're given a predefined feature identifier.
// Map to its corresponding feature name.
//
while (featureInfo[index].pKeyword && groupId != featureInfo[index].groupId)
index++;
pKeyword = featureInfo[index].pKeyword;
Assert(pKeyword != NULL);
savedBuffer = pParserData->option;
pParserData->option.pBuffer = (PBYTE) pKeyword;
pParserData->option.size = strlen(pKeyword);
pFeature = CreateListItem(pParserData,
(PLISTOBJ *) &pParserData->pFeatures,
sizeof(FEATUREOBJ),
NULL);
pParserData->option = savedBuffer;
}
if (pFeature) {
//
// Get information about newly created feature item
//
pFeature->groupId = featureInfo[index].groupId;
if (pFeature->groupId == GID_MEMOPTION) {
pFeature->installable = TRUE;
pFeature->section = SECTION_NONE;
} else {
pFeature->installable = FALSE;
pFeature->section = SECTION_DOCSETUP;
}
pFeature->itemSize = featureInfo[index].itemSize;
}
return pFeature;
}
STATUSCODE
GenericFeatureProc(
PPARSERDATA pParserData,
PFEATUREOBJ pFeature
)
/*++
Routine Description:
Function for handling a generic feature selection entry
Arguments:
pParserData - Points to parser data structure
pFeature - Points to feature data structure
Return Value:
Status code
--*/
{
POPTIONOBJ pOption;
//
// Special case
//
if (pFeature == NULL)
return ERR_MEMORY;
//
// Create a feature selection item and parse
// the option name and translation string
//
if (!(pOption = CreateListItem(pParserData,
(PLISTOBJ *) &pFeature->pOptions,
pFeature->itemSize,
NULL)) ||
(!BufferIsEmpty(&pParserData->xlation) &&
!(pOption->pXlation = ParseString(pParserData, &pParserData->xlation))))
{
return ERR_MEMORY;
}
if (pOption->invocation.pData) {
Warning(("Duplicate entry for %s %s\n", pFeature->pName, pOption->pName));
}
//
// Parse the invocation string
//
return ParseInvocation(pParserData, &pOption->invocation);
}
STATUSCODE
IncludeDataFileProc(
PPARSERDATA pParserData,
PSYMBOLOBJ *pSymList
)
{
PSYMBOLOBJ pListItem;
WCHAR unicodeFilename[MAX_PATH];
PVOID pFileData;
DWORD fileSize;
HFILEMAP hFileMap;
PBYTE pSymbolData;
WarnExtraXlation(pParserData);
//
// Create a new symbol item
//
if (! (pListItem = CreateListItem(pParserData,
(PLISTOBJ *) pSymList,
sizeof(SYMBOLOBJ),
(PSTR) pParserData->keyword.pBuffer)))
{
return ERR_MEMORY;
}
//
// Convert filename to Unicode
//
Assert(pParserData->valueType != SYMBOL_VALUE);
CopyStr2Unicode(unicodeFilename, (PSTR) pParserData->value.pBuffer, MAX_PATH);
//
// Map the symbol file into memory
//
if (! (hFileMap = MapFileIntoMemory(unicodeFilename, &pFileData, &fileSize))) {
Error(("Couldn't open file: %ws\n", unicodeFilename));
return ERR_FILE;
}
//
// Allocate a memory buffer and copy the content of symbol file into it
//
if (! (pSymbolData = AllocParserMem(pParserData, fileSize))) {
Error(("Memory allocation failed\n"));
UnmapFileFromMemory(hFileMap);
return ERR_MEMORY;
}
memcpy(pSymbolData, pFileData, fileSize);
UnmapFileFromMemory(hFileMap);
pListItem->invocation.pData = pSymbolData;
pListItem->invocation.length = fileSize;
Assert(!IsSymbolInvocation(&pListItem->invocation));
return ERR_NONE;
}
// Mark the beginning of a new printer feature section
STATUSCODE
BeginFeatureProc(
PPARSERDATA pParserData
)
{
if (pParserData->pOpenFeature != NULL)
return SyntaxError(pParserData->pFile, "Nested BeginFeature entry");
if (!(pParserData->pOpenFeature = CreateFeatureItem(pParserData, GID_UNKNOWN)) ||
!(pParserData->pOpenFeature->pDefault = ParseString(pParserData, &pParserData->value)))
{
return ERR_MEMORY;
}
return ERR_NONE;
}
// Mark the end of a printer feature section
STATUSCODE
EndFeatureProc(
PPARSERDATA pParserData
)
{
if (pParserData->pOpenFeature == NULL ||
strcmp(pParserData->pOpenFeature->pName, (PSTR) pParserData->value.pBuffer) != EQUAL_STRING)
{
return SyntaxError(pParserData->pFile, "Unbalanced EndFeature entry");
}
pParserData->pOpenFeature = NULL;
return ERR_NONE;
}
// Specifies a list of installable options
STATUSCODE
InsOptionProc(
PPARSERDATA pParserData
)
{
PLISTOBJ pItem;
// Create a new installable options item
if (!(pItem = AllocParserMem(pParserData, sizeof(LISTOBJ))) ||
!(pItem->pName = ParseString(pParserData, &pParserData->value)))
{
Error(("Memory allocation failed\n"));
return ERR_MEMORY;
}
pItem->pNext = pParserData->pInstallableOptions;
pParserData->pInstallableOptions = pItem;
return ERR_NONE;
}
// Specifies feature constraints
STATUSCODE
ConstraintsProc(
PPARSERDATA pParserData
)
{
PLISTOBJ pItem;
// Create a new feature constraint item
if (!(pItem = AllocParserMem(pParserData, sizeof(LISTOBJ))) ||
!(pItem->pName = ParseString(pParserData, &pParserData->value)))
{
Error(("Memory allocation failed\n"));
return ERR_MEMORY;
}
pItem->pNext = pParserData->pConstraints;
pParserData->pConstraints = pItem;
return ERR_NONE;
}
// Specifies feature dependencies
STATUSCODE
DependencyProc(
PPARSERDATA pParserData
)
{
PLISTOBJ pItem;
// Create a new feature dependency item
if (!(pItem = AllocParserMem(pParserData, sizeof(LISTOBJ))) ||
!(pItem->pName = ParseString(pParserData, &pParserData->value)))
{
Error(("Memory allocation failed\n"));
return ERR_MEMORY;
}
pItem->pNext = pParserData->pDependencies;
pParserData->pDependencies = pItem;
return ERR_NONE;
}
// Specifies paper size information
STATUSCODE
PageSizeProc(
PPARSERDATA pParserData
)
{
return GenericFeatureProc(pParserData, CreateFeatureItem(pParserData, GID_PAPERSIZE));
}
// Specifies paper dimension information
STATUSCODE
PaperDimProc(
PPARSERDATA pParserData
)
{
PFEATUREOBJ pFeature;
PPAPEROBJ pOption;
PSTR pStr;
double width, height;
if (! (pFeature = CreateFeatureItem(pParserData, GID_PAPERSIZE)))
return ERR_MEMORY;
if (!(pOption = CreateListItem(pParserData,
(PLISTOBJ *) &pFeature->pOptions,
pFeature->itemSize,
NULL)) ||
(!BufferIsEmpty(&pParserData->xlation) &&
!(pOption->pXlation = ParseString(pParserData, &pParserData->xlation))))
{
return ERR_MEMORY;
}
if (pOption->size.cx || pOption->size.cy) {
Warning(("Duplicate entry for PaperDimension %s\n", pOption->pName));
}
//
// Parse paper width and height
//
pStr = (PSTR) pParserData->value.pBuffer;
if (!ParseFloat(&pStr, &width) || !ParseFloat(&pStr, &height))
return SyntaxError(pParserData->pFile, "Invalid paper dimension");
pOption->size.cx = UnitToMicron(pParserData->unit, width);
pOption->size.cy = UnitToMicron(pParserData->unit, height);
if (*pStr != NUL) {
WarnExtraChar(pParserData->pFile);
}
return ERR_NONE;
}
// Specifies imageable area information
STATUSCODE
ImageAreaProc(
PPARSERDATA pParserData
)
{
PFEATUREOBJ pFeature;
PPAPEROBJ pOption;
PSTR pStr;
double left, top, right, bottom;
if (! (pFeature = CreateFeatureItem(pParserData, GID_PAPERSIZE)))
return ERR_MEMORY;
if (!(pOption = CreateListItem(pParserData,
(PLISTOBJ *) &pFeature->pOptions,
pFeature->itemSize,
NULL)) ||
(!BufferIsEmpty(&pParserData->xlation) &&
!(pOption->pXlation = ParseString(pParserData, &pParserData->xlation))))
{
return ERR_MEMORY;
}
if (pOption->imageableArea.left || pOption->imageableArea.top ||
pOption->imageableArea.right || pOption->imageableArea.bottom)
{
Warning(("Duplicate entry for ImageableArea %s\n", pOption->pName));
}
//
// Parse imageable area: left, top, right, bottom
//
pStr = (PSTR) pParserData->value.pBuffer;
if (!ParseFloat(&pStr, &left) || !ParseFloat(&pStr, &top) ||
!ParseFloat(&pStr, &right) || !ParseFloat(&pStr, &bottom))
{
return SyntaxError(pParserData->pFile, "Invalid imageable area");
}
pOption->imageableArea.left = UnitToMicron(pParserData->unit, left);
pOption->imageableArea.top = UnitToMicron(pParserData->unit, top);
pOption->imageableArea.right = UnitToMicron(pParserData->unit, right);
pOption->imageableArea.bottom = UnitToMicron(pParserData->unit, bottom);
if (*pStr != NUL) {
WarnExtraChar(pParserData->pFile);
}
return ERR_NONE;
}
// Specifies custom paper size information
STATUSCODE
CustomSizeProc(
PPARSERDATA pParserData
)
{
PSTR pStr;
double maxWidth, maxHeight;
pStr = (PSTR) pParserData->value.pBuffer;
if (!ParseFloat(&pStr, &maxWidth) || !ParseFloat(&pStr, &maxHeight))
return SyntaxError(pParserData->pFile, "Invalid custom paper size");
pParserData->maxCustomSize.cx = UnitToMicron(pParserData->unit, maxWidth);
pParserData->maxCustomSize.cy = UnitToMicron(pParserData->unit, maxHeight);
if (*pStr != NUL) {
WarnExtraChar(pParserData->pFile);
}
return ERR_NONE;
}
// Specifies input slot information
STATUSCODE
InputSlotProc(
PPARSERDATA pParserData
)
{
return GenericFeatureProc(pParserData, CreateFeatureItem(pParserData, GID_INPUTSLOT));
}
// Specifies media type information
STATUSCODE
MediaTypeProc(
PPARSERDATA pParserData
)
{
return GenericFeatureProc(pParserData, CreateFeatureItem(pParserData, GID_MEDIATYPE));
}
// Specifies output bin information
STATUSCODE
OutputBinProc(
PPARSERDATA pParserData
)
{
return GenericFeatureProc(pParserData, CreateFeatureItem(pParserData, GID_OUTPUTBIN));
}
// Specifies information about duplex feature
STATUSCODE
DuplexProc(
PPARSERDATA pParserData
)
{
return GenericFeatureProc(pParserData, CreateFeatureItem(pParserData, GID_DUPLEX));
}
// Specifies information about collation feature
STATUSCODE
CollateProc(
PPARSERDATA pParserData
)
{
return GenericFeatureProc(pParserData, CreateFeatureItem(pParserData, GID_COLLATE));
}
// Specifies information about collation feature
// Specifies resolution information
STATUSCODE
ResolutionProc(
PPARSERDATA pParserData
)
{
return GenericFeatureProc(pParserData, CreateFeatureItem(pParserData, GID_RESOLUTION));
}
// Specifies memory configuration information
STATUSCODE
MemOptionProc(
PPARSERDATA pParserData
)
{
return GenericFeatureProc(pParserData, CreateFeatureItem(pParserData, GID_MEMOPTION));
}
// Specifies information about a device font
STATUSCODE
FontProc(
PPARSERDATA pParserData
)
{
PFONTREC pFont;
PSTR pFontEnc, pFontMtx, pStr;
//
// Create a new device font item
//
if (!(pFont = CreateListItem(pParserData,
(PLISTOBJ *) &pParserData->pFonts,
sizeof(FONTREC),
"Font")) ||
(!BufferIsEmpty(&pParserData->xlation) &&
!(pFont->pXlation = ParseString(pParserData, &pParserData->xlation))))
{
return ERR_MEMORY;
}
//
// Parse font encoding and font metrics information
//
pStr = (PSTR) pParserData->value.pBuffer;
pFontEnc = FindNextWord(&pStr);
pFontMtx = FindNextWord(&pStr);
//
// Parse font metrics information
//
if (!pFontMtx || !pFontEnc)
return SyntaxError(pParserData->pFile, "Invalid Font entry");
if (!(pFont->pFontMtx = AllocParserMem(pParserData, strlen(pFontMtx)+1)) ||
!(pFont->pFontEnc = AllocParserMem(pParserData, strlen(pFontEnc)+1)))
{
return ERR_MEMORY;
}
strcpy(pFont->pFontMtx, pFontMtx);
strcpy(pFont->pFontEnc, pFontEnc);
if (*pStr == NUL) {
WarnExtraChar(pParserData->pFile);
}
return ERR_NONE;
}
// Specifies font metrics information
STATUSCODE
FontMtxProc(
PPARSERDATA pParserData
)
{
return IncludeDataFileProc(pParserData, &pParserData->pFontMtx);
}
// Specifies font encoding information
STATUSCODE
FontEncProc(
PPARSERDATA pParserData
)
{
return IncludeDataFileProc(pParserData, &pParserData->pFontEnc);
}
// Define a symbol - value is provided as quoted string
STATUSCODE
SymbolProc(
PPARSERDATA pParserData
)
{
PSYMBOLOBJ pSymbol;
STATUSCODE status;
WarnExtraXlation(pParserData);
//
// Create a new symbol item
//
if (! (pSymbol = CreateListItem(pParserData,
(PLISTOBJ *) &pParserData->pSymbols,
sizeof(SYMBOLOBJ),
"Symbol")))
{
return ERR_MEMORY;
}
//
// Parse the symbol value
//
Assert(pParserData->valueType != SYMBOL_VALUE);
return ParseInvocation(pParserData, &pSymbol->invocation);
}
// Define a symbol - value is provided in another file
STATUSCODE
SymbolIncProc(
PPARSERDATA pParserData
)
{
return IncludeDataFileProc(pParserData, &pParserData->pSymbols);
}
// Include another file
STATUSCODE
IncludeProc(
PPARSERDATA pParserData
)
{
WCHAR unicodeFilename[MAX_PATH];
PFILEOBJ pPreviousFile;
STATUSCODE status;
pPreviousFile = pParserData->pFile;
CopyStr2Unicode(unicodeFilename, (PSTR) pParserData->value.pBuffer, MAX_PATH);
status = ParseFile(pParserData, unicodeFilename);
pParserData->pFile = pPreviousFile;
return status;
}
// Specifies printer description file format version number
STATUSCODE
SpecVerProc(
PPARSERDATA pParserData
)
{
return VersionNumberProc(pParserData, &pParserData->specVersion);
}
// Specifies file version number
STATUSCODE
FileVerProc(
PPARSERDATA pParserData
)
{
return VersionNumberProc(pParserData, &pParserData->fileVersion);
}
// Specifies PCL-XL protocol version number
STATUSCODE
XLVerProc(
PPARSERDATA pParserData
)
{
return VersionNumberProc(pParserData, &pParserData->xlProtocol);
}
// Specifies the product vendor name
STATUSCODE
VendorProc(
PPARSERDATA pParserData
)
{
return !(pParserData->pVendorName = ParseString(pParserData, &pParserData->value)) ?
ERR_MEMORY : ERR_NONE;
}
// Specifies the product model name
STATUSCODE
ModelProc(
PPARSERDATA pParserData
)
{
return !(pParserData->pModelName = ParseString(pParserData, &pParserData->value)) ?
ERR_MEMORY : ERR_NONE;
}
// Specifies the control code to put at the beginning of a job
STATUSCODE
JCLBeginProc(
PPARSERDATA pParserData
)
{
Assert(pParserData->valueType != SYMBOL_VALUE);
return ParseInvocation(pParserData, &pParserData->jclBegin);
}
// Specifies the job control code to switch to PCL-XL language
STATUSCODE
JCLEnterProc(
PPARSERDATA pParserData
)
{
Assert(pParserData->valueType != SYMBOL_VALUE);
return ParseInvocation(pParserData, &pParserData->jclEnterLanguage);
}
// Specifies the control code to put at the end of a job
STATUSCODE
JCLEndProc(
PPARSERDATA pParserData
)
{
Assert(pParserData->valueType != SYMBOL_VALUE);
return ParseInvocation(pParserData, &pParserData->jclEnd);
}
// Specifies color depth information
STATUSCODE
ColorProc(
PPARSERDATA pParserData
)
{
DWORD numPlanes, bitsPerPlane;
PSTR pStr;
// Number of color planes followed by bits-per-plane
pStr = (PSTR) pParserData->value.pBuffer;
if (!ParseInteger(&pStr, &numPlanes) || !ParseInteger(&pStr, &bitsPerPlane) ||
numPlanes*bitsPerPlane == 0 || numPlanes*bitsPerPlane > 32)
{
return SyntaxError(pParserData->pFile, "Invalid color depth information");
}
pParserData->numPlanes = (WORD) numPlanes;
pParserData->bitsPerPlane = (WORD) bitsPerPlane;
if (*pStr != NUL) {
WarnExtraChar(pParserData->pFile);
}
return ERR_NONE;
}
// Enable or disable embedded hexdecimal strings
STATUSCODE
HexStrProc(
PPARSERDATA pParserData
)
{
static STRTABLE OnOffStrs[] = {
"On", TRUE,
"Off", FALSE,
NULL, 0
};
INT value;
if (!SearchStrTable(OnOffStrs, (PSTR) pParserData->value.pBuffer, &value))
return SyntaxError(pParserData->pFile, UNRECOGNIZED_KEYWORD);
pParserData->allowHexStr = value;
return ERR_NONE;
}
// Specifies the current unit used for paper size, etc.
STATUSCODE
UnitProc(
PPARSERDATA pParserData
)
{
static STRTABLE UnitStrs[] = {
"Inch", UNIT_INCH,
"Point", UNIT_POINT,
"Millimeter", UNIT_MM,
NULL, UNIT_INCH
};
INT value;
if (!SearchStrTable(UnitStrs, (PSTR) pParserData->value.pBuffer, &value))
return SyntaxError(pParserData->pFile, UNRECOGNIZED_KEYWORD);
pParserData->unit = (WORD) value;
return ERR_NONE;
}
// Inform the parser to echo a debug message on the screen
STATUSCODE
EchoProc(
PPARSERDATA pParserData
)
{
#if DBG
DbgPrint("%s", pParserData->value.pBuffer);
#endif
return ERR_NONE;
}
// Built-in keyword table
KWDENTRY BuiltInKeywordTable[] = {
{ "BeginFeature", BeginFeatureProc, STRING_VALUE|REQ_OPTION },
{ "EndFeature", EndFeatureProc, STRING_VALUE },
{ "InstallableOptions", InsOptionProc, STRING_VALUE },
{ "UIConstraints", ConstraintsProc, STRING_VALUE },
{ "OrderDependency", DependencyProc, STRING_VALUE },
{ "PageSize", PageSizeProc, INVOC_VALUE |REQ_OPTION },
{ "PaperDimension", PaperDimProc, STRING_VALUE|REQ_OPTION },
{ "ImageableArea", ImageAreaProc, STRING_VALUE|REQ_OPTION },
{ "CustomPaperSize", CustomSizeProc, STRING_VALUE },
{ "InputSlot", InputSlotProc, INVOC_VALUE |REQ_OPTION },
{ "MediaType", MediaTypeProc, INVOC_VALUE |REQ_OPTION },
{ "OutputBin", OutputBinProc, INVOC_VALUE |REQ_OPTION },
{ "Duplex", DuplexProc, INVOC_VALUE |REQ_OPTION },
{ "Collate", CollateProc, INVOC_VALUE |REQ_OPTION },
{ "Resolution", ResolutionProc, INVOC_VALUE |REQ_OPTION },
{ "MemoryOption", MemOptionProc, QUOTED_VALUE|REQ_OPTION },
{ "Font", FontProc, STRING_VALUE|REQ_OPTION },
{ "FontMetrics", FontMtxProc, QUOTED_VALUE|REQ_OPTION },
{ "FontEncoding", FontEncProc, QUOTED_VALUE|REQ_OPTION },
{ "Symbol", SymbolProc, QUOTED_VALUE|REQ_OPTION },
{ "SymbolInclude", SymbolIncProc, QUOTED_VALUE|REQ_OPTION },
{ "Include", IncludeProc, QUOTED_VALUE },
{ "SpecVersion", SpecVerProc, STRING_VALUE },
{ "FileVersion", FileVerProc, STRING_VALUE },
{ "XLProtocol", XLVerProc, STRING_VALUE },
{ "VendorName", VendorProc, QUOTED_VALUE },
{ "ModelName", ModelProc, QUOTED_VALUE },
{ "JCLBegin", JCLBeginProc, QUOTED_VALUE },
{ "JCLEnterLanguage", JCLEnterProc, QUOTED_VALUE },
{ "JCLEnd", JCLEndProc, QUOTED_VALUE },
{ "ColorDepth", ColorProc, STRING_VALUE },
{ "QuotedHexString", HexStrProc, STRING_VALUE },
{ "Unit", UnitProc, STRING_VALUE },
{ "Echo", EchoProc, QUOTED_VALUE },
// Last entry
{ NULL, 0, 0 }
};
VOID
ValidateInstallableOptionsEntries(
PPARSERDATA pParserData
)
/*++
Routine Description:
Validate InstallableOptions entries in a printer description file
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
PFEATUREOBJ pFeature;
PLISTOBJ pList;
PSTR pKeyword, pStr;
INT index;
// List of predefined features which must not be installable
static WORD docStickyFeatureIds[] = {
GID_PAPERSIZE,
GID_INPUTSLOT,
GID_OUTPUTBIN,
GID_MEDIATYPE,
GID_DUPLEX,
GID_COLLATE,
GID_RESOLUTION,
GID_UNKNOWN
};
pList = pParserData->pInstallableOptions;
while (pList != NULL) {
pStr = pList->pName;
pList = pList->pNext;
while (pKeyword = FindNextWord(&pStr)) {
if (IsKeywordChar(*pKeyword))
pKeyword++;
else {
Warning(("Invalid InstallableOptions entry:\n"));
Warning((" Missing keyword character in front of %s\n", pKeyword));
}
if (!(pFeature = FindListItem(pParserData->pFeatures, pKeyword, NULL))) {
Warning(("Invalid InstallableOptions entry:\n"));
Warning((" Unkown feature: %s\n", pKeyword));
} else {
for (index=0; docStickyFeatureIds[index] != GID_UNKNOWN; index++) {
if (docStickyFeatureIds[index] == pFeature->groupId) {
Error(("%s cannot be an installable option\n", pFeature->pName));
pParserData->errors++;
break;
}
}
pFeature->installable = TRUE;
pFeature->section = SECTION_NONE;
}
}
}
}
VOID
ValidateOrderDependencyEntries(
PPARSERDATA pParserData
)
/*++
Routine Description:
Validate OrderDependency entries in a printer description file
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
static STRTABLE SectionStrs[] = {
"JobSetup", SECTION_JOBSETUP,
"DocSetup", SECTION_DOCSETUP,
"PageSetup", SECTION_PAGESETUP,
"Trailer", SECTION_TRAILER,
"None", SECTION_NONE,
NULL, SECTION_NONE
};
PFEATUREOBJ pFeature;
PLISTOBJ pList;
PSTR pKeyword, pStr;
pList = pParserData->pDependencies;
while (pList != NULL) {
INT section;
DWORD order;
pKeyword = pList->pName;
pList = pList->pNext;
if (!ParseInteger(&pKeyword, &order) || order > MAX_WORD ||
!(pStr = FindNextWord(&pKeyword)) ||
!SearchStrTable(SectionStrs, pStr, &section))
{
Warning(("Invalid OrderDependency entry: %s\n", pKeyword));
} else {
if (IsKeywordChar(*pKeyword))
pKeyword++;
else {
Warning(("Invalid OrderDependency entry:\n"));
Warning((" Missing keyword character in front of %s\n", pKeyword));
}
if (!(pFeature = FindListItem(pParserData->pFeatures, pKeyword, NULL))) {
Warning(("Invalid OrderDependency entry:\n"));
Warning((" Unknown feature: %s\n", pKeyword));
} else {
pFeature->section = (WORD) section;
pFeature->order = (WORD) order;
}
}
}
}
VOID
ValidateUiConstraintsEntries(
PPARSERDATA pParserData
)
/*++
Routine Description:
Validate UIConstraints entries in a printer description file
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
PCONSTRAINT pConstraints;
PLISTOBJ pItem;
WORD cConstraints;
if ((pParserData->cConstraints = CountListItem(pParserData->pConstraints)) == 0)
return;
//
// Allocate memory to hold packed constraint data
//
pConstraints = AllocParserMem(pParserData, sizeof(CONSTRAINT)*pParserData->cConstraints);
if (pConstraints == NULL) {
Error(("Memory allocate failed\n"));
pParserData->errors++;
return;
}
// NOTE: The memory used to hold original constraint entries is allocated from
// the parser memory heap. It'll be automatically freed when the heap is destroyed.
pItem = pParserData->pConstraints;
pParserData->pConstraints = (PLISTOBJ) pConstraints;
for (cConstraints = 0; pItem; pItem = pItem->pNext) {
PFEATUREOBJ pFeature1, pFeature2;
WORD feature1, selection1, feature2, selection2;
PSTR pStr, pFeatureStr1, pSelStr1, pFeatureStr2, pSelStr2;
pStr = pItem->pName;
// The value for a UIConstraints entry consists of four separate words:
// featureName1 selectionName1 featureName2 selectionName2
if (!(pFeatureStr1 = FindNextWord(&pStr)) || !(pSelStr1 = FindNextWord(&pStr)) ||
!(pFeatureStr2 = FindNextWord(&pStr)) || !(pSelStr2 = FindNextWord(&pStr)))
{
Warning(("Invalid UIConstraints entry: %s\n", pItem->pName));
continue;
}
if (!IsKeywordChar(*pFeatureStr1) || !IsKeywordChar(*pFeatureStr2)) {
Warning(("Missing keyword character in UIConstraints entry: %s/%s\n",
pFeatureStr1, pFeatureStr2));
}
if (*pStr != NUL) {
Warning(("Extra information in UIConstraints entry ignored: %s/%s\n",
pFeatureStr1, pFeatureStr2));
}
if (IsKeywordChar(*pFeatureStr1))
pFeatureStr1++;
if (IsKeywordChar(*pFeatureStr2))
pFeatureStr2++;
if (!(pFeature1 = FindListItem(pParserData->pFeatures, pFeatureStr1, &feature1)) ||
!(pFeature2 = FindListItem(pParserData->pFeatures, pFeatureStr2, &feature2)))
{
Warning(("Unknown feature in UIConstraints entry: %s/%s\n",
pFeatureStr1, pFeatureStr2));
continue;
}
selection1 = selection2 = SELIDX_ANY;
if ((strcmp(pSelStr1, "*") == EQUAL_STRING ||
FindListItem(pFeature1->pOptions, pSelStr1, &selection1)) &&
(strcmp(pSelStr2, "*") == EQUAL_STRING ||
FindListItem(pFeature2->pOptions, pSelStr2, &selection2)))
{
pConstraints->feature1 = feature1;
pConstraints->selection1 = selection1;
pConstraints->feature2 = feature2;
pConstraints->selection2 = selection2;
pConstraints++;
cConstraints++;
} else {
Warning(("Unknown feature selection in UIConstraints entry:\n"));
Warning((" %s/%s, %s/%s\n", pFeatureStr1, pSelStr1, pFeatureStr2, pSelStr2));
}
}
pParserData->cConstraints = cConstraints;
}
VOID
SortPrinterFeatures(
PPARSERDATA pParserData
)
/*++
Routine Description:
Sort all features based order dependency values.
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
PFEATUREOBJ pNewList, pCurItem;
WORD order, count = 0;
//
// Sort the feature list based on OrderDependency values
//
pNewList = NULL;
pCurItem = pParserData->pFeatures;
while (pCurItem != NULL) {
PFEATUREOBJ pTempItem, pNextItem, pPrevItem;
pNextItem = pCurItem->pNext;
//
// Insert current item into the new sorted list
//
pTempItem = pNewList;
pPrevItem = NULL;
while (pTempItem != NULL && pTempItem->order < pCurItem->order) {
pPrevItem = pTempItem;
pTempItem = pTempItem->pNext;
}
if (pPrevItem == NULL) {
pCurItem->pNext = pNewList;
pNewList = pCurItem;
} else {
pCurItem->pNext = pPrevItem->pNext;
pPrevItem->pNext = pCurItem;
}
count++;
pCurItem = pNextItem;
}
pParserData->pFeatures = pNewList;
//
// Make sure the number of features is below the maximum allowed
//
if (count > MAX_FEATURES) {
Error(("Too many features: %d\n", count));
pParserData->errors++;
}
}
VOID
ValidatePrinterFeatures(
PPARSERDATA pParserData
)
/*++
Routine Description:
Validate printer feature information
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
PFEATUREOBJ pFeature;
POPTIONOBJ pOption, pPrev, pNext;
WORD index;
for (pFeature = pParserData->pFeatures; pFeature; pFeature = pFeature->pNext) {
//
// Reverse feature selection list
//
for (pOption = pFeature->pOptions, pPrev = NULL, index = 0; pOption; index++) {
pNext = pOption->pNext;
pOption->pNext = pPrev;
pPrev = pOption;
pOption = pNext;
}
pFeature->pOptions = pPrev;
if (index >= SELIDX_ANY) {
Error(("Too many selections for feature %s\n", pFeature->pName));
pParserData->errors++;
}
//
// Get default selection index
//
if (pFeature->pDefault == NULL) {
Warning(("No default selection for feature %s \n", pFeature->pName));
} else if (!FindListItem(pFeature->pOptions, pFeature->pDefault, &index)) {
if (strcmp(pFeature->pDefault, "Unknown") != EQUAL_STRING) {
Warning(("Default selection for %s not found: %s\n",
pFeature->pName, pFeature->pDefault));
}
} else
pFeature->defaultIndex = index;
//
// Make sure there is at least one selection for each feature
//
if ((pOption = pFeature->pOptions) == NULL) {
Error(("No selections defined for feature: %s\n", pFeature->pName));
pParserData->errors++;
}
//
// Validate feature selections
//
for ( ; pOption; pOption = pOption->pNext) {
if (!pFeature->installable && pOption->invocation.length == 0) {
Warning(("No invocation string for %s/%s\n", pFeature->pName, pOption->pName));
}
switch (pFeature->groupId) {
case GID_PAPERSIZE:
//
// Validate paper size option
//
{ PPAPEROBJ pPaper = (PPAPEROBJ) pOption;
if (pPaper->size.cx <= 0 || pPaper->size.cx <= 0 ||
pPaper->imageableArea.left >= pPaper->imageableArea.right ||
pPaper->imageableArea.top >= pPaper->imageableArea.bottom ||
pPaper->imageableArea.right > pPaper->size.cx ||
pPaper->imageableArea.bottom > pPaper->size.cy)
{
Error(("Invalid page size: %d\n", pPaper->pName));
pParserData->errors++;
}
}
break;
case GID_RESOLUTION:
//
// Validate resolution option
//
{ PRESOBJ pResOption = (PRESOBJ) pOption;
PSTR pStr = pResOption->pName;
DWORD xres, yres;
BOOL ok;
if (ok = ParseInteger(&pStr, &xres)) {
yres = xres;
while (*pStr && !IsDigit(*pStr))
pStr++;
if (*pStr == NUL || (ok = ParseInteger(&pStr, &yres))) {
if (xres == 0 || xres > MAX_SHORT || yres == 0 || yres > MAX_SHORT) {
ok = FALSE;
} else {
pResOption->xdpi = (SHORT) xres;
pResOption->ydpi = (SHORT) yres;
}
}
}
if (! ok) {
Error(("Invalid resolution option: %s\n", pResOption->pName));
pParserData->errors++;
}
}
break;
case GID_MEMOPTION:
//
// Validate memory configuration option
//
{ PMEMOBJ pMemOption = (PMEMOBJ) pOption;
PSTR pStr = (PSTR) pMemOption->invocation.pData;
DWORD freeMem;
if (pStr == NULL || !ParseInteger(&pStr, &freeMem) || freeMem < MIN_FREEMEM) {
Error(("Invalid memory option: %s\n", pMemOption->pName));
pParserData->errors++;
freeMem = MIN_FREEMEM;
}
pMemOption->freeMem = freeMem;
}
break;
case GID_DUPLEX:
//
// Validate duplex option
//
if (strcmp(pOption->pName, "None") != EQUAL_STRING &&
strcmp(pOption->pName, "Horizontal") != EQUAL_STRING &&
strcmp(pOption->pName, "Vertical") != EQUAL_STRING)
{
Warning(("Unknown duplex option: %s\n", pOption->pName));
}
break;
case GID_COLLATE:
//
// Validate collate option
//
if (strcmp(pOption->pName, "False") != EQUAL_STRING &&
strcmp(pOption->pName, "True") != EQUAL_STRING)
{
Warning(("Unknown collate option: %s\n", pOption->pName));
}
break;
}
}
}
}
VOID
ValidateFontEntries(
PPARSERDATA pParserData
)
/*++
Routine Description:
Validate device font information parsed from a printer description file
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
PSYMBOLOBJ pSymItem;
PFONTREC pFont;
//
// Validate font encoding information
//
for (pSymItem = pParserData->pFontEnc; pSymItem; pSymItem = pSymItem->pNext) {
// _TODO_
}
//
// Validate font metrics information
//
for (pSymItem = pParserData->pFontMtx; pSymItem; pSymItem = pSymItem->pNext) {
// _TODO_
}
//
// Resolve font encoding and font metrics reference information
//
for (pFont = pParserData->pFonts; pFont; pFont = pFont->pNext) {
//
// Resolve font encoding information
//
if (! (pFont->pFontEnc = FindListItem(pParserData->pFontEnc, pFont->pFontEnc, NULL))) {
Error(("Undefined font encoding: %s\n", pFont->pFontEnc));
pParserData->errors++;
}
//
// Resolve font metrics information
//
if (! (pFont->pFontMtx = FindListItem(pParserData->pFontMtx, pFont->pFontMtx, NULL))) {
Error(("Undefined font metrics: %s\n", pFont->pFontMtx));
pParserData->errors++;
}
}
}
VOID
ResolveAllSymbols(
PPARSERDATA pParserData
)
/*++
Routine Description:
Resolve symbol references in a printer description file
Arguments:
pParserData - Points to parser data structure
Return Value:
NONE
--*/
{
PFEATUREOBJ pFeature;
POPTIONOBJ pOption;
PSYMBOLOBJ pSymbol;
PSTR pSymName;
for (pFeature=pParserData->pFeatures; pFeature; pFeature=pFeature->pNext) {
for (pOption=pFeature->pOptions; pOption; pOption=pOption->pNext) {
if (IsSymbolInvocation(&pOption->invocation)) {
pSymName = (PSTR) pOption->invocation.pData;
if (! (pSymbol = FindListItem(pParserData->pSymbols, pSymName, NULL))) {
Error(("Undefined symbol '%s' referenced in entry %s/%s\n",
pSymName, pFeature->pName, pOption->pName));
pParserData->errors++;
} else
pOption->invocation.pData = (PBYTE) pSymbol;
}
}
}
}
BOOL
ValidateParserData(
PPARSERDATA pParserData
)
/*++
Routine Description:
Validate the data parsed from a printer description file
Arguments:
pParserData - Points to parser data structure
Return Value:
TRUE if the parsed data is consistent, FALSE otherwise
Note:
This function assumes that no syntax errors were found by the parser
up to this point.
--*/
{
pParserData->errors = 0;
if (pParserData->pOpenFeature) {
Error(("Missing EndFeature for: %s\n", pParserData->pOpenFeature->pName));
pParserData->errors++;
}
if (!pParserData->pVendorName || !pParserData->pModelName) {
Error(("Missing VendorName and/or ModelName\n"));
pParserData->errors++;
}
if (pParserData->specVersion == 0 ||
pParserData->fileVersion == 0 ||
pParserData->xlProtocol == 0)
{
Error(("Missing version information (spec, file, or xl)\n"));
pParserData->errors++;
}
//
// Go through InstallableOptions and OrderDependency entries.
//
ValidateInstallableOptionsEntries(pParserData);
ValidateOrderDependencyEntries(pParserData);
//
// Validate all printer features
//
ValidatePrinterFeatures(pParserData);
//
// Sort all features based order dependency values.
//
SortPrinterFeatures(pParserData);
//
// Go thru UIConstraints entries. This must be called after
// the features have been processed and sorted.
//
ValidateUiConstraintsEntries(pParserData);
//
// Resolve symbols
//
ResolveAllSymbols(pParserData);
//
// Process device font entries
//
ValidateFontEntries(pParserData);
return (pParserData->errors == 0);
}