/*++ Copyright (c) 2000 Microsoft Corporation All rights reserved. Module Name: getdata.c Abstract: PostScript helper functions for OEM plugins HGetGlobalAttribute HGetFeatureAttribute HGetOptionAttribute HEnumFeaturesOrOptions Author: Feng Yue (fengy) 8/24/2000 fengy Completed with support of both PPD and driver features. 5/22/2000 fengy Created it with function framework. --*/ #include "lib.h" #include "ppd.h" #include "pslib.h" // // PS driver's helper functions for OEM plugins // // // global attribute names // const CHAR kstrCenterReg[] = "CenterRegistered"; const CHAR kstrColorDevice[] = "ColorDevice"; const CHAR kstrExtensions[] = "Extensions"; const CHAR kstrFileVersion[] = "FileVersion"; const CHAR kstrFreeVM[] = "FreeVM"; const CHAR kstrLSOrientation[] = "LandscapeOrientation"; const CHAR kstrLangEncoding[] = "LanguageEncoding"; const CHAR kstrLangLevel[] = "LanguageLevel"; const CHAR kstrNickName[] = "NickName"; const CHAR kstrPPDAdobe[] = "PPD-Adobe"; const CHAR kstrPrintError[] = "PrintPSErrors"; const CHAR kstrProduct[] = "Product"; const CHAR kstrProtocols[] = "Protocols"; const CHAR kstrPSVersion[] = "PSVersion"; const CHAR kstrJobTimeout[] = "SuggestedJobTimeout"; const CHAR kstrWaitTimeout[] = "SuggestedWaitTimeout"; const CHAR kstrThroughput[] = "Throughput"; const CHAR kstrTTRasterizer[] = "TTRasterizer"; // // feature attribute names // const CHAR kstrDisplayName[] = "DisplayName"; const CHAR kstrDefOption[] = "DefaultOption"; const CHAR kstrOpenUIType[] = "OpenUIType"; const CHAR kstrOpenGroupType[] = "OpenGroupType"; const CHAR kstrOrderDepValue[] = "OrderDependencyValue"; const CHAR kstrOrderDepSect[] = "OrderDependencySection"; // // option keyword names, option attribute names // const CHAR kstrInvocation[] = "Invocation"; const CHAR kstrInputSlot[] = "InputSlot"; const CHAR kstrReqPageRgn[] = "RequiresPageRegion"; const CHAR kstrOutputBin[] = "OutputBin"; const CHAR kstrOutOrderRev[] = "OutputOrderReversed"; const CHAR kstrPageSize[] = "PageSize"; const CHAR kstrPaperDim[] = "PaperDimension"; const CHAR kstrImgArea[] = "ImageableArea"; const CHAR kstrCustomPS[] = "CustomPageSize"; const CHAR kstrParamCustomPS[] = "ParamCustomPageSize"; const CHAR kstrHWMargins[] = "HWMargins"; const CHAR kstrMaxMWidth[] = "MaxMediaWidth"; const CHAR kstrMaxMHeight[] = "MaxMediaHeight"; const CHAR kstrInstalledMem[] = "InstalledMemory"; const CHAR kstrVMOption[] = "VMOption"; const CHAR kstrFCacheSize[] = "FCacheSize"; // // enumeration of data region where an attribute is stored // typedef enum _EATTRIBUTE_DATAREGION { kADR_UIINFO, // attribute is stored in UIINFO structure kADR_PPDDATA, // attribute is stored in PPDDATA structure } EATTRIBUTE_DATAREGION; /*++ Routine Name: HGetSingleData Routine Description: copy source data to specified output buffer and set the output data type Arguments: pSrcData - pointer to source data buffer dwSrcDataType - source data type cbSrcSize - source data buffer size in bytes pdwOutDataType - pointer to DWORD to store output data type pbOutData - pointer to output data buffer cbOutSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: S_OK if succeeds E_OUTOFMEMORY if output data buffer size is not big enough Last Error: None --*/ HRESULT HGetSingleData( IN PVOID pSrcData, IN DWORD dwSrcDataType, IN DWORD cbSrcSize, OUT PDWORD pdwOutDataType, OUT PBYTE pbOutData, IN DWORD cbOutSize, OUT PDWORD pcbNeeded ) { // // Either pSrcData is NULL and cbSrcSize is 0, // or pSrcData is non-NULL and cbSrcSize is non-0. // ASSERT((pSrcData != NULL) || (cbSrcSize == 0)); ASSERT((cbSrcSize != 0) || (pSrcData == NULL)); if (pdwOutDataType) { *pdwOutDataType = dwSrcDataType; } if (pcbNeeded) { *pcbNeeded = cbSrcSize; } if (cbSrcSize) { // // We do have data for output. // if (!pbOutData || cbOutSize < cbSrcSize) { return E_OUTOFMEMORY; } CopyMemory(pbOutData, pSrcData, cbSrcSize); } return S_OK; } /*++ Routine Name: HGetGABool Routine Description: get global boolean attribute Arguments: pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the attribute Get operation pszAttribute - name of the global attribute pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: E_INVALIDARG if the global attribute is not recognized S_OK E_OUTOFMEMORY see function HGetSingleData Last Error: None --*/ HRESULT HGetGABool( IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszAttribute, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { typedef struct _GA_BOOL_ENTRY { PCSTR pszAttributeName; // attribute name EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA DWORD cbOffset; // byte offset to the DWORD data DWORD dwFlagBit; // bit flag in the DWORD } GA_BOOL_ENTRY, *PGA_BOOL_ENTRY; static const GA_BOOL_ENTRY kGABoolTable[] = { {kstrCenterReg, kADR_PPDDATA, offsetof(PPDDATA, dwCustomSizeFlags), CUSTOMSIZE_CENTERREG}, {kstrColorDevice, kADR_UIINFO, offsetof(UIINFO, dwFlags), FLAG_COLOR_DEVICE}, {kstrPrintError, kADR_PPDDATA, offsetof(PPDDATA, dwFlags), PPDFLAG_PRINTPSERROR}, }; PUIINFO pUIInfo; PPPDDATA pPpdData; DWORD cIndex; DWORD cTableEntry = sizeof(kGABoolTable) / sizeof(GA_BOOL_ENTRY); PGA_BOOL_ENTRY pEntry; pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader); ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO)); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA)); if (pUIInfo == NULL || pPpdData == NULL) { return E_FAIL; } pEntry = (PGA_BOOL_ENTRY)(&kGABoolTable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { if ((*pszAttribute == *(pEntry->pszAttributeName)) && (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING)) { // // attribute name matches // DWORD dwValue; BOOL bValue; if (pEntry->eADR == kADR_UIINFO) { dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset)); } else if (pEntry->eADR == kADR_PPDDATA) { dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset)); } else { // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGABool: unknown eADR %d\n", pEntry->eADR)); return E_FAIL; } // // map the bit flag to boolean value // bValue = (dwValue & pEntry->dwFlagBit) ? TRUE : FALSE; return HGetSingleData((PVOID)&bValue, kADT_BOOL, sizeof(BOOL), pdwDataType, pbData, cbSize, pcbNeeded); } } // // can't find the attribute // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGABool: unknown attribute %s\n", pszAttribute)); return E_INVALIDARG; } /*++ Routine Name: HGetGAInvocation Routine Description: get global invocation attribute Arguments: pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the attribute Get operation pszAttribute - name of the global attribute pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: E_INVALIDARG if the global attribute is not recognized S_OK E_OUTOFMEMORY see function HGetSingleData Last Error: None --*/ HRESULT HGetGAInvocation( IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszAttribute, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { typedef struct _GA_INVOC_ENTRY { PCSTR pszAttributeName; // attribute name EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA DWORD cbOffset; // byte offset to INVOCATION structure } GA_INVOC_ENTRY, *PGA_INVOC_ENTRY; static const GA_INVOC_ENTRY kGAInvocTable[] = { {kstrProduct, kADR_PPDDATA, offsetof(PPDDATA, Product)}, {kstrPSVersion, kADR_PPDDATA, offsetof(PPDDATA, PSVersion)}, }; PUIINFO pUIInfo; PPPDDATA pPpdData; DWORD cIndex; DWORD cTableEntry = sizeof(kGAInvocTable) / sizeof(GA_INVOC_ENTRY); PGA_INVOC_ENTRY pEntry; pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader); ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO)); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA)); if (pUIInfo == NULL || pPpdData == NULL) { return E_FAIL; } pEntry = (PGA_INVOC_ENTRY)(&kGAInvocTable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { if ((*pszAttribute == *(pEntry->pszAttributeName)) && (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING)) { // // attribute name matches // PINVOCATION pInvoc; if (pEntry->eADR == kADR_UIINFO) { pInvoc = (PINVOCATION)((PBYTE)pUIInfo + pEntry->cbOffset); } else if (pEntry->eADR == kADR_PPDDATA) { pInvoc = (PINVOCATION)((PBYTE)pPpdData + pEntry->cbOffset); } else { // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGAInvocation: unknown eADR %d\n", pEntry->eADR)); return E_FAIL; } return HGetSingleData(OFFSET_TO_POINTER(pInfoHeader, pInvoc->loOffset), kADT_BINARY, pInvoc->dwCount, pdwDataType, pbData, cbSize, pcbNeeded); } } // // can't find the attribute // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGAInvocation: unknown attribute %s\n", pszAttribute)); return E_INVALIDARG; } /*++ Routine Name: HGetGAString Routine Description: get global ASCII string attribute Arguments: pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the attribute Get operation pszAttribute - name of the global attribute pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: S_OK if succeeds E_OUTOFMEMORY if output data buffer size is not big enough Last Error: None --*/ HRESULT HGetGAString( IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszAttribute, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { typedef struct _GA_STRING_ENTRY { PCSTR pszAttributeName; // attribute name EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA DWORD cbOffset; // byte offset to the DWORD data BOOL bCheckDWord; // TRUE to check the whole DWORD // FALSE to check a bit in the DWORD // (If bCheckDWord is TRUE, table look // up will stop when first match is found.) BOOL bCheckBitSet; // TRUE to check if the bit is set // FALSE to check if the bit is cleared // (this is ignored if bCheckDWord is TRUE) DWORD dwFlag; // flag value PCSTR pszValue; // registered value string } GA_STRING_ENTRY, *PGA_STRING_ENTRY; static const GA_STRING_ENTRY kGAStringTable[] = { {kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_DPS, "DPS"}, {kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_CMYK, "CMYK"}, {kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_COMPOSITE, "Composite"}, {kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_FILESYSTEM, "FileSystem"}, {kstrLSOrientation, kADR_UIINFO, offsetof(UIINFO, dwFlags), FALSE, TRUE, FLAG_ROTATE90, "Plus90"}, {kstrLSOrientation, kADR_UIINFO, offsetof(UIINFO, dwFlags), FALSE, FALSE, FLAG_ROTATE90, "Minus90"}, {kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_ISOLATIN1, "ISOLatin1"}, {kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_UNICODE, "Unicode"}, {kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_JIS83_RKSJ, "JIS83-RKSJ"}, {kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_NONE, "None"}, {kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_BCP, "BCP"}, {kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_PJL, "PJL"}, {kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_TBCP, "TBCP"}, {kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_SIC, "SIC"}, {kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_NONE, "None"}, {kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_ACCEPT68K, "Accept68K"}, {kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_TYPE42, "Type42"}, {kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_TRUEIMAGE, "TrueImage"}, }; PUIINFO pUIInfo; PPPDDATA pPpdData; PGA_STRING_ENTRY pEntry; DWORD cTableEntry = sizeof(kGAStringTable) / sizeof(GA_STRING_ENTRY); PSTR pCurrentOut; DWORD cbNeeded, cIndex; INT cbRemain; if (pdwDataType) { *pdwDataType = kADT_ASCII; } pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader); ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO)); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA)); if (pUIInfo == NULL || pPpdData == NULL) { return E_FAIL; } pCurrentOut = (PSTR)pbData; cbNeeded = 0; cbRemain = (INT)cbSize; pEntry = (PGA_STRING_ENTRY)(&kGAStringTable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { if ((*pszAttribute == *(pEntry->pszAttributeName)) && (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING)) { // // attribute name matches // DWORD dwValue; BOOL bMatch; if (pEntry->eADR == kADR_UIINFO) { dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset)); } else if (pEntry->eADR == kADR_PPDDATA) { dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset)); } else { // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGAString: unknown eADR %d\n", pEntry->eADR)); return E_FAIL; } if (pEntry->bCheckDWord) { // // check the whole DWORD // bMatch = (dwValue == pEntry->dwFlag) ? TRUE : FALSE; } else { BOOL bBitIsSet; // // check the one bit in the DWORD // bBitIsSet = (dwValue & pEntry->dwFlag) ? TRUE : FALSE; bMatch = (bBitIsSet == pEntry->bCheckBitSet ) ? TRUE : FALSE; } if (bMatch) { DWORD cbNameSize; // // count in the NUL delimiter // cbNameSize = strlen(pEntry->pszValue) + 1; if (pCurrentOut && cbRemain >= (INT)cbNameSize) { CopyMemory(pCurrentOut, pEntry->pszValue, cbNameSize); pCurrentOut += cbNameSize; } cbRemain -= cbNameSize; cbNeeded += cbNameSize; if (pEntry->bCheckDWord) { // // stop table look up when first match is found if we are // checking the whole DWORD instead of bits in the DWORD. // break; } } } } // // remember the the last NUL terminator for the MULTI_SZ output string // cbRemain--; cbNeeded++; if (pcbNeeded) { *pcbNeeded = cbNeeded; } if (!pCurrentOut || cbRemain < 0) { return E_OUTOFMEMORY; } *pCurrentOut = NUL; return S_OK; } /*++ Routine Name: HGetGADWord Routine Description: get global DWORD attribute Arguments: pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the attribute Get operation pszAttribute - name of the global attribute pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: E_INVALIDARG if the global attribute is not recognized S_OK E_OUTOFMEMORY see function HGetSingleData Last Error: None --*/ HRESULT HGetGADWord( IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszAttribute, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { typedef struct _GA_DWORD_ENTRY { PCSTR pszAttributeName; // attribute name EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA DWORD cbOffset; // byte offset to the DWORD data } GA_DWORD_ENTRY, *PGA_DWORD_ENTRY; static const GA_DWORD_ENTRY kGADWordTable[] = { {kstrFileVersion, kADR_PPDDATA, offsetof(PPDDATA, dwPpdFilever)}, {kstrFreeVM, kADR_UIINFO, offsetof(UIINFO, dwFreeMem)}, {kstrLangLevel, kADR_UIINFO, offsetof(UIINFO, dwLangLevel)}, {kstrPPDAdobe, kADR_UIINFO, offsetof(UIINFO, dwSpecVersion)}, {kstrJobTimeout, kADR_UIINFO, offsetof(UIINFO, dwJobTimeout)}, {kstrWaitTimeout, kADR_UIINFO, offsetof(UIINFO, dwWaitTimeout)}, {kstrThroughput, kADR_UIINFO, offsetof(UIINFO, dwPrintRate)}, }; PUIINFO pUIInfo; PPPDDATA pPpdData; DWORD cIndex; DWORD cTableEntry = sizeof(kGADWordTable) / sizeof(GA_DWORD_ENTRY); PGA_DWORD_ENTRY pEntry; pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader); ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO)); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA)); if (pUIInfo == NULL || pPpdData == NULL) { return E_FAIL; } pEntry = (PGA_DWORD_ENTRY)(&kGADWordTable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { if ((*pszAttribute == *(pEntry->pszAttributeName)) && (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING)) { // // attribute name matches // DWORD dwValue; if (pEntry->eADR == kADR_UIINFO) { dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset)); } else if (pEntry->eADR == kADR_PPDDATA) { dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset)); } else { // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGADWord: unknown eADR %d\n", pEntry->eADR)); return E_FAIL; } return HGetSingleData((PVOID)&dwValue, kADT_DWORD, sizeof(DWORD), pdwDataType, pbData, cbSize, pcbNeeded); } } // // can't find the attribute // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGADWord: unknown attribute %s\n", pszAttribute)); return E_INVALIDARG; } /*++ Routine Name: HGetGAUnicode Routine Description: get global Unicode string attribute Arguments: pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the attribute Get operation pszAttribute - name of the global attribute pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: E_INVALIDARG if the global attribute is not recognized S_OK E_OUTOFMEMORY see function HGetSingleData Last Error: None --*/ HRESULT HGetGAUnicode( IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszAttribute, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { typedef struct _GA_UNICODE_ENTRY { PCSTR pszAttributeName; // attribute name EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA DWORD cbOffset; // byte offset to DWORD specifying // offset to the UNICODE string } GA_UNICODE_ENTRY, *PGA_UNICODE_ENTRY; static const GA_UNICODE_ENTRY kGAUnicodeTable[] = { {kstrNickName, kADR_UIINFO, offsetof(UIINFO, loNickName)}, }; PUIINFO pUIInfo; PPPDDATA pPpdData; DWORD cIndex; DWORD cTableEntry = sizeof(kGAUnicodeTable) / sizeof(GA_UNICODE_ENTRY); PGA_UNICODE_ENTRY pEntry; pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader); ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO)); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA)); if (pUIInfo == NULL || pPpdData == NULL) { return E_FAIL; } pEntry = (PGA_UNICODE_ENTRY)(&kGAUnicodeTable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { if ((*pszAttribute == *(pEntry->pszAttributeName)) && (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING)) { // // attribute name matches // PTSTR ptstrString; DWORD cbOffset; if (pEntry->eADR == kADR_UIINFO) { cbOffset = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset)); } else if (pEntry->eADR == kADR_PPDDATA) { cbOffset = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset)); } else { // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGAUnicode: unknown eADR %d\n", pEntry->eADR)); return E_FAIL; } ptstrString = OFFSET_TO_POINTER(pInfoHeader, cbOffset); if (ptstrString == NULL) { return E_FAIL; } return HGetSingleData((PVOID)ptstrString, kADT_UNICODE, SIZE_OF_STRING(ptstrString), pdwDataType, pbData, cbSize, pcbNeeded); } } // // can't find the attribute // // This shouldn't happen. It's here to catch our coding error. // RIP(("HGetGAUnicode: unknown attribute %s\n", pszAttribute)); return E_INVALIDARG; } /*++ Routine Name: HGetGlobalAttribute Routine Description: get PPD global attribute Arguments: pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the attribute get operation pszAttribute - name of the global attribute pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: S_OK if succeeds E_OUTOFMEMORY if output data buffer size is not big enough E_INVALIDARG if the global attribute name is not recognized Last Error: None --*/ HRESULT HGetGlobalAttribute( IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszAttribute, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { typedef HRESULT (*_HGET_GA_PROC)( IN PINFOHEADER, IN DWORD, IN PCSTR, OUT PDWORD, OUT PBYTE, IN DWORD, OUT PDWORD); typedef struct _GA_PROCESS_ENTRY { PCSTR pszAttributeName; // attribute name _HGET_GA_PROC pfnGetGAProc; // attribute handling proc } GA_PROCESS_ENTRY, *PGA_PROCESS_ENTRY; static const GA_PROCESS_ENTRY kGAProcTable[] = { {kstrCenterReg, HGetGABool}, {kstrColorDevice, HGetGABool}, {kstrExtensions, HGetGAString}, {kstrFileVersion, HGetGADWord}, {kstrFreeVM, HGetGADWord}, {kstrLSOrientation, HGetGAString}, {kstrLangEncoding, HGetGAString}, {kstrLangLevel, HGetGADWord}, {kstrNickName, HGetGAUnicode}, {kstrPPDAdobe, HGetGADWord}, {kstrPrintError, HGetGABool}, {kstrProduct, HGetGAInvocation}, {kstrProtocols, HGetGAString}, {kstrPSVersion, HGetGAInvocation}, {kstrJobTimeout, HGetGADWord}, {kstrWaitTimeout, HGetGADWord}, {kstrThroughput, HGetGADWord}, {kstrTTRasterizer, HGetGAString}, }; DWORD cIndex; DWORD cTableEntry = sizeof(kGAProcTable) / sizeof(GA_PROCESS_ENTRY); PGA_PROCESS_ENTRY pEntry; if (!pszAttribute) { // // Client is asking for the full list of supported global attribute names // PSTR pCurrentOut; DWORD cbNeeded; INT cbRemain; if (pdwDataType) { *pdwDataType = kADT_ASCII; } pCurrentOut = (PSTR)pbData; cbNeeded = 0; cbRemain = (INT)cbSize; pEntry = (PGA_PROCESS_ENTRY)(&kGAProcTable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { DWORD cbNameSize; // // count in the NUL between attribute keywords // cbNameSize = strlen(pEntry->pszAttributeName) + 1; if (pCurrentOut && cbRemain >= (INT)cbNameSize) { CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize); pCurrentOut += cbNameSize; } cbRemain -= cbNameSize; cbNeeded += cbNameSize; } // // remember the last NUL terminator for the MULTI_SZ output string // cbRemain--; cbNeeded++; if (pcbNeeded) { *pcbNeeded = cbNeeded; } if (!pCurrentOut || cbRemain < 0) { return E_OUTOFMEMORY; } *pCurrentOut = NUL; return S_OK; } // // Client does provide the global attribute name // pEntry = (PGA_PROCESS_ENTRY)(&kGAProcTable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { if ((*pszAttribute == *(pEntry->pszAttributeName)) && (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING)) { // // attribute name matches // ASSERT(pEntry->pfnGetGAProc); return (pEntry->pfnGetGAProc)(pInfoHeader, dwFlags, pszAttribute, pdwDataType, pbData, cbSize, pcbNeeded); } } TERSE(("HGetGlobalAttribute: unknown global attribute %s\n", pszAttribute)); return E_INVALIDARG; } /*++ Routine Name: PGetOrderDepNode Routine Description: get the ORDERDEPEND strucutre associated with the specific feature/option Arguments: pInfoHeader - pointer to driver's INFOHEADER structure pPpdData - pointer to driver's PPDDATA structure dwFeatureIndex - feature index dwOptionIndex - option index (this could be OPTION_INDEX_ANY) Return Value: pointer to the ORDERDEPEND structure if succeeds NULL otherwise Last Error: None --*/ PORDERDEPEND PGetOrderDepNode( IN PINFOHEADER pInfoHeader, IN PPPDDATA pPpdData, IN DWORD dwFeatureIndex, IN DWORD dwOptionIndex ) { PORDERDEPEND pOrder; DWORD cIndex; pOrder = (PORDERDEPEND)OFFSET_TO_POINTER(&(pInfoHeader->RawData), pPpdData->OrderDeps.loOffset); ASSERT(pOrder != NULL || pPpdData->OrderDeps.dwCount == 0); if (pOrder == NULL) { return NULL; } for (cIndex = 0; cIndex < pPpdData->OrderDeps.dwCount; cIndex++, pOrder++) { if (pOrder->dwSection == SECTION_UNASSIGNED) continue; if (pOrder->dwFeatureIndex == dwFeatureIndex && pOrder->dwOptionIndex == dwOptionIndex) { return pOrder; } } return NULL; } /*++ Routine Name: HGetOrderDepSection Routine Description: get order dependency section name Arguments: pOrder - pointer to the ORDERDEPEND structure pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: S_OK E_OUTOFMEMORY see function HGetSingleData Last Error: None --*/ HRESULT HGetOrderDepSection( IN PORDERDEPEND pOrder, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { static const CHAR kpstrSections[][20] = { "DocumentSetup", "PageSetup", "Prolog", "ExitServer", "JCLSetup", "AnySetup" }; DWORD dwSectIndex; ASSERT(pOrder); switch (pOrder->dwPPDSection) { case SECTION_DOCSETUP: dwSectIndex = 0; break; case SECTION_PAGESETUP: dwSectIndex = 1; break; case SECTION_PROLOG: dwSectIndex = 2; break; case SECTION_EXITSERVER: dwSectIndex = 3; break; case SECTION_JCLSETUP: dwSectIndex = 4; break; case SECTION_ANYSETUP: default: dwSectIndex = 5; break; } return HGetSingleData((PVOID)kpstrSections[dwSectIndex], kADT_ASCII, strlen(kpstrSections[dwSectIndex]) + 1, pdwDataType, pbData, cbSize, pcbNeeded); } /*++ Routine Name: HGetFeatureAttribute Routine Description: get PPD feature attribute Arguments: pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the attribute get operation pszFeatureKeyword - PPD feature keyword name pszAttribute - name of the feature attribute pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: S_OK if succeeds E_OUTOFMEMORY if output data buffer size is not big enough E_INVALIDARG if feature keyword name or attribute name is not recognized Last Error: None --*/ HRESULT HGetFeatureAttribute( IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszFeatureKeyword, IN PCSTR pszAttribute, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { typedef struct _FA_ENTRY { PCSTR pszAttributeName; // feature attribute name BOOL bNeedOrderDepNode; // TRUE if the attribute only exist // when the feature has an *OrderDependency // entry in PPD, FALSE otherwise. } FA_ENTRY, *PFA_ENTRY; static const FA_ENTRY kFATable[] = { {kstrDisplayName, FALSE}, {kstrDefOption, FALSE}, {kstrOpenUIType, FALSE}, {kstrOpenGroupType, FALSE}, {kstrOrderDepValue, TRUE}, {kstrOrderDepSect, TRUE}, }; PUIINFO pUIInfo; PPPDDATA pPpdData; PFEATURE pFeature; PORDERDEPEND pOrder; DWORD dwFeatureIndex; pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader); ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO)); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA)); if (pUIInfo == NULL || pPpdData == NULL) { return E_FAIL; } if (!pszFeatureKeyword || (pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex)) == NULL) { ERR(("HGetFeatureAttribute: invalid feature\n")); return E_INVALIDARG; } pOrder = PGetOrderDepNode(pInfoHeader, pPpdData, dwFeatureIndex, OPTION_INDEX_ANY); if (!pszAttribute) { // // Client is asking for the full list of supported feature attribute names // PFA_ENTRY pEntry; DWORD cIndex; DWORD cTableEntry = sizeof(kFATable) / sizeof(FA_ENTRY); PSTR pCurrentOut; DWORD cbNeeded; INT cbRemain; if (pdwDataType) { *pdwDataType = kADT_ASCII; } pCurrentOut = (PSTR)pbData; cbNeeded = 0; cbRemain = (INT)cbSize; pEntry = (PFA_ENTRY)(&kFATable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { DWORD cbNameSize; // // If the attribute only exist when the feature has an *OrderDependency entry in PPD, // but we didn't find the feature's pOrder node, skip it. // if (pEntry->bNeedOrderDepNode && !pOrder) continue; // // count in the NUL between attribute keywords // cbNameSize = strlen(pEntry->pszAttributeName) + 1; if (pCurrentOut && cbRemain >= (INT)cbNameSize) { CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize); pCurrentOut += cbNameSize; } cbRemain -= cbNameSize; cbNeeded += cbNameSize; } // // remember the last NUL terminator for the MULTI_SZ output string // cbRemain--; cbNeeded++; if (pcbNeeded) { *pcbNeeded = cbNeeded; } if (!pCurrentOut || cbRemain < 0) { return E_OUTOFMEMORY; } *pCurrentOut = NUL; return S_OK; } // // Client does provide the feature attribute name // if ((*pszAttribute == kstrDisplayName[0]) && (strcmp(pszAttribute, kstrDisplayName) == EQUAL_STRING)) { PTSTR ptstrDispName; ptstrDispName = OFFSET_TO_POINTER(pInfoHeader, pFeature->loDisplayName); if (ptstrDispName == NULL) { return E_FAIL; } return HGetSingleData((PVOID)ptstrDispName, kADT_UNICODE, SIZE_OF_STRING(ptstrDispName), pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrDefOption[0]) && (strcmp(pszAttribute, kstrDefOption) == EQUAL_STRING)) { POPTION pOption; PSTR pstrKeywordName; pOption = PGetIndexedOption(pUIInfo, pFeature, pFeature->dwDefaultOptIndex); if (!pOption) { ERR(("HGetFeatureAttribute: can't find default option. Use the first one.\n")); pOption = PGetIndexedOption(pUIInfo, pFeature, 0); if (!pOption) { return E_FAIL; } } pstrKeywordName = OFFSET_TO_POINTER(pInfoHeader, pOption->loKeywordName); return HGetSingleData((PVOID)pstrKeywordName, kADT_ASCII, strlen(pstrKeywordName) + 1, pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrOpenUIType[0]) && (strcmp(pszAttribute, kstrOpenUIType) == EQUAL_STRING)) { static const CHAR pstrUITypes[][10] = { "PickOne", "PickMany", "Boolean" }; DWORD dwType = pFeature->dwUIType; if (dwType > UITYPE_BOOLEAN) { RIP(("HGetFeatureAttribute: invalid UIType %d\n", dwType)); dwType = 0; } return HGetSingleData((PVOID)pstrUITypes[dwType], kADT_ASCII, strlen(pstrUITypes[dwType]) + 1, pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrOpenGroupType[0]) && (strcmp(pszAttribute, kstrOpenGroupType) == EQUAL_STRING)) { static const CHAR pstrGroupTypes[][30] = { "InstallableOptions", "" }; DWORD dwType; dwType = (pFeature->dwFeatureType == FEATURETYPE_PRINTERPROPERTY) ? 0 : 1; return HGetSingleData((PVOID)pstrGroupTypes[dwType], kADT_ASCII, strlen(pstrGroupTypes[dwType]) + 1, pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrOrderDepValue[0]) && (strcmp(pszAttribute, kstrOrderDepValue) == EQUAL_STRING)) { if (!pOrder) { TERSE(("HGetFeatureAttribute: attribute %s not available\n", pszAttribute)); return E_INVALIDARG; } return HGetSingleData((PVOID)&(pOrder->lOrder), kADT_LONG, sizeof(LONG), pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrOrderDepSect[0]) && (strcmp(pszAttribute, kstrOrderDepSect) == EQUAL_STRING)) { if (!pOrder) { TERSE(("HGetFeatureAttribute: attribute %s not available\n", pszAttribute)); return E_INVALIDARG; } return HGetOrderDepSection(pOrder, pdwDataType, pbData, cbSize, pcbNeeded); } else { TERSE(("HGetFeatureAttribute: unknown feature attribute %s\n", pszAttribute)); return E_INVALIDARG; } } /*++ Routine Name: HGetOptionAttribute Routine Description: get option attribute of a PPD feature Arguments: pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the attribute get operation pszFeatureKeyword - PPD feature keyword name pszOptionKeyword - option keyword name of the PPD feature pszAttribute - name of the feature attribute pdwDataType - pointer to DWORD to store output data type pbData - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: S_OK if succeeds E_OUTOFMEMORY if output data buffer size is not big enough E_INVALIDARG if feature keyword name, or option keyword name, or attribute name is not recognized Last Error: None --*/ HRESULT HGetOptionAttribute( IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszFeatureKeyword, IN PCSTR pszOptionKeyword, IN PCSTR pszAttribute, OUT PDWORD pdwDataType, OUT PBYTE pbData, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { typedef struct _OA_ENTRY { PCSTR pszFeatureKeyword; // feature keyword name // (NULL for non-feature specific attributes) PCSTR pszOptionKeyword; // option keyword name // (NULL for non-option specific attributes) PCSTR pszAttributeName; // option attribute name (this field must be // unique across the table) BOOL bNeedOrderDepNode; // TRUE if the attribute only exist // when the option has an *OrderDependency // entry in PPD, FALSE otherwise. BOOL bSpecialHandle; // TRUE if the attribute needs special handling. // If TRUE, following table fields are not used. DWORD dwDataType; // data type of the attribute value DWORD cbNeeded; // byte count of the attribute value DWORD cbOffset; // byte offset to the attribute value, starting // from the beginning of OPTION structure } OA_ENTRY, *POA_ENTRY; static const OA_ENTRY kOATable[] = { {NULL, NULL, kstrDisplayName, FALSE, TRUE, 0, 0, 0}, {NULL, NULL, kstrInvocation, FALSE, TRUE, 0, 0, 0}, {NULL, NULL, kstrOrderDepValue, TRUE, TRUE, 0, 0, 0}, {NULL, NULL, kstrOrderDepSect, TRUE, TRUE, 0, 0, 0}, {kstrInputSlot, NULL, kstrReqPageRgn, FALSE, TRUE, 0, 0, 0}, {kstrOutputBin, NULL, kstrOutOrderRev, FALSE, FALSE, kADT_BOOL, sizeof(BOOL), offsetof(OUTPUTBIN, bOutputOrderReversed)}, {kstrPageSize, NULL, kstrPaperDim, FALSE, FALSE, kADT_SIZE, sizeof(SIZE), offsetof(PAGESIZE, szPaperSize)}, {kstrPageSize, NULL, kstrImgArea, FALSE, TRUE, 0, 0, 0}, {kstrPageSize, kstrCustomPS, kstrParamCustomPS, FALSE, TRUE, 0, 0, 0}, {kstrPageSize, kstrCustomPS, kstrHWMargins, FALSE, FALSE, kADT_RECT, sizeof(RECT), offsetof(PAGESIZE, rcImgArea)}, {kstrPageSize, kstrCustomPS, kstrMaxMWidth, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(PAGESIZE, szPaperSize) + offsetof(SIZE, cx)}, {kstrPageSize, kstrCustomPS, kstrMaxMHeight, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(PAGESIZE, szPaperSize) + offsetof(SIZE, cy)}, {kstrInstalledMem, NULL, kstrVMOption, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(MEMOPTION, dwInstalledMem)}, {kstrInstalledMem, NULL, kstrFCacheSize, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(MEMOPTION, dwFreeFontMem)}, }; PUIINFO pUIInfo; PPPDDATA pPpdData; PFEATURE pFeature; POPTION pOption; PORDERDEPEND pOrder; DWORD dwFeatureIndex, dwOptionIndex, cIndex; DWORD cTableEntry = sizeof(kOATable) / sizeof(OA_ENTRY); POA_ENTRY pEntry; pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader); ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO)); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA)); if (pUIInfo == NULL || pPpdData == NULL) { return E_FAIL; } if (!pszFeatureKeyword || (pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex)) == NULL) { ERR(("HGetOptionAttribute: invalid feature\n")); return E_INVALIDARG; } if (!pszOptionKeyword || (pOption = PGetNamedOption(pUIInfo, pFeature, pszOptionKeyword, &dwOptionIndex)) == NULL) { ERR(("HGetOptionAttribute: invalid option\n")); return E_INVALIDARG; } pOrder = PGetOrderDepNode(pInfoHeader, pPpdData, dwFeatureIndex, dwOptionIndex); if (!pszAttribute) { // // Client is asking for the full list of supported option attribute names // PSTR pCurrentOut; DWORD cbNeeded; INT cbRemain; if (pdwDataType) { *pdwDataType = kADT_ASCII; } pCurrentOut = (PSTR)pbData; cbNeeded = 0; cbRemain = (INT)cbSize; pEntry = (POA_ENTRY)(&kOATable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { DWORD cbNameSize; // // If the attribute is specific to a certain feature, check the feature keyword match. // if (pEntry->pszFeatureKeyword && (strcmp(pEntry->pszFeatureKeyword, pszFeatureKeyword) != EQUAL_STRING)) continue; // // If the attribute is specific to a certain option, check the option keyword match. // if (pEntry->pszOptionKeyword && (strcmp(pEntry->pszOptionKeyword, pszOptionKeyword) != EQUAL_STRING)) continue; // // special case: For PageSize's CustomPageSize option, we need to skip attributes // that are only available to PageSize's all non-CustomPageSize options. // if (pEntry->pszFeatureKeyword && !pEntry->pszOptionKeyword && (pFeature->dwFeatureID == GID_PAGESIZE) && (((PPAGESIZE)pOption)->dwPaperSizeID == DMPAPER_CUSTOMSIZE)) continue; // // If the attribute only exist when the option has an *OrderDependency entry in PPD, // but we didn't find the option's pOrder node, skip it. // if (pEntry->bNeedOrderDepNode && !pOrder) continue; // // count in the NUL between attribute keywords // cbNameSize = strlen(pEntry->pszAttributeName) + 1; if (pCurrentOut && cbRemain >= (INT)cbNameSize) { CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize); pCurrentOut += cbNameSize; } cbRemain -= cbNameSize; cbNeeded += cbNameSize; } // // remember the last NUL terminator for the MULTI_SZ output string. // cbRemain--; cbNeeded++; if (pcbNeeded) { *pcbNeeded = cbNeeded; } if (!pCurrentOut || cbRemain < 0) { return E_OUTOFMEMORY; } *pCurrentOut = NUL; return S_OK; } // // Client does provide the option attribute name // // // First handle a few special cases (bSpecialHandle == TRUE in the table). // Generic case handling is in the last else-part. // if ((*pszAttribute == kstrDisplayName[0]) && (strcmp(pszAttribute, kstrDisplayName) == EQUAL_STRING)) { // // "DisplayName" // PTSTR ptstrDispName; ptstrDispName = OFFSET_TO_POINTER(pInfoHeader, pOption->loDisplayName); if (ptstrDispName == NULL) { return E_FAIL; } return HGetSingleData((PVOID)ptstrDispName, kADT_UNICODE, SIZE_OF_STRING(ptstrDispName), pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrInvocation[0]) && (strcmp(pszAttribute, kstrInvocation) == EQUAL_STRING)) { // // "Invocation" // return HGetSingleData(OFFSET_TO_POINTER(pInfoHeader, pOption->Invocation.loOffset), kADT_BINARY, pOption->Invocation.dwCount, pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrOrderDepValue[0]) && (strcmp(pszAttribute, kstrOrderDepValue) == EQUAL_STRING)) { // // "OrderDependencyValue" // if (!pOrder) { TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute)); return E_INVALIDARG; } return HGetSingleData((PVOID)&(pOrder->lOrder), kADT_LONG, sizeof(LONG), pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrOrderDepSect[0]) && (strcmp(pszAttribute, kstrOrderDepSect) == EQUAL_STRING)) { // // "OrderDependencySection" // if (!pOrder) { TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute)); return E_INVALIDARG; } return HGetOrderDepSection(pOrder, pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrReqPageRgn[0]) && (strcmp(pszAttribute, kstrReqPageRgn) == EQUAL_STRING)) { // // "RequiresPageRegion" // PINPUTSLOT pInputSlot = (PINPUTSLOT)pOption; BOOL bValue; // // This attribute is only available to *InputSlot options, excluding the first // one "*UseFormTrayTable", which is synthesized by PPD parser. // if (pFeature->dwFeatureID != GID_INPUTSLOT || (dwOptionIndex == 0 && pInputSlot->dwPaperSourceID == DMBIN_FORMSOURCE)) { TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute)); return E_INVALIDARG; } bValue = (pInputSlot->dwFlags & INPUTSLOT_REQ_PAGERGN) ? TRUE : FALSE; return HGetSingleData((PVOID)&bValue, kADT_BOOL, sizeof(BOOL), pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrImgArea[0]) && (strcmp(pszAttribute, kstrImgArea) == EQUAL_STRING)) { // // "ImageableArea" // PPAGESIZE pPageSize = (PPAGESIZE)pOption; RECT rcImgArea; // // This attribute is only available to *PageSize options, excluding CustomPageSize option. // if (pFeature->dwFeatureID != GID_PAGESIZE || pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE) { TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute)); return E_INVALIDARG; } // // convert GDI coordinate system back to PS coordinate system // (see VPackPrinterFeatures() case GID_PAGESIZE) // rcImgArea.left = pPageSize->rcImgArea.left; rcImgArea.right = pPageSize->rcImgArea.right; rcImgArea.top = pPageSize->szPaperSize.cy - pPageSize->rcImgArea.top; rcImgArea.bottom = pPageSize->szPaperSize.cy - pPageSize->rcImgArea.bottom; return HGetSingleData((PVOID)&rcImgArea, kADT_RECT, sizeof(RECT), pdwDataType, pbData, cbSize, pcbNeeded); } else if ((*pszAttribute == kstrParamCustomPS[0]) && (strcmp(pszAttribute, kstrParamCustomPS) == EQUAL_STRING)) { // // "ParamCustomPageSize" // PPAGESIZE pPageSize = (PPAGESIZE)pOption; // // This attribute is only available to *PageSize feature's CustomPageSize option. // if (pFeature->dwFeatureID != GID_PAGESIZE || pPageSize->dwPaperSizeID != DMPAPER_CUSTOMSIZE) { TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute)); return E_INVALIDARG; } return HGetSingleData((PVOID)(pPpdData->CustomSizeParams), kADT_CUSTOMSIZEPARAMS, sizeof(pPpdData->CustomSizeParams), pdwDataType, pbData, cbSize, pcbNeeded); } else { // // generic case handling // pEntry = (POA_ENTRY)(&kOATable[0]); for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++) { // // skip any entry that has already been specially handled // if (pEntry->bSpecialHandle) continue; ASSERT(pEntry->bNeedOrderDepNode == FALSE); if ((*pszAttribute == *(pEntry->pszAttributeName)) && (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING)) { // // Attribute name matches. We still need to verify feature/option keyword match. // if (pEntry->pszFeatureKeyword && strcmp(pEntry->pszFeatureKeyword, pszFeatureKeyword) != EQUAL_STRING) { TERSE(("HGetOptionAttribute: feature keyword mismatch for attribute %s\n", pszAttribute)); return E_INVALIDARG; } if (pEntry->pszOptionKeyword && (strcmp(pEntry->pszOptionKeyword, pszOptionKeyword) != EQUAL_STRING)) { TERSE(("HGetOptionAttribute: option keyword mismatch for attribute %s\n", pszAttribute)); return E_INVALIDARG; } // // special case: For PageSize's CustomPageSize option, we need to skip attributes // that are only available to PageSize's all non-CustomPageSize options. // if (pEntry->pszFeatureKeyword && !pEntry->pszOptionKeyword && (pFeature->dwFeatureID == GID_PAGESIZE) && (((PPAGESIZE)pOption)->dwPaperSizeID == DMPAPER_CUSTOMSIZE)) continue; return HGetSingleData((PVOID)((PBYTE)pOption + pEntry->cbOffset), pEntry->dwDataType, pEntry->cbNeeded, pdwDataType, pbData, cbSize, pcbNeeded); } } TERSE(("HGetOptionAttribute: unknown option attribute %s\n", pszAttribute)); return E_INVALIDARG; } } /*++ Routine Name: BIsSupported_PSF Routine Description: determine if the PS driver synthesized feature is supported or not Arguments: pszFeature - name of the PS driver synthesized feature pUIInfo - pointer to driver's UIINFO structure pPpdData - pointer to driver's PPDDATA structure bEMFSpooling - whether spooler EMF spooling is enabled or not Return Value: TRUE if the feature is currently supported FALSE otherwise Last Error: None --*/ BOOL BIsSupported_PSF( IN PCSTR pszFeature, IN PUIINFO pUIInfo, IN PPPDDATA pPpdData, IN BOOL bEMFSpooling ) { #ifdef WINNT_40 // // On NT4, bEMFSpooling should always be FALSE. // ASSERT(!bEMFSpooling); #endif // WINNT_40 // // Note that the first character is always the % prefix. // if ((pszFeature[1] == kstrPSFAddEuro[1]) && (strcmp(pszFeature, kstrPSFAddEuro) == EQUAL_STRING)) { // // AddEuro is only supported for Level 2+ printers. // return(pUIInfo->dwLangLevel >= 2); } else if ((pszFeature[1] == kstrPSFEMF[1]) && (strcmp(pszFeature, kstrPSFEMF) == EQUAL_STRING)) { // // Driver EMF is always supported on NT4, and only supported // when spooler EMF is enabled on Win2K+. // #ifndef WINNT_40 return bEMFSpooling; #else return TRUE; #endif // !WINNT_40 } else if ((pszFeature[1] == kstrPSFNegative[1]) && (strcmp(pszFeature, kstrPSFNegative) == EQUAL_STRING)) { // // Negative is only supported for b/w printers. // return(IS_COLOR_DEVICE(pUIInfo) ? FALSE : TRUE); } else if ((pszFeature[1] == kstrPSFPageOrder[1]) && (strcmp(pszFeature, kstrPSFPageOrder) == EQUAL_STRING)) { // // PageOrder is not supported on NT4, and is only supported // when spooler EMF is enabled on Win2K+. // return bEMFSpooling; } else { return TRUE; } } /*++ Routine Name: HEnumFeaturesOrOptions Routine Description: enumerate the feature or option keyword name list Arguments: hPrinter - printer handle pInfoHeader - pointer to driver's INFOHEADER structure dwFlags - flags for the enumeration operation pszFeatureKeyword - feature keyword name. This should be NULL for feature enumeration and non-NULL for option enumeration. pmszOutputList - pointer to output data buffer cbSize - output data buffer size in bytes pcbNeeded - buffer size in bytes needed to store the output data Return Value: S_OK if succeeds E_OUTOFMEMORY if output data buffer size is not big enough E_INVALIDARG if for option enumeration, feature keyword name is not recognized E_NOTIMPL if being called to enumerate options of PS driver synthesized feature that is not currently supported or whose options are not enumerable E_FAIL if other internal failures are encountered Last Error: None --*/ HRESULT HEnumFeaturesOrOptions( IN HANDLE hPrinter, IN PINFOHEADER pInfoHeader, IN DWORD dwFlags, IN PCSTR pszFeatureKeyword, OUT PSTR pmszOutputList, IN DWORD cbSize, OUT PDWORD pcbNeeded ) { PUIINFO pUIInfo; PPPDDATA pPpdData; PFEATURE pFeature; POPTION pOption; DWORD cIndex, cPPDFeaturesOrOptions; BOOL bEnumFeatures, bEnumPPDOptions; PSTR pCurrentOut; DWORD cbNeeded; INT cbRemain; BOOL bEMFSpooling; PPSFEATURE_ENTRY pEntry; pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader); pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader); ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO)); ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA)); if (pUIInfo == NULL || pPpdData == NULL) { return E_FAIL; } pCurrentOut = pmszOutputList; cbNeeded = 0; cbRemain = (INT)cbSize; bEnumFeatures = pszFeatureKeyword ? FALSE : TRUE; bEnumPPDOptions = TRUE; if (bEnumFeatures) { // // Enumerate driver synthersized features first. // VGetSpoolerEmfCaps(hPrinter, NULL, &bEMFSpooling, 0, NULL); pEntry = (PPSFEATURE_ENTRY)(&kPSFeatureTable[0]); while (pEntry->pszPSFeatureName) { if (BIsSupported_PSF(pEntry->pszPSFeatureName, pUIInfo, pPpdData, bEMFSpooling)) { DWORD cbNameLen; cbNameLen = strlen(pEntry->pszPSFeatureName) + 1; if (pCurrentOut && cbRemain >= (INT)cbNameLen) { CopyMemory(pCurrentOut, pEntry->pszPSFeatureName, cbNameLen); pCurrentOut += cbNameLen; } cbRemain -= cbNameLen; cbNeeded += cbNameLen; } pEntry++; } } else { if (*pszFeatureKeyword == PSFEATURE_PREFIX) { bEnumPPDOptions = FALSE; VGetSpoolerEmfCaps(hPrinter, NULL, &bEMFSpooling, 0, NULL); if (!BIsSupported_PSF(pszFeatureKeyword, pUIInfo, pPpdData, bEMFSpooling)) { WARNING(("HEnumFeaturesOrOptions: feature %s is not supported\n", pszFeatureKeyword)); return E_NOTIMPL; } } } if (bEnumFeatures) { cPPDFeaturesOrOptions = pUIInfo->dwDocumentFeatures + pUIInfo->dwPrinterFeatures; pFeature = OFFSET_TO_POINTER(pInfoHeader, pUIInfo->loFeatureList); ASSERT(cPPDFeaturesOrOptions == 0 || pFeature != NULL); if (pFeature == NULL) { return E_FAIL; } } else if (bEnumPPDOptions) { DWORD dwFeatureIndex; pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex); if (!pFeature) { ERR(("HEnumFeaturesOrOptions: unrecognized feature %s\n", pszFeatureKeyword)); return E_INVALIDARG; } cPPDFeaturesOrOptions = pFeature->Options.dwCount; pOption = OFFSET_TO_POINTER(pInfoHeader, pFeature->Options.loOffset); ASSERT(cPPDFeaturesOrOptions == 0 || pOption != NULL); if (pOption == NULL) { return E_FAIL; } } else { // // Enum driver synthersized feature's options. // pEntry = (PPSFEATURE_ENTRY)(&kPSFeatureTable[0]); while (pEntry->pszPSFeatureName) { if ((*pszFeatureKeyword == *(pEntry->pszPSFeatureName)) && strcmp(pszFeatureKeyword, pEntry->pszPSFeatureName) == EQUAL_STRING) { if (!pEntry->bEnumerableOptions) { // // This driver feature doesn't support option enumeration. // WARNING(("HEnumFeaturesOrOptions: enum options not supported for %s\n", pszFeatureKeyword)); return E_NOTIMPL; } if (pEntry->bBooleanOptions) { // // This driver feature has True/False boolean options. // DWORD cbKwdTrueSize, cbKwdFalseSize; cbKwdTrueSize = strlen(kstrKwdTrue) + 1; cbKwdFalseSize = strlen(kstrKwdFalse) + 1; if (pCurrentOut && (cbRemain >= (INT)(cbKwdTrueSize + cbKwdFalseSize))) { CopyMemory(pCurrentOut, kstrKwdTrue, cbKwdTrueSize); pCurrentOut += cbKwdTrueSize; CopyMemory(pCurrentOut, kstrKwdFalse, cbKwdFalseSize); pCurrentOut += cbKwdFalseSize; } cbRemain -= (cbKwdTrueSize + cbKwdFalseSize); cbNeeded += cbKwdTrueSize + cbKwdFalseSize; } else { // // This driver feature needs special handler to enumerate its options. // if (pEntry->pfnPSProc) { DWORD cbPSFOptionsSize; BOOL bResult; bResult = (pEntry->pfnPSProc)(hPrinter, pUIInfo, pPpdData, NULL, NULL, pszFeatureKeyword, NULL, pCurrentOut, cbRemain, &cbPSFOptionsSize, PSFPROC_ENUMOPTION_MODE); if (bResult) { pCurrentOut += cbPSFOptionsSize; } else { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { ERR(("HEnumFeaturesOrOptions: enum options failed for %s\n", pszFeatureKeyword)); return E_FAIL; } } cbRemain -= cbPSFOptionsSize; cbNeeded += cbPSFOptionsSize; } else { RIP(("HEnumFeaturesOrOptions: %%-feature handle is NULL for %s\n", pszFeatureKeyword)); return E_FAIL; } } break; } pEntry++; } if (pEntry->pszPSFeatureName == NULL) { ERR(("HEnumFeaturesOrOptions: unrecognized feature %s\n", pszFeatureKeyword)); return E_INVALIDARG; } cPPDFeaturesOrOptions = 0; } for (cIndex = 0; cIndex < cPPDFeaturesOrOptions; cIndex++) { // // Now enumerate PPD features/options. // PSTR pszKeyword; DWORD cbKeySize; if (bEnumFeatures) { pszKeyword = OFFSET_TO_POINTER(pInfoHeader, pFeature->loKeywordName); } else { pszKeyword = OFFSET_TO_POINTER(pInfoHeader, pOption->loKeywordName); } if (pszKeyword == NULL) { ASSERT(pszKeyword != NULL); return E_FAIL; } // // count in the NUL character between feature/option keywords // cbKeySize = strlen(pszKeyword) + 1; if (pCurrentOut && cbRemain >= (INT)cbKeySize) { CopyMemory(pCurrentOut, pszKeyword, cbKeySize); pCurrentOut += cbKeySize; } cbRemain -= cbKeySize; cbNeeded += cbKeySize; if (bEnumFeatures) { pFeature++; } else { pOption = (POPTION)((PBYTE)pOption + pFeature->dwOptionSize); } } // // remember the last NUL terminator for the MULTI_SZ output string // cbRemain--; cbNeeded++; if (pcbNeeded) { *pcbNeeded = cbNeeded; } if (!pCurrentOut || cbRemain < 0) { return E_OUTOFMEMORY; } *pCurrentOut = NUL; return S_OK; }