503 lines
13 KiB
C++
503 lines
13 KiB
C++
/*++
|
||
|
||
Copyright (c) 1998 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
pass2.cpp
|
||
|
||
Abstract:
|
||
|
||
Functions for additional checking of a PPD file
|
||
|
||
Environment:
|
||
|
||
PostScript driver, PPD parser
|
||
|
||
Revision History:
|
||
|
||
09/15/98 -rorleth-
|
||
Created it.
|
||
|
||
--*/
|
||
|
||
#include <lib.h>
|
||
#include <iostream.h>
|
||
|
||
#include "pass2.h"
|
||
|
||
enum FeatureId
|
||
{
|
||
FID_PAGE_SIZE,
|
||
FID_PAGE_REGION,
|
||
FID_INPUT_SLOT,
|
||
FID_SMOOTHING,
|
||
FID_MEDIA_COLOR,
|
||
FID_MEDIA_TYPE,
|
||
FID_MEDIA_WEIGHT,
|
||
FID_OUTPUT_MODE,
|
||
FID_PAPER_DIMENSION,
|
||
FID_IMAGE_AREA,
|
||
FID_OUTPUT_ORDER,
|
||
NO_OF_FEATURES
|
||
};
|
||
|
||
typedef struct _PPD_FEATURE
|
||
{
|
||
FeatureId eId;
|
||
LPSTR lpszName;
|
||
} PPD_FEATURE, *PPPD_FEATURE;
|
||
|
||
//
|
||
// features whose options we have to check
|
||
//
|
||
|
||
static PPD_FEATURE aCheckFeat[] =
|
||
{
|
||
{ FID_PAGE_SIZE, "PageSize" },
|
||
{ FID_PAGE_REGION, "PageRegion" },
|
||
{ FID_INPUT_SLOT, "InputSlot" },
|
||
{ FID_SMOOTHING, "Smoothing" },
|
||
{ FID_MEDIA_COLOR, "MediaColor" },
|
||
{ FID_MEDIA_TYPE, "MediaType" },
|
||
{ FID_MEDIA_WEIGHT, "MediaWeight" },
|
||
{ FID_OUTPUT_MODE, "OutputMode" },
|
||
{ FID_PAPER_DIMENSION, "PaperDimension" },
|
||
{ FID_IMAGE_AREA, "ImageableArea" },
|
||
{ FID_OUTPUT_ORDER, "OutputOrder" },
|
||
{ NO_OF_FEATURES, NULL}
|
||
};
|
||
|
||
typedef struct _PPD_OPTION
|
||
{
|
||
FeatureId eId;
|
||
LPSTR lpszName;
|
||
} PPD_OPTION, *PPPD_OPTION;
|
||
|
||
//
|
||
// keywords that require defined feature options
|
||
//
|
||
static PPD_OPTION gaCheckKeyword[] =
|
||
{
|
||
{ FID_INPUT_SLOT, "RequiresPageRegion"},
|
||
{ NO_OF_FEATURES, NULL }
|
||
};
|
||
|
||
//
|
||
// special option names
|
||
//
|
||
static PPD_OPTION gaSpecialOptions[] =
|
||
{
|
||
{ NO_OF_FEATURES, "None" }, // NO_OF_FEATURES means valid for all features in that case
|
||
{ NO_OF_FEATURES, "All" },
|
||
{ NO_OF_FEATURES, "Unknown" },
|
||
{ FID_OUTPUT_ORDER, "Normal" }, // Normal and Reverse are predefined options for OutputOrder
|
||
{ FID_OUTPUT_ORDER, "Reverse" },
|
||
{ NO_OF_FEATURES, NULL},
|
||
};
|
||
|
||
//
|
||
// keywords that have a length limitation for the UI
|
||
//
|
||
typedef struct _PPD_LENGTH_CHECK
|
||
{
|
||
FeatureId eId;
|
||
size_t iMaxLen;
|
||
} PPD_LENGTH_CHECK, *PPPD_LENGTH_CHECK;
|
||
|
||
static PPD_LENGTH_CHECK gaCheckLength[] =
|
||
{
|
||
{ FID_INPUT_SLOT, 23},
|
||
{ NO_OF_FEATURES, 0 }
|
||
};
|
||
|
||
const char *pDefaultKeyword = "Default";
|
||
const int MaxOptionNameLen = 40;
|
||
const int MaxTranslationNameLen = 128;
|
||
|
||
typedef struct _OPTION_LIST
|
||
{
|
||
char aName[MaxOptionNameLen+1];
|
||
char aTransName[MaxTranslationNameLen+1];
|
||
_OPTION_LIST *pNext;
|
||
} OPTION_LIST, *POPTION_LIST;
|
||
|
||
|
||
static POPTION_LIST gaOptionList[NO_OF_FEATURES]; // stores all defined options
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
checks whether a references option is defined
|
||
|
||
Arguments:
|
||
|
||
char **ppString : Pointer to pointer to option, is advanced by the option name length
|
||
FeatureId FeatId : ID of the feature, which should have the option
|
||
char *pOptionName: pointer to buffer, where the option name shall be stored for error messages
|
||
|
||
Return Value:
|
||
|
||
TRUE if the identified feature has that option, FALSE if not
|
||
|
||
--*/
|
||
|
||
static BOOL IsOptionDefined(char **ppString, FeatureId FeatId, char *pOptionName)
|
||
{
|
||
char *pEndName, *pName = *ppString;
|
||
|
||
while (isspace(*pName))
|
||
pName++;
|
||
|
||
pEndName = strpbrk(pName, "/: \t\n\r\0");
|
||
|
||
*ppString = pEndName; // advance current pointer
|
||
|
||
strncpy(pOptionName, pName, min((DWORD)(pEndName - pName), MaxOptionNameLen));
|
||
pOptionName[pEndName-pName] = 0;
|
||
|
||
//
|
||
// check special cases that do not have to be defined
|
||
//
|
||
int i=0;
|
||
|
||
while (gaSpecialOptions[i].lpszName != NULL)
|
||
{
|
||
if ((gaSpecialOptions[i].eId == NO_OF_FEATURES) ||
|
||
(gaSpecialOptions[i].eId == FeatId))
|
||
{
|
||
if (!strcmp(gaSpecialOptions[i].lpszName, pOptionName))
|
||
return TRUE;
|
||
}
|
||
i++;
|
||
}
|
||
|
||
POPTION_LIST pList = gaOptionList[FeatId], pNew;
|
||
|
||
while (pList != NULL)
|
||
{
|
||
if (!strcmp(pList->aName, pOptionName))
|
||
return TRUE; // found it, it's defined
|
||
|
||
pList = pList->pNext;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
checks a whole PPD-file, whether all referenced options are defined
|
||
|
||
Arguments:
|
||
|
||
PTSTR FileName: Name of the PPD-file to check
|
||
|
||
--*/
|
||
|
||
extern "C" void CheckOptionIntegrity(PTSTR ptstrPpdFilename)
|
||
{
|
||
|
||
ZeroMemory(gaOptionList, sizeof(gaOptionList)); // initialise the list header
|
||
|
||
_flushall(); // to avoid sync problems with the DbgPrint output
|
||
|
||
//
|
||
// create the file mapping
|
||
//
|
||
HANDLE hFile = CreateFile(ptstrPpdFilename, GENERIC_READ, FILE_SHARE_READ,
|
||
NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
||
if (hFile == INVALID_HANDLE_VALUE)
|
||
{
|
||
return;
|
||
}
|
||
|
||
DWORD dwFileSize = GetFileSize(hFile, NULL);
|
||
|
||
if (dwFileSize == 0xffffffff)
|
||
{
|
||
CloseHandle(hFile);
|
||
return;
|
||
}
|
||
|
||
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY,0, 0,NULL);
|
||
|
||
if (hMap == NULL)
|
||
{
|
||
CloseHandle(hFile);
|
||
return;
|
||
}
|
||
|
||
LPCVOID pView = MapViewOfFile(hMap, FILE_MAP_READ, 0,0,0);
|
||
if (pView == NULL)
|
||
{
|
||
CloseHandle(hMap);
|
||
CloseHandle(hFile);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// copy the whole file into an allocated buffer just to get zero-termination
|
||
//
|
||
LPSTR pFile, pFileStart;
|
||
|
||
pFileStart = (LPSTR) VirtualAlloc(NULL, dwFileSize+1, MEM_COMMIT, PAGE_READWRITE);
|
||
|
||
if (pFileStart != NULL)
|
||
{
|
||
CopyMemory(pFileStart, pView, dwFileSize);
|
||
*(pFileStart + dwFileSize) = 0;
|
||
}
|
||
|
||
UnmapViewOfFile(pView);
|
||
CloseHandle(hMap);
|
||
CloseHandle(hFile);
|
||
|
||
if (pFileStart == NULL)
|
||
{
|
||
cout << "ppdcheck.exe out of memory" << endl;
|
||
return;
|
||
}
|
||
|
||
pFile = pFileStart;
|
||
|
||
//
|
||
// now the whole PPD-file is a giant string
|
||
// extract all the features/options
|
||
//
|
||
char *pCurOption = (char *) pFileStart;
|
||
char OptionName[MaxOptionNameLen+1];
|
||
|
||
|
||
//
|
||
// step 1 : extract all valid feature options
|
||
//
|
||
while ((pFile != NULL) &&
|
||
(pCurOption = strchr(pFile, '*')) != NULL)
|
||
{
|
||
pCurOption++;
|
||
|
||
char *pNextLine = strpbrk(pCurOption, "\n\r");
|
||
pFile = pNextLine;
|
||
|
||
if (*pCurOption == '%') // skip comments
|
||
continue;
|
||
|
||
//
|
||
// scan whether this is one of the features to look for
|
||
//
|
||
int Index = 0;
|
||
|
||
while (aCheckFeat[Index].eId != NO_OF_FEATURES)
|
||
{
|
||
if (strncmp(aCheckFeat[Index].lpszName, pCurOption, strlen(aCheckFeat[Index].lpszName)))
|
||
{
|
||
Index++;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// this is one of the monitored features: make entry in list
|
||
//
|
||
POPTION_LIST pList = gaOptionList[aCheckFeat[Index].eId], pNew;
|
||
|
||
pNew = new OPTION_LIST;
|
||
|
||
pNew->pNext = gaOptionList[aCheckFeat[Index].eId];
|
||
gaOptionList[aCheckFeat[Index].eId] = pNew;
|
||
|
||
char *pName = pCurOption + strlen(aCheckFeat[Index].lpszName), *pEndName;
|
||
|
||
while (isspace(*pName))
|
||
pName++;
|
||
|
||
pEndName = strpbrk(pName, "/: \0");
|
||
|
||
DWORD dwNameLen = min((DWORD)(pEndName - pName), MaxOptionNameLen);
|
||
strncpy(pNew->aName, pName, dwNameLen);
|
||
pNew->aName[dwNameLen] = 0;
|
||
|
||
dwNameLen = 0;
|
||
|
||
if (*pEndName == '/') // there is a translation string
|
||
{
|
||
pName = pEndName +1;
|
||
pEndName = strpbrk(pName, ":\n\r\0");
|
||
|
||
dwNameLen = min((DWORD) (pEndName - pName), MaxTranslationNameLen);
|
||
strncpy(pNew->aTransName, pName, dwNameLen);
|
||
}
|
||
pNew->aTransName[dwNameLen] = 0;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// step 2: check whether all referenced options are featured
|
||
//
|
||
pFile = pFileStart;
|
||
pCurOption = (char *) pFile;
|
||
|
||
while ((pFile != NULL) &&
|
||
(pCurOption = strchr(pFile, '*')) != NULL)
|
||
{
|
||
pCurOption++;
|
||
|
||
char *pNextLine = strpbrk(pCurOption, "\n\r");
|
||
pFile = pNextLine;
|
||
|
||
//
|
||
// skip comments
|
||
//
|
||
if (*pCurOption == '%')
|
||
continue;
|
||
|
||
//
|
||
// check whether it starts with "Default", if yes, check that feature option
|
||
//
|
||
if (!strncmp(pDefaultKeyword, pCurOption, strlen(pDefaultKeyword)))
|
||
{
|
||
pCurOption += strlen(pDefaultKeyword);
|
||
|
||
int Index = 0;
|
||
|
||
while (aCheckFeat[Index].eId != NO_OF_FEATURES)
|
||
{
|
||
if (strncmp(aCheckFeat[Index].lpszName, pCurOption, strlen(aCheckFeat[Index].lpszName)))
|
||
{
|
||
Index++;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// it's one of the checked featurs
|
||
//
|
||
pCurOption += strlen(aCheckFeat[Index].lpszName);
|
||
|
||
char *pOption = strpbrk(pCurOption, ":");
|
||
|
||
if (pOption == NULL)
|
||
{
|
||
cout << "Warning: default option for '" << aCheckFeat[Index].lpszName << "' is not completed !" << endl;
|
||
break;
|
||
}
|
||
pCurOption = pOption + 1;
|
||
|
||
if (!IsOptionDefined(&pCurOption, aCheckFeat[Index].eId, OptionName))
|
||
cout << "Warning: default option '" << OptionName << "' for feature '*" << aCheckFeat[Index].lpszName <<"' is not defined!" << endl;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// scan whether this is one of the keywords to look for
|
||
//
|
||
int Index = 0;
|
||
|
||
while (gaCheckKeyword[Index].eId != NO_OF_FEATURES)
|
||
{
|
||
if (strncmp(gaCheckKeyword[Index].lpszName, pCurOption, strlen(gaCheckKeyword[Index].lpszName)))
|
||
{
|
||
Index++;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// this is one of the monitored features: get the option it references
|
||
//
|
||
pCurOption += strlen(gaCheckKeyword[Index].lpszName);
|
||
|
||
if (!IsOptionDefined(&pCurOption, gaCheckKeyword[Index].eId, OptionName))
|
||
cout << "Warning: option '" << OptionName << "' for keyword '*" << gaCheckKeyword[Index].lpszName <<"' is not defined!" << endl;
|
||
break;
|
||
}
|
||
Index++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// step 3: check that all option names are different and don't have trailing or leading spaces
|
||
//
|
||
for (int i = 0; i < NO_OF_FEATURES;i++)
|
||
{
|
||
POPTION_LIST pCheck = gaOptionList[i], pCur;
|
||
|
||
while (pCheck != NULL)
|
||
{
|
||
pCur = pCheck->pNext;
|
||
|
||
while (pCur != NULL)
|
||
{
|
||
if (strlen(pCheck->aName) &&
|
||
!strcmp(pCheck->aName, pCur->aName))
|
||
cout << "Warning: option name '" << pCheck->aName << "' used twice" << endl;
|
||
if (strlen(pCheck->aTransName) &&
|
||
!strcmp(pCheck->aTransName, pCur->aTransName))
|
||
cout << "Warning: translation name '" << pCheck->aTransName << "' used twice" << endl;
|
||
|
||
pCur = pCur->pNext;
|
||
}
|
||
size_t TransNameLen = strlen(pCheck->aTransName);
|
||
|
||
if (isspace(pCheck->aTransName[0]))
|
||
cout << "Warning: translation name '" << pCheck->aTransName << "' has leading whitespace" << endl;
|
||
if ((TransNameLen > 1) &&
|
||
isspace(pCheck->aTransName[TransNameLen-1]))
|
||
cout << "Warning: translation name '" << pCheck->aTransName << "' has trailing whitespace" << endl;
|
||
|
||
pCheck = pCheck->pNext;
|
||
}
|
||
}
|
||
|
||
//
|
||
// step 4: warn if the string that is used for the display is too long
|
||
//
|
||
i = 0;
|
||
while (gaCheckLength[i].eId != NO_OF_FEATURES)
|
||
{
|
||
POPTION_LIST pCheck = gaOptionList[gaCheckLength[i].eId], pCur;
|
||
while (pCheck != NULL)
|
||
{
|
||
size_t TransNameLen = strlen(pCheck->aTransName);
|
||
|
||
if (TransNameLen > gaCheckLength[i].iMaxLen)
|
||
cout << "Warning: translation name '" << pCheck->aTransName << "' will be truncated to "<< (unsigned int) gaCheckLength[i].iMaxLen << " characters"<< endl;
|
||
else if ((TransNameLen == 0) && (strlen(pCheck->aName) > gaCheckLength[i].iMaxLen))
|
||
cout << "Warning: option name '" << pCheck->aName << "' will be truncated to "<< (unsigned int) gaCheckLength[i].iMaxLen << " characters"<< endl;
|
||
|
||
pCheck = pCheck->pNext;
|
||
}
|
||
i++;
|
||
}
|
||
|
||
|
||
//
|
||
// clean up
|
||
//
|
||
for (i = 0; i < NO_OF_FEATURES;i++)
|
||
{
|
||
POPTION_LIST pTmp = gaOptionList[i], pCur;
|
||
|
||
while (pTmp != NULL)
|
||
{
|
||
pCur = pTmp->pNext;
|
||
delete pTmp;
|
||
pTmp = pCur;
|
||
}
|
||
gaOptionList[i] = NULL;
|
||
}
|
||
|
||
_flushall(); // to avoid sync problems with the DbgPrint output
|
||
|
||
VirtualFree((LPVOID) pFileStart, 0, MEM_RELEASE);
|
||
}
|
||
|