Leaked source code of windows server 2003
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.

2388 lines
70 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. getdata.c
  6. Abstract:
  7. PostScript helper functions for OEM plugins
  8. HGetGlobalAttribute
  9. HGetFeatureAttribute
  10. HGetOptionAttribute
  11. HEnumFeaturesOrOptions
  12. Author:
  13. Feng Yue (fengy)
  14. 8/24/2000 fengy Completed with support of both PPD and driver features.
  15. 5/22/2000 fengy Created it with function framework.
  16. --*/
  17. #include "lib.h"
  18. #include "ppd.h"
  19. #include "pslib.h"
  20. //
  21. // PS driver's helper functions for OEM plugins
  22. //
  23. //
  24. // global attribute names
  25. //
  26. const CHAR kstrCenterReg[] = "CenterRegistered";
  27. const CHAR kstrColorDevice[] = "ColorDevice";
  28. const CHAR kstrExtensions[] = "Extensions";
  29. const CHAR kstrFileVersion[] = "FileVersion";
  30. const CHAR kstrFreeVM[] = "FreeVM";
  31. const CHAR kstrLSOrientation[] = "LandscapeOrientation";
  32. const CHAR kstrLangEncoding[] = "LanguageEncoding";
  33. const CHAR kstrLangLevel[] = "LanguageLevel";
  34. const CHAR kstrNickName[] = "NickName";
  35. const CHAR kstrPPDAdobe[] = "PPD-Adobe";
  36. const CHAR kstrPrintError[] = "PrintPSErrors";
  37. const CHAR kstrProduct[] = "Product";
  38. const CHAR kstrProtocols[] = "Protocols";
  39. const CHAR kstrPSVersion[] = "PSVersion";
  40. const CHAR kstrJobTimeout[] = "SuggestedJobTimeout";
  41. const CHAR kstrWaitTimeout[] = "SuggestedWaitTimeout";
  42. const CHAR kstrThroughput[] = "Throughput";
  43. const CHAR kstrTTRasterizer[] = "TTRasterizer";
  44. //
  45. // feature attribute names
  46. //
  47. const CHAR kstrDisplayName[] = "DisplayName";
  48. const CHAR kstrDefOption[] = "DefaultOption";
  49. const CHAR kstrOpenUIType[] = "OpenUIType";
  50. const CHAR kstrOpenGroupType[] = "OpenGroupType";
  51. const CHAR kstrOrderDepValue[] = "OrderDependencyValue";
  52. const CHAR kstrOrderDepSect[] = "OrderDependencySection";
  53. //
  54. // option keyword names, option attribute names
  55. //
  56. const CHAR kstrInvocation[] = "Invocation";
  57. const CHAR kstrInputSlot[] = "InputSlot";
  58. const CHAR kstrReqPageRgn[] = "RequiresPageRegion";
  59. const CHAR kstrOutputBin[] = "OutputBin";
  60. const CHAR kstrOutOrderRev[] = "OutputOrderReversed";
  61. const CHAR kstrPageSize[] = "PageSize";
  62. const CHAR kstrPaperDim[] = "PaperDimension";
  63. const CHAR kstrImgArea[] = "ImageableArea";
  64. const CHAR kstrCustomPS[] = "CustomPageSize";
  65. const CHAR kstrParamCustomPS[] = "ParamCustomPageSize";
  66. const CHAR kstrHWMargins[] = "HWMargins";
  67. const CHAR kstrMaxMWidth[] = "MaxMediaWidth";
  68. const CHAR kstrMaxMHeight[] = "MaxMediaHeight";
  69. const CHAR kstrInstalledMem[] = "InstalledMemory";
  70. const CHAR kstrVMOption[] = "VMOption";
  71. const CHAR kstrFCacheSize[] = "FCacheSize";
  72. //
  73. // enumeration of data region where an attribute is stored
  74. //
  75. typedef enum _EATTRIBUTE_DATAREGION {
  76. kADR_UIINFO, // attribute is stored in UIINFO structure
  77. kADR_PPDDATA, // attribute is stored in PPDDATA structure
  78. } EATTRIBUTE_DATAREGION;
  79. /*++
  80. Routine Name:
  81. HGetSingleData
  82. Routine Description:
  83. copy source data to specified output buffer and set the output data type
  84. Arguments:
  85. pSrcData - pointer to source data buffer
  86. dwSrcDataType - source data type
  87. cbSrcSize - source data buffer size in bytes
  88. pdwOutDataType - pointer to DWORD to store output data type
  89. pbOutData - pointer to output data buffer
  90. cbOutSize - output data buffer size in bytes
  91. pcbNeeded - buffer size in bytes needed to store the output data
  92. Return Value:
  93. S_OK if succeeds
  94. E_OUTOFMEMORY if output data buffer size is not big enough
  95. Last Error:
  96. None
  97. --*/
  98. HRESULT
  99. HGetSingleData(
  100. IN PVOID pSrcData,
  101. IN DWORD dwSrcDataType,
  102. IN DWORD cbSrcSize,
  103. OUT PDWORD pdwOutDataType,
  104. OUT PBYTE pbOutData,
  105. IN DWORD cbOutSize,
  106. OUT PDWORD pcbNeeded
  107. )
  108. {
  109. //
  110. // Either pSrcData is NULL and cbSrcSize is 0,
  111. // or pSrcData is non-NULL and cbSrcSize is non-0.
  112. //
  113. ASSERT((pSrcData != NULL) || (cbSrcSize == 0));
  114. ASSERT((cbSrcSize != 0) || (pSrcData == NULL));
  115. if (pdwOutDataType)
  116. {
  117. *pdwOutDataType = dwSrcDataType;
  118. }
  119. if (pcbNeeded)
  120. {
  121. *pcbNeeded = cbSrcSize;
  122. }
  123. if (cbSrcSize)
  124. {
  125. //
  126. // We do have data for output.
  127. //
  128. if (!pbOutData || cbOutSize < cbSrcSize)
  129. {
  130. return E_OUTOFMEMORY;
  131. }
  132. CopyMemory(pbOutData, pSrcData, cbSrcSize);
  133. }
  134. return S_OK;
  135. }
  136. /*++
  137. Routine Name:
  138. HGetGABool
  139. Routine Description:
  140. get global boolean attribute
  141. Arguments:
  142. pInfoHeader - pointer to driver's INFOHEADER structure
  143. dwFlags - flags for the attribute Get operation
  144. pszAttribute - name of the global attribute
  145. pdwDataType - pointer to DWORD to store output data type
  146. pbData - pointer to output data buffer
  147. cbSize - output data buffer size in bytes
  148. pcbNeeded - buffer size in bytes needed to store the output data
  149. Return Value:
  150. E_INVALIDARG if the global attribute is not recognized
  151. S_OK
  152. E_OUTOFMEMORY see function HGetSingleData
  153. Last Error:
  154. None
  155. --*/
  156. HRESULT
  157. HGetGABool(
  158. IN PINFOHEADER pInfoHeader,
  159. IN DWORD dwFlags,
  160. IN PCSTR pszAttribute,
  161. OUT PDWORD pdwDataType,
  162. OUT PBYTE pbData,
  163. IN DWORD cbSize,
  164. OUT PDWORD pcbNeeded
  165. )
  166. {
  167. typedef struct _GA_BOOL_ENTRY {
  168. PCSTR pszAttributeName; // attribute name
  169. EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
  170. DWORD cbOffset; // byte offset to the DWORD data
  171. DWORD dwFlagBit; // bit flag in the DWORD
  172. } GA_BOOL_ENTRY, *PGA_BOOL_ENTRY;
  173. static const GA_BOOL_ENTRY kGABoolTable[] =
  174. {
  175. {kstrCenterReg, kADR_PPDDATA, offsetof(PPDDATA, dwCustomSizeFlags), CUSTOMSIZE_CENTERREG},
  176. {kstrColorDevice, kADR_UIINFO, offsetof(UIINFO, dwFlags), FLAG_COLOR_DEVICE},
  177. {kstrPrintError, kADR_PPDDATA, offsetof(PPDDATA, dwFlags), PPDFLAG_PRINTPSERROR},
  178. };
  179. PUIINFO pUIInfo;
  180. PPPDDATA pPpdData;
  181. DWORD cIndex;
  182. DWORD cTableEntry = sizeof(kGABoolTable) / sizeof(GA_BOOL_ENTRY);
  183. PGA_BOOL_ENTRY pEntry;
  184. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
  185. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
  186. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  187. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  188. if (pUIInfo == NULL || pPpdData == NULL)
  189. {
  190. return E_FAIL;
  191. }
  192. pEntry = (PGA_BOOL_ENTRY)(&kGABoolTable[0]);
  193. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  194. {
  195. if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
  196. (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
  197. {
  198. //
  199. // attribute name matches
  200. //
  201. DWORD dwValue;
  202. BOOL bValue;
  203. if (pEntry->eADR == kADR_UIINFO)
  204. {
  205. dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset));
  206. }
  207. else if (pEntry->eADR == kADR_PPDDATA)
  208. {
  209. dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset));
  210. }
  211. else
  212. {
  213. //
  214. // This shouldn't happen. It's here to catch our coding error.
  215. //
  216. RIP(("HGetGABool: unknown eADR %d\n", pEntry->eADR));
  217. return E_FAIL;
  218. }
  219. //
  220. // map the bit flag to boolean value
  221. //
  222. bValue = (dwValue & pEntry->dwFlagBit) ? TRUE : FALSE;
  223. return HGetSingleData((PVOID)&bValue, kADT_BOOL, sizeof(BOOL),
  224. pdwDataType, pbData, cbSize, pcbNeeded);
  225. }
  226. }
  227. //
  228. // can't find the attribute
  229. //
  230. // This shouldn't happen. It's here to catch our coding error.
  231. //
  232. RIP(("HGetGABool: unknown attribute %s\n", pszAttribute));
  233. return E_INVALIDARG;
  234. }
  235. /*++
  236. Routine Name:
  237. HGetGAInvocation
  238. Routine Description:
  239. get global invocation attribute
  240. Arguments:
  241. pInfoHeader - pointer to driver's INFOHEADER structure
  242. dwFlags - flags for the attribute Get operation
  243. pszAttribute - name of the global attribute
  244. pdwDataType - pointer to DWORD to store output data type
  245. pbData - pointer to output data buffer
  246. cbSize - output data buffer size in bytes
  247. pcbNeeded - buffer size in bytes needed to store the output data
  248. Return Value:
  249. E_INVALIDARG if the global attribute is not recognized
  250. S_OK
  251. E_OUTOFMEMORY see function HGetSingleData
  252. Last Error:
  253. None
  254. --*/
  255. HRESULT
  256. HGetGAInvocation(
  257. IN PINFOHEADER pInfoHeader,
  258. IN DWORD dwFlags,
  259. IN PCSTR pszAttribute,
  260. OUT PDWORD pdwDataType,
  261. OUT PBYTE pbData,
  262. IN DWORD cbSize,
  263. OUT PDWORD pcbNeeded
  264. )
  265. {
  266. typedef struct _GA_INVOC_ENTRY {
  267. PCSTR pszAttributeName; // attribute name
  268. EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
  269. DWORD cbOffset; // byte offset to INVOCATION structure
  270. } GA_INVOC_ENTRY, *PGA_INVOC_ENTRY;
  271. static const GA_INVOC_ENTRY kGAInvocTable[] =
  272. {
  273. {kstrProduct, kADR_PPDDATA, offsetof(PPDDATA, Product)},
  274. {kstrPSVersion, kADR_PPDDATA, offsetof(PPDDATA, PSVersion)},
  275. };
  276. PUIINFO pUIInfo;
  277. PPPDDATA pPpdData;
  278. DWORD cIndex;
  279. DWORD cTableEntry = sizeof(kGAInvocTable) / sizeof(GA_INVOC_ENTRY);
  280. PGA_INVOC_ENTRY pEntry;
  281. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
  282. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
  283. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  284. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  285. if (pUIInfo == NULL || pPpdData == NULL)
  286. {
  287. return E_FAIL;
  288. }
  289. pEntry = (PGA_INVOC_ENTRY)(&kGAInvocTable[0]);
  290. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  291. {
  292. if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
  293. (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
  294. {
  295. //
  296. // attribute name matches
  297. //
  298. PINVOCATION pInvoc;
  299. if (pEntry->eADR == kADR_UIINFO)
  300. {
  301. pInvoc = (PINVOCATION)((PBYTE)pUIInfo + pEntry->cbOffset);
  302. }
  303. else if (pEntry->eADR == kADR_PPDDATA)
  304. {
  305. pInvoc = (PINVOCATION)((PBYTE)pPpdData + pEntry->cbOffset);
  306. }
  307. else
  308. {
  309. //
  310. // This shouldn't happen. It's here to catch our coding error.
  311. //
  312. RIP(("HGetGAInvocation: unknown eADR %d\n", pEntry->eADR));
  313. return E_FAIL;
  314. }
  315. return HGetSingleData(OFFSET_TO_POINTER(pInfoHeader, pInvoc->loOffset),
  316. kADT_BINARY, pInvoc->dwCount,
  317. pdwDataType, pbData, cbSize, pcbNeeded);
  318. }
  319. }
  320. //
  321. // can't find the attribute
  322. //
  323. // This shouldn't happen. It's here to catch our coding error.
  324. //
  325. RIP(("HGetGAInvocation: unknown attribute %s\n", pszAttribute));
  326. return E_INVALIDARG;
  327. }
  328. /*++
  329. Routine Name:
  330. HGetGAString
  331. Routine Description:
  332. get global ASCII string attribute
  333. Arguments:
  334. pInfoHeader - pointer to driver's INFOHEADER structure
  335. dwFlags - flags for the attribute Get operation
  336. pszAttribute - name of the global attribute
  337. pdwDataType - pointer to DWORD to store output data type
  338. pbData - pointer to output data buffer
  339. cbSize - output data buffer size in bytes
  340. pcbNeeded - buffer size in bytes needed to store the output data
  341. Return Value:
  342. S_OK if succeeds
  343. E_OUTOFMEMORY if output data buffer size is not big enough
  344. Last Error:
  345. None
  346. --*/
  347. HRESULT
  348. HGetGAString(
  349. IN PINFOHEADER pInfoHeader,
  350. IN DWORD dwFlags,
  351. IN PCSTR pszAttribute,
  352. OUT PDWORD pdwDataType,
  353. OUT PBYTE pbData,
  354. IN DWORD cbSize,
  355. OUT PDWORD pcbNeeded
  356. )
  357. {
  358. typedef struct _GA_STRING_ENTRY {
  359. PCSTR pszAttributeName; // attribute name
  360. EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
  361. DWORD cbOffset; // byte offset to the DWORD data
  362. BOOL bCheckDWord; // TRUE to check the whole DWORD
  363. // FALSE to check a bit in the DWORD
  364. // (If bCheckDWord is TRUE, table look
  365. // up will stop when first match is found.)
  366. BOOL bCheckBitSet; // TRUE to check if the bit is set
  367. // FALSE to check if the bit is cleared
  368. // (this is ignored if bCheckDWord is TRUE)
  369. DWORD dwFlag; // flag value
  370. PCSTR pszValue; // registered value string
  371. } GA_STRING_ENTRY, *PGA_STRING_ENTRY;
  372. static const GA_STRING_ENTRY kGAStringTable[] =
  373. {
  374. {kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_DPS, "DPS"},
  375. {kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_CMYK, "CMYK"},
  376. {kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_COMPOSITE, "Composite"},
  377. {kstrExtensions, kADR_PPDDATA, offsetof(PPDDATA, dwExtensions), FALSE, TRUE, LANGEXT_FILESYSTEM, "FileSystem"},
  378. {kstrLSOrientation, kADR_UIINFO, offsetof(UIINFO, dwFlags), FALSE, TRUE, FLAG_ROTATE90, "Plus90"},
  379. {kstrLSOrientation, kADR_UIINFO, offsetof(UIINFO, dwFlags), FALSE, FALSE, FLAG_ROTATE90, "Minus90"},
  380. {kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_ISOLATIN1, "ISOLatin1"},
  381. {kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_UNICODE, "Unicode"},
  382. {kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_JIS83_RKSJ, "JIS83-RKSJ"},
  383. {kstrLangEncoding, kADR_UIINFO, offsetof(UIINFO, dwLangEncoding), TRUE, FALSE, LANGENC_NONE, "None"},
  384. {kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_BCP, "BCP"},
  385. {kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_PJL, "PJL"},
  386. {kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_TBCP, "TBCP"},
  387. {kstrProtocols, kADR_UIINFO, offsetof(UIINFO, dwProtocols), FALSE, TRUE, PROTOCOL_SIC, "SIC"},
  388. {kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_NONE, "None"},
  389. {kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_ACCEPT68K, "Accept68K"},
  390. {kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_TYPE42, "Type42"},
  391. {kstrTTRasterizer, kADR_UIINFO, offsetof(UIINFO, dwTTRasterizer), TRUE, FALSE, TTRAS_TRUEIMAGE, "TrueImage"},
  392. };
  393. PUIINFO pUIInfo;
  394. PPPDDATA pPpdData;
  395. PGA_STRING_ENTRY pEntry;
  396. DWORD cTableEntry = sizeof(kGAStringTable) / sizeof(GA_STRING_ENTRY);
  397. PSTR pCurrentOut;
  398. DWORD cbNeeded, cIndex;
  399. INT cbRemain;
  400. if (pdwDataType)
  401. {
  402. *pdwDataType = kADT_ASCII;
  403. }
  404. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
  405. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
  406. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  407. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  408. if (pUIInfo == NULL || pPpdData == NULL)
  409. {
  410. return E_FAIL;
  411. }
  412. pCurrentOut = (PSTR)pbData;
  413. cbNeeded = 0;
  414. cbRemain = (INT)cbSize;
  415. pEntry = (PGA_STRING_ENTRY)(&kGAStringTable[0]);
  416. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  417. {
  418. if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
  419. (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
  420. {
  421. //
  422. // attribute name matches
  423. //
  424. DWORD dwValue;
  425. BOOL bMatch;
  426. if (pEntry->eADR == kADR_UIINFO)
  427. {
  428. dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset));
  429. }
  430. else if (pEntry->eADR == kADR_PPDDATA)
  431. {
  432. dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset));
  433. }
  434. else
  435. {
  436. //
  437. // This shouldn't happen. It's here to catch our coding error.
  438. //
  439. RIP(("HGetGAString: unknown eADR %d\n", pEntry->eADR));
  440. return E_FAIL;
  441. }
  442. if (pEntry->bCheckDWord)
  443. {
  444. //
  445. // check the whole DWORD
  446. //
  447. bMatch = (dwValue == pEntry->dwFlag) ? TRUE : FALSE;
  448. }
  449. else
  450. {
  451. BOOL bBitIsSet;
  452. //
  453. // check the one bit in the DWORD
  454. //
  455. bBitIsSet = (dwValue & pEntry->dwFlag) ? TRUE : FALSE;
  456. bMatch = (bBitIsSet == pEntry->bCheckBitSet ) ? TRUE : FALSE;
  457. }
  458. if (bMatch)
  459. {
  460. DWORD cbNameSize;
  461. //
  462. // count in the NUL delimiter
  463. //
  464. cbNameSize = strlen(pEntry->pszValue) + 1;
  465. if (pCurrentOut && cbRemain >= (INT)cbNameSize)
  466. {
  467. CopyMemory(pCurrentOut, pEntry->pszValue, cbNameSize);
  468. pCurrentOut += cbNameSize;
  469. }
  470. cbRemain -= cbNameSize;
  471. cbNeeded += cbNameSize;
  472. if (pEntry->bCheckDWord)
  473. {
  474. //
  475. // stop table look up when first match is found if we are
  476. // checking the whole DWORD instead of bits in the DWORD.
  477. //
  478. break;
  479. }
  480. }
  481. }
  482. }
  483. //
  484. // remember the the last NUL terminator for the MULTI_SZ output string
  485. //
  486. cbRemain--;
  487. cbNeeded++;
  488. if (pcbNeeded)
  489. {
  490. *pcbNeeded = cbNeeded;
  491. }
  492. if (!pCurrentOut || cbRemain < 0)
  493. {
  494. return E_OUTOFMEMORY;
  495. }
  496. *pCurrentOut = NUL;
  497. return S_OK;
  498. }
  499. /*++
  500. Routine Name:
  501. HGetGADWord
  502. Routine Description:
  503. get global DWORD attribute
  504. Arguments:
  505. pInfoHeader - pointer to driver's INFOHEADER structure
  506. dwFlags - flags for the attribute Get operation
  507. pszAttribute - name of the global attribute
  508. pdwDataType - pointer to DWORD to store output data type
  509. pbData - pointer to output data buffer
  510. cbSize - output data buffer size in bytes
  511. pcbNeeded - buffer size in bytes needed to store the output data
  512. Return Value:
  513. E_INVALIDARG if the global attribute is not recognized
  514. S_OK
  515. E_OUTOFMEMORY see function HGetSingleData
  516. Last Error:
  517. None
  518. --*/
  519. HRESULT
  520. HGetGADWord(
  521. IN PINFOHEADER pInfoHeader,
  522. IN DWORD dwFlags,
  523. IN PCSTR pszAttribute,
  524. OUT PDWORD pdwDataType,
  525. OUT PBYTE pbData,
  526. IN DWORD cbSize,
  527. OUT PDWORD pcbNeeded
  528. )
  529. {
  530. typedef struct _GA_DWORD_ENTRY {
  531. PCSTR pszAttributeName; // attribute name
  532. EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
  533. DWORD cbOffset; // byte offset to the DWORD data
  534. } GA_DWORD_ENTRY, *PGA_DWORD_ENTRY;
  535. static const GA_DWORD_ENTRY kGADWordTable[] =
  536. {
  537. {kstrFileVersion, kADR_PPDDATA, offsetof(PPDDATA, dwPpdFilever)},
  538. {kstrFreeVM, kADR_UIINFO, offsetof(UIINFO, dwFreeMem)},
  539. {kstrLangLevel, kADR_UIINFO, offsetof(UIINFO, dwLangLevel)},
  540. {kstrPPDAdobe, kADR_UIINFO, offsetof(UIINFO, dwSpecVersion)},
  541. {kstrJobTimeout, kADR_UIINFO, offsetof(UIINFO, dwJobTimeout)},
  542. {kstrWaitTimeout, kADR_UIINFO, offsetof(UIINFO, dwWaitTimeout)},
  543. {kstrThroughput, kADR_UIINFO, offsetof(UIINFO, dwPrintRate)},
  544. };
  545. PUIINFO pUIInfo;
  546. PPPDDATA pPpdData;
  547. DWORD cIndex;
  548. DWORD cTableEntry = sizeof(kGADWordTable) / sizeof(GA_DWORD_ENTRY);
  549. PGA_DWORD_ENTRY pEntry;
  550. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
  551. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
  552. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  553. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  554. if (pUIInfo == NULL || pPpdData == NULL)
  555. {
  556. return E_FAIL;
  557. }
  558. pEntry = (PGA_DWORD_ENTRY)(&kGADWordTable[0]);
  559. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  560. {
  561. if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
  562. (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
  563. {
  564. //
  565. // attribute name matches
  566. //
  567. DWORD dwValue;
  568. if (pEntry->eADR == kADR_UIINFO)
  569. {
  570. dwValue = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset));
  571. }
  572. else if (pEntry->eADR == kADR_PPDDATA)
  573. {
  574. dwValue = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset));
  575. }
  576. else
  577. {
  578. //
  579. // This shouldn't happen. It's here to catch our coding error.
  580. //
  581. RIP(("HGetGADWord: unknown eADR %d\n", pEntry->eADR));
  582. return E_FAIL;
  583. }
  584. return HGetSingleData((PVOID)&dwValue, kADT_DWORD, sizeof(DWORD),
  585. pdwDataType, pbData, cbSize, pcbNeeded);
  586. }
  587. }
  588. //
  589. // can't find the attribute
  590. //
  591. // This shouldn't happen. It's here to catch our coding error.
  592. //
  593. RIP(("HGetGADWord: unknown attribute %s\n", pszAttribute));
  594. return E_INVALIDARG;
  595. }
  596. /*++
  597. Routine Name:
  598. HGetGAUnicode
  599. Routine Description:
  600. get global Unicode string attribute
  601. Arguments:
  602. pInfoHeader - pointer to driver's INFOHEADER structure
  603. dwFlags - flags for the attribute Get operation
  604. pszAttribute - name of the global attribute
  605. pdwDataType - pointer to DWORD to store output data type
  606. pbData - pointer to output data buffer
  607. cbSize - output data buffer size in bytes
  608. pcbNeeded - buffer size in bytes needed to store the output data
  609. Return Value:
  610. E_INVALIDARG if the global attribute is not recognized
  611. S_OK
  612. E_OUTOFMEMORY see function HGetSingleData
  613. Last Error:
  614. None
  615. --*/
  616. HRESULT
  617. HGetGAUnicode(
  618. IN PINFOHEADER pInfoHeader,
  619. IN DWORD dwFlags,
  620. IN PCSTR pszAttribute,
  621. OUT PDWORD pdwDataType,
  622. OUT PBYTE pbData,
  623. IN DWORD cbSize,
  624. OUT PDWORD pcbNeeded
  625. )
  626. {
  627. typedef struct _GA_UNICODE_ENTRY {
  628. PCSTR pszAttributeName; // attribute name
  629. EATTRIBUTE_DATAREGION eADR; // in UIINFO or PPDDATA
  630. DWORD cbOffset; // byte offset to DWORD specifying
  631. // offset to the UNICODE string
  632. } GA_UNICODE_ENTRY, *PGA_UNICODE_ENTRY;
  633. static const GA_UNICODE_ENTRY kGAUnicodeTable[] =
  634. {
  635. {kstrNickName, kADR_UIINFO, offsetof(UIINFO, loNickName)},
  636. };
  637. PUIINFO pUIInfo;
  638. PPPDDATA pPpdData;
  639. DWORD cIndex;
  640. DWORD cTableEntry = sizeof(kGAUnicodeTable) / sizeof(GA_UNICODE_ENTRY);
  641. PGA_UNICODE_ENTRY pEntry;
  642. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
  643. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
  644. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  645. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  646. if (pUIInfo == NULL || pPpdData == NULL)
  647. {
  648. return E_FAIL;
  649. }
  650. pEntry = (PGA_UNICODE_ENTRY)(&kGAUnicodeTable[0]);
  651. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  652. {
  653. if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
  654. (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
  655. {
  656. //
  657. // attribute name matches
  658. //
  659. PTSTR ptstrString;
  660. DWORD cbOffset;
  661. if (pEntry->eADR == kADR_UIINFO)
  662. {
  663. cbOffset = *((PDWORD)((PBYTE)pUIInfo + pEntry->cbOffset));
  664. }
  665. else if (pEntry->eADR == kADR_PPDDATA)
  666. {
  667. cbOffset = *((PDWORD)((PBYTE)pPpdData + pEntry->cbOffset));
  668. }
  669. else
  670. {
  671. //
  672. // This shouldn't happen. It's here to catch our coding error.
  673. //
  674. RIP(("HGetGAUnicode: unknown eADR %d\n", pEntry->eADR));
  675. return E_FAIL;
  676. }
  677. ptstrString = OFFSET_TO_POINTER(pInfoHeader, cbOffset);
  678. if (ptstrString == NULL)
  679. {
  680. return E_FAIL;
  681. }
  682. return HGetSingleData((PVOID)ptstrString, kADT_UNICODE, SIZE_OF_STRING(ptstrString),
  683. pdwDataType, pbData, cbSize, pcbNeeded);
  684. }
  685. }
  686. //
  687. // can't find the attribute
  688. //
  689. // This shouldn't happen. It's here to catch our coding error.
  690. //
  691. RIP(("HGetGAUnicode: unknown attribute %s\n", pszAttribute));
  692. return E_INVALIDARG;
  693. }
  694. /*++
  695. Routine Name:
  696. HGetGlobalAttribute
  697. Routine Description:
  698. get PPD global attribute
  699. Arguments:
  700. pInfoHeader - pointer to driver's INFOHEADER structure
  701. dwFlags - flags for the attribute get operation
  702. pszAttribute - name of the global attribute
  703. pdwDataType - pointer to DWORD to store output data type
  704. pbData - pointer to output data buffer
  705. cbSize - output data buffer size in bytes
  706. pcbNeeded - buffer size in bytes needed to store the output data
  707. Return Value:
  708. S_OK if succeeds
  709. E_OUTOFMEMORY if output data buffer size is not big enough
  710. E_INVALIDARG if the global attribute name is not recognized
  711. Last Error:
  712. None
  713. --*/
  714. HRESULT
  715. HGetGlobalAttribute(
  716. IN PINFOHEADER pInfoHeader,
  717. IN DWORD dwFlags,
  718. IN PCSTR pszAttribute,
  719. OUT PDWORD pdwDataType,
  720. OUT PBYTE pbData,
  721. IN DWORD cbSize,
  722. OUT PDWORD pcbNeeded
  723. )
  724. {
  725. typedef HRESULT (*_HGET_GA_PROC)(
  726. IN PINFOHEADER,
  727. IN DWORD,
  728. IN PCSTR,
  729. OUT PDWORD,
  730. OUT PBYTE,
  731. IN DWORD,
  732. OUT PDWORD);
  733. typedef struct _GA_PROCESS_ENTRY {
  734. PCSTR pszAttributeName; // attribute name
  735. _HGET_GA_PROC pfnGetGAProc; // attribute handling proc
  736. } GA_PROCESS_ENTRY, *PGA_PROCESS_ENTRY;
  737. static const GA_PROCESS_ENTRY kGAProcTable[] =
  738. {
  739. {kstrCenterReg, HGetGABool},
  740. {kstrColorDevice, HGetGABool},
  741. {kstrExtensions, HGetGAString},
  742. {kstrFileVersion, HGetGADWord},
  743. {kstrFreeVM, HGetGADWord},
  744. {kstrLSOrientation, HGetGAString},
  745. {kstrLangEncoding, HGetGAString},
  746. {kstrLangLevel, HGetGADWord},
  747. {kstrNickName, HGetGAUnicode},
  748. {kstrPPDAdobe, HGetGADWord},
  749. {kstrPrintError, HGetGABool},
  750. {kstrProduct, HGetGAInvocation},
  751. {kstrProtocols, HGetGAString},
  752. {kstrPSVersion, HGetGAInvocation},
  753. {kstrJobTimeout, HGetGADWord},
  754. {kstrWaitTimeout, HGetGADWord},
  755. {kstrThroughput, HGetGADWord},
  756. {kstrTTRasterizer, HGetGAString},
  757. };
  758. DWORD cIndex;
  759. DWORD cTableEntry = sizeof(kGAProcTable) / sizeof(GA_PROCESS_ENTRY);
  760. PGA_PROCESS_ENTRY pEntry;
  761. if (!pszAttribute)
  762. {
  763. //
  764. // Client is asking for the full list of supported global attribute names
  765. //
  766. PSTR pCurrentOut;
  767. DWORD cbNeeded;
  768. INT cbRemain;
  769. if (pdwDataType)
  770. {
  771. *pdwDataType = kADT_ASCII;
  772. }
  773. pCurrentOut = (PSTR)pbData;
  774. cbNeeded = 0;
  775. cbRemain = (INT)cbSize;
  776. pEntry = (PGA_PROCESS_ENTRY)(&kGAProcTable[0]);
  777. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  778. {
  779. DWORD cbNameSize;
  780. //
  781. // count in the NUL between attribute keywords
  782. //
  783. cbNameSize = strlen(pEntry->pszAttributeName) + 1;
  784. if (pCurrentOut && cbRemain >= (INT)cbNameSize)
  785. {
  786. CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize);
  787. pCurrentOut += cbNameSize;
  788. }
  789. cbRemain -= cbNameSize;
  790. cbNeeded += cbNameSize;
  791. }
  792. //
  793. // remember the last NUL terminator for the MULTI_SZ output string
  794. //
  795. cbRemain--;
  796. cbNeeded++;
  797. if (pcbNeeded)
  798. {
  799. *pcbNeeded = cbNeeded;
  800. }
  801. if (!pCurrentOut || cbRemain < 0)
  802. {
  803. return E_OUTOFMEMORY;
  804. }
  805. *pCurrentOut = NUL;
  806. return S_OK;
  807. }
  808. //
  809. // Client does provide the global attribute name
  810. //
  811. pEntry = (PGA_PROCESS_ENTRY)(&kGAProcTable[0]);
  812. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  813. {
  814. if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
  815. (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
  816. {
  817. //
  818. // attribute name matches
  819. //
  820. ASSERT(pEntry->pfnGetGAProc);
  821. return (pEntry->pfnGetGAProc)(pInfoHeader,
  822. dwFlags,
  823. pszAttribute,
  824. pdwDataType,
  825. pbData,
  826. cbSize,
  827. pcbNeeded);
  828. }
  829. }
  830. TERSE(("HGetGlobalAttribute: unknown global attribute %s\n", pszAttribute));
  831. return E_INVALIDARG;
  832. }
  833. /*++
  834. Routine Name:
  835. PGetOrderDepNode
  836. Routine Description:
  837. get the ORDERDEPEND strucutre associated with the specific feature/option
  838. Arguments:
  839. pInfoHeader - pointer to driver's INFOHEADER structure
  840. pPpdData - pointer to driver's PPDDATA structure
  841. dwFeatureIndex - feature index
  842. dwOptionIndex - option index (this could be OPTION_INDEX_ANY)
  843. Return Value:
  844. pointer to the ORDERDEPEND structure if succeeds
  845. NULL otherwise
  846. Last Error:
  847. None
  848. --*/
  849. PORDERDEPEND
  850. PGetOrderDepNode(
  851. IN PINFOHEADER pInfoHeader,
  852. IN PPPDDATA pPpdData,
  853. IN DWORD dwFeatureIndex,
  854. IN DWORD dwOptionIndex
  855. )
  856. {
  857. PORDERDEPEND pOrder;
  858. DWORD cIndex;
  859. pOrder = (PORDERDEPEND)OFFSET_TO_POINTER(&(pInfoHeader->RawData),
  860. pPpdData->OrderDeps.loOffset);
  861. ASSERT(pOrder != NULL || pPpdData->OrderDeps.dwCount == 0);
  862. if (pOrder == NULL)
  863. {
  864. return NULL;
  865. }
  866. for (cIndex = 0; cIndex < pPpdData->OrderDeps.dwCount; cIndex++, pOrder++)
  867. {
  868. if (pOrder->dwSection == SECTION_UNASSIGNED)
  869. continue;
  870. if (pOrder->dwFeatureIndex == dwFeatureIndex &&
  871. pOrder->dwOptionIndex == dwOptionIndex)
  872. {
  873. return pOrder;
  874. }
  875. }
  876. return NULL;
  877. }
  878. /*++
  879. Routine Name:
  880. HGetOrderDepSection
  881. Routine Description:
  882. get order dependency section name
  883. Arguments:
  884. pOrder - pointer to the ORDERDEPEND structure
  885. pdwDataType - pointer to DWORD to store output data type
  886. pbData - pointer to output data buffer
  887. cbSize - output data buffer size in bytes
  888. pcbNeeded - buffer size in bytes needed to store the output data
  889. Return Value:
  890. S_OK
  891. E_OUTOFMEMORY see function HGetSingleData
  892. Last Error:
  893. None
  894. --*/
  895. HRESULT
  896. HGetOrderDepSection(
  897. IN PORDERDEPEND pOrder,
  898. OUT PDWORD pdwDataType,
  899. OUT PBYTE pbData,
  900. IN DWORD cbSize,
  901. OUT PDWORD pcbNeeded
  902. )
  903. {
  904. static const CHAR kpstrSections[][20] =
  905. {
  906. "DocumentSetup",
  907. "PageSetup",
  908. "Prolog",
  909. "ExitServer",
  910. "JCLSetup",
  911. "AnySetup"
  912. };
  913. DWORD dwSectIndex;
  914. ASSERT(pOrder);
  915. switch (pOrder->dwPPDSection)
  916. {
  917. case SECTION_DOCSETUP:
  918. dwSectIndex = 0;
  919. break;
  920. case SECTION_PAGESETUP:
  921. dwSectIndex = 1;
  922. break;
  923. case SECTION_PROLOG:
  924. dwSectIndex = 2;
  925. break;
  926. case SECTION_EXITSERVER:
  927. dwSectIndex = 3;
  928. break;
  929. case SECTION_JCLSETUP:
  930. dwSectIndex = 4;
  931. break;
  932. case SECTION_ANYSETUP:
  933. default:
  934. dwSectIndex = 5;
  935. break;
  936. }
  937. return HGetSingleData((PVOID)kpstrSections[dwSectIndex], kADT_ASCII,
  938. strlen(kpstrSections[dwSectIndex]) + 1,
  939. pdwDataType, pbData, cbSize, pcbNeeded);
  940. }
  941. /*++
  942. Routine Name:
  943. HGetFeatureAttribute
  944. Routine Description:
  945. get PPD feature attribute
  946. Arguments:
  947. pInfoHeader - pointer to driver's INFOHEADER structure
  948. dwFlags - flags for the attribute get operation
  949. pszFeatureKeyword - PPD feature keyword name
  950. pszAttribute - name of the feature attribute
  951. pdwDataType - pointer to DWORD to store output data type
  952. pbData - pointer to output data buffer
  953. cbSize - output data buffer size in bytes
  954. pcbNeeded - buffer size in bytes needed to store the output data
  955. Return Value:
  956. S_OK if succeeds
  957. E_OUTOFMEMORY if output data buffer size is not big enough
  958. E_INVALIDARG if feature keyword name or attribute name is not recognized
  959. Last Error:
  960. None
  961. --*/
  962. HRESULT
  963. HGetFeatureAttribute(
  964. IN PINFOHEADER pInfoHeader,
  965. IN DWORD dwFlags,
  966. IN PCSTR pszFeatureKeyword,
  967. IN PCSTR pszAttribute,
  968. OUT PDWORD pdwDataType,
  969. OUT PBYTE pbData,
  970. IN DWORD cbSize,
  971. OUT PDWORD pcbNeeded
  972. )
  973. {
  974. typedef struct _FA_ENTRY {
  975. PCSTR pszAttributeName; // feature attribute name
  976. BOOL bNeedOrderDepNode; // TRUE if the attribute only exist
  977. // when the feature has an *OrderDependency
  978. // entry in PPD, FALSE otherwise.
  979. } FA_ENTRY, *PFA_ENTRY;
  980. static const FA_ENTRY kFATable[] =
  981. {
  982. {kstrDisplayName, FALSE},
  983. {kstrDefOption, FALSE},
  984. {kstrOpenUIType, FALSE},
  985. {kstrOpenGroupType, FALSE},
  986. {kstrOrderDepValue, TRUE},
  987. {kstrOrderDepSect, TRUE},
  988. };
  989. PUIINFO pUIInfo;
  990. PPPDDATA pPpdData;
  991. PFEATURE pFeature;
  992. PORDERDEPEND pOrder;
  993. DWORD dwFeatureIndex;
  994. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
  995. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
  996. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  997. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  998. if (pUIInfo == NULL || pPpdData == NULL)
  999. {
  1000. return E_FAIL;
  1001. }
  1002. if (!pszFeatureKeyword ||
  1003. (pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex)) == NULL)
  1004. {
  1005. ERR(("HGetFeatureAttribute: invalid feature\n"));
  1006. return E_INVALIDARG;
  1007. }
  1008. pOrder = PGetOrderDepNode(pInfoHeader, pPpdData, dwFeatureIndex, OPTION_INDEX_ANY);
  1009. if (!pszAttribute)
  1010. {
  1011. //
  1012. // Client is asking for the full list of supported feature attribute names
  1013. //
  1014. PFA_ENTRY pEntry;
  1015. DWORD cIndex;
  1016. DWORD cTableEntry = sizeof(kFATable) / sizeof(FA_ENTRY);
  1017. PSTR pCurrentOut;
  1018. DWORD cbNeeded;
  1019. INT cbRemain;
  1020. if (pdwDataType)
  1021. {
  1022. *pdwDataType = kADT_ASCII;
  1023. }
  1024. pCurrentOut = (PSTR)pbData;
  1025. cbNeeded = 0;
  1026. cbRemain = (INT)cbSize;
  1027. pEntry = (PFA_ENTRY)(&kFATable[0]);
  1028. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  1029. {
  1030. DWORD cbNameSize;
  1031. //
  1032. // If the attribute only exist when the feature has an *OrderDependency entry in PPD,
  1033. // but we didn't find the feature's pOrder node, skip it.
  1034. //
  1035. if (pEntry->bNeedOrderDepNode && !pOrder)
  1036. continue;
  1037. //
  1038. // count in the NUL between attribute keywords
  1039. //
  1040. cbNameSize = strlen(pEntry->pszAttributeName) + 1;
  1041. if (pCurrentOut && cbRemain >= (INT)cbNameSize)
  1042. {
  1043. CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize);
  1044. pCurrentOut += cbNameSize;
  1045. }
  1046. cbRemain -= cbNameSize;
  1047. cbNeeded += cbNameSize;
  1048. }
  1049. //
  1050. // remember the last NUL terminator for the MULTI_SZ output string
  1051. //
  1052. cbRemain--;
  1053. cbNeeded++;
  1054. if (pcbNeeded)
  1055. {
  1056. *pcbNeeded = cbNeeded;
  1057. }
  1058. if (!pCurrentOut || cbRemain < 0)
  1059. {
  1060. return E_OUTOFMEMORY;
  1061. }
  1062. *pCurrentOut = NUL;
  1063. return S_OK;
  1064. }
  1065. //
  1066. // Client does provide the feature attribute name
  1067. //
  1068. if ((*pszAttribute == kstrDisplayName[0]) &&
  1069. (strcmp(pszAttribute, kstrDisplayName) == EQUAL_STRING))
  1070. {
  1071. PTSTR ptstrDispName;
  1072. ptstrDispName = OFFSET_TO_POINTER(pInfoHeader, pFeature->loDisplayName);
  1073. if (ptstrDispName == NULL)
  1074. {
  1075. return E_FAIL;
  1076. }
  1077. return HGetSingleData((PVOID)ptstrDispName, kADT_UNICODE, SIZE_OF_STRING(ptstrDispName),
  1078. pdwDataType, pbData, cbSize, pcbNeeded);
  1079. }
  1080. else if ((*pszAttribute == kstrDefOption[0]) &&
  1081. (strcmp(pszAttribute, kstrDefOption) == EQUAL_STRING))
  1082. {
  1083. POPTION pOption;
  1084. PSTR pstrKeywordName;
  1085. pOption = PGetIndexedOption(pUIInfo, pFeature, pFeature->dwDefaultOptIndex);
  1086. if (!pOption)
  1087. {
  1088. ERR(("HGetFeatureAttribute: can't find default option. Use the first one.\n"));
  1089. pOption = PGetIndexedOption(pUIInfo, pFeature, 0);
  1090. if (!pOption)
  1091. {
  1092. return E_FAIL;
  1093. }
  1094. }
  1095. pstrKeywordName = OFFSET_TO_POINTER(pInfoHeader, pOption->loKeywordName);
  1096. return HGetSingleData((PVOID)pstrKeywordName, kADT_ASCII, strlen(pstrKeywordName) + 1,
  1097. pdwDataType, pbData, cbSize, pcbNeeded);
  1098. }
  1099. else if ((*pszAttribute == kstrOpenUIType[0]) &&
  1100. (strcmp(pszAttribute, kstrOpenUIType) == EQUAL_STRING))
  1101. {
  1102. static const CHAR pstrUITypes[][10] =
  1103. {
  1104. "PickOne",
  1105. "PickMany",
  1106. "Boolean"
  1107. };
  1108. DWORD dwType = pFeature->dwUIType;
  1109. if (dwType > UITYPE_BOOLEAN)
  1110. {
  1111. RIP(("HGetFeatureAttribute: invalid UIType %d\n", dwType));
  1112. dwType = 0;
  1113. }
  1114. return HGetSingleData((PVOID)pstrUITypes[dwType], kADT_ASCII,
  1115. strlen(pstrUITypes[dwType]) + 1,
  1116. pdwDataType, pbData, cbSize, pcbNeeded);
  1117. }
  1118. else if ((*pszAttribute == kstrOpenGroupType[0]) &&
  1119. (strcmp(pszAttribute, kstrOpenGroupType) == EQUAL_STRING))
  1120. {
  1121. static const CHAR pstrGroupTypes[][30] =
  1122. {
  1123. "InstallableOptions",
  1124. ""
  1125. };
  1126. DWORD dwType;
  1127. dwType = (pFeature->dwFeatureType == FEATURETYPE_PRINTERPROPERTY) ? 0 : 1;
  1128. return HGetSingleData((PVOID)pstrGroupTypes[dwType], kADT_ASCII,
  1129. strlen(pstrGroupTypes[dwType]) + 1,
  1130. pdwDataType, pbData, cbSize, pcbNeeded);
  1131. }
  1132. else if ((*pszAttribute == kstrOrderDepValue[0]) &&
  1133. (strcmp(pszAttribute, kstrOrderDepValue) == EQUAL_STRING))
  1134. {
  1135. if (!pOrder)
  1136. {
  1137. TERSE(("HGetFeatureAttribute: attribute %s not available\n", pszAttribute));
  1138. return E_INVALIDARG;
  1139. }
  1140. return HGetSingleData((PVOID)&(pOrder->lOrder), kADT_LONG, sizeof(LONG),
  1141. pdwDataType, pbData, cbSize, pcbNeeded);
  1142. }
  1143. else if ((*pszAttribute == kstrOrderDepSect[0]) &&
  1144. (strcmp(pszAttribute, kstrOrderDepSect) == EQUAL_STRING))
  1145. {
  1146. if (!pOrder)
  1147. {
  1148. TERSE(("HGetFeatureAttribute: attribute %s not available\n", pszAttribute));
  1149. return E_INVALIDARG;
  1150. }
  1151. return HGetOrderDepSection(pOrder, pdwDataType, pbData, cbSize, pcbNeeded);
  1152. }
  1153. else
  1154. {
  1155. TERSE(("HGetFeatureAttribute: unknown feature attribute %s\n", pszAttribute));
  1156. return E_INVALIDARG;
  1157. }
  1158. }
  1159. /*++
  1160. Routine Name:
  1161. HGetOptionAttribute
  1162. Routine Description:
  1163. get option attribute of a PPD feature
  1164. Arguments:
  1165. pInfoHeader - pointer to driver's INFOHEADER structure
  1166. dwFlags - flags for the attribute get operation
  1167. pszFeatureKeyword - PPD feature keyword name
  1168. pszOptionKeyword - option keyword name of the PPD feature
  1169. pszAttribute - name of the feature attribute
  1170. pdwDataType - pointer to DWORD to store output data type
  1171. pbData - pointer to output data buffer
  1172. cbSize - output data buffer size in bytes
  1173. pcbNeeded - buffer size in bytes needed to store the output data
  1174. Return Value:
  1175. S_OK if succeeds
  1176. E_OUTOFMEMORY if output data buffer size is not big enough
  1177. E_INVALIDARG if feature keyword name, or option keyword name,
  1178. or attribute name is not recognized
  1179. Last Error:
  1180. None
  1181. --*/
  1182. HRESULT
  1183. HGetOptionAttribute(
  1184. IN PINFOHEADER pInfoHeader,
  1185. IN DWORD dwFlags,
  1186. IN PCSTR pszFeatureKeyword,
  1187. IN PCSTR pszOptionKeyword,
  1188. IN PCSTR pszAttribute,
  1189. OUT PDWORD pdwDataType,
  1190. OUT PBYTE pbData,
  1191. IN DWORD cbSize,
  1192. OUT PDWORD pcbNeeded
  1193. )
  1194. {
  1195. typedef struct _OA_ENTRY {
  1196. PCSTR pszFeatureKeyword; // feature keyword name
  1197. // (NULL for non-feature specific attributes)
  1198. PCSTR pszOptionKeyword; // option keyword name
  1199. // (NULL for non-option specific attributes)
  1200. PCSTR pszAttributeName; // option attribute name (this field must be
  1201. // unique across the table)
  1202. BOOL bNeedOrderDepNode; // TRUE if the attribute only exist
  1203. // when the option has an *OrderDependency
  1204. // entry in PPD, FALSE otherwise.
  1205. BOOL bSpecialHandle; // TRUE if the attribute needs special handling.
  1206. // If TRUE, following table fields are not used.
  1207. DWORD dwDataType; // data type of the attribute value
  1208. DWORD cbNeeded; // byte count of the attribute value
  1209. DWORD cbOffset; // byte offset to the attribute value, starting
  1210. // from the beginning of OPTION structure
  1211. } OA_ENTRY, *POA_ENTRY;
  1212. static const OA_ENTRY kOATable[] =
  1213. {
  1214. {NULL, NULL, kstrDisplayName, FALSE, TRUE, 0, 0, 0},
  1215. {NULL, NULL, kstrInvocation, FALSE, TRUE, 0, 0, 0},
  1216. {NULL, NULL, kstrOrderDepValue, TRUE, TRUE, 0, 0, 0},
  1217. {NULL, NULL, kstrOrderDepSect, TRUE, TRUE, 0, 0, 0},
  1218. {kstrInputSlot, NULL, kstrReqPageRgn, FALSE, TRUE, 0, 0, 0},
  1219. {kstrOutputBin, NULL, kstrOutOrderRev, FALSE, FALSE, kADT_BOOL, sizeof(BOOL), offsetof(OUTPUTBIN, bOutputOrderReversed)},
  1220. {kstrPageSize, NULL, kstrPaperDim, FALSE, FALSE, kADT_SIZE, sizeof(SIZE), offsetof(PAGESIZE, szPaperSize)},
  1221. {kstrPageSize, NULL, kstrImgArea, FALSE, TRUE, 0, 0, 0},
  1222. {kstrPageSize, kstrCustomPS, kstrParamCustomPS, FALSE, TRUE, 0, 0, 0},
  1223. {kstrPageSize, kstrCustomPS, kstrHWMargins, FALSE, FALSE, kADT_RECT, sizeof(RECT), offsetof(PAGESIZE, rcImgArea)},
  1224. {kstrPageSize, kstrCustomPS, kstrMaxMWidth, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(PAGESIZE, szPaperSize) + offsetof(SIZE, cx)},
  1225. {kstrPageSize, kstrCustomPS, kstrMaxMHeight, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(PAGESIZE, szPaperSize) + offsetof(SIZE, cy)},
  1226. {kstrInstalledMem, NULL, kstrVMOption, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(MEMOPTION, dwInstalledMem)},
  1227. {kstrInstalledMem, NULL, kstrFCacheSize, FALSE, FALSE, kADT_DWORD, sizeof(DWORD), offsetof(MEMOPTION, dwFreeFontMem)},
  1228. };
  1229. PUIINFO pUIInfo;
  1230. PPPDDATA pPpdData;
  1231. PFEATURE pFeature;
  1232. POPTION pOption;
  1233. PORDERDEPEND pOrder;
  1234. DWORD dwFeatureIndex, dwOptionIndex, cIndex;
  1235. DWORD cTableEntry = sizeof(kOATable) / sizeof(OA_ENTRY);
  1236. POA_ENTRY pEntry;
  1237. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
  1238. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
  1239. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  1240. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  1241. if (pUIInfo == NULL || pPpdData == NULL)
  1242. {
  1243. return E_FAIL;
  1244. }
  1245. if (!pszFeatureKeyword ||
  1246. (pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex)) == NULL)
  1247. {
  1248. ERR(("HGetOptionAttribute: invalid feature\n"));
  1249. return E_INVALIDARG;
  1250. }
  1251. if (!pszOptionKeyword ||
  1252. (pOption = PGetNamedOption(pUIInfo, pFeature, pszOptionKeyword, &dwOptionIndex)) == NULL)
  1253. {
  1254. ERR(("HGetOptionAttribute: invalid option\n"));
  1255. return E_INVALIDARG;
  1256. }
  1257. pOrder = PGetOrderDepNode(pInfoHeader, pPpdData, dwFeatureIndex, dwOptionIndex);
  1258. if (!pszAttribute)
  1259. {
  1260. //
  1261. // Client is asking for the full list of supported option attribute names
  1262. //
  1263. PSTR pCurrentOut;
  1264. DWORD cbNeeded;
  1265. INT cbRemain;
  1266. if (pdwDataType)
  1267. {
  1268. *pdwDataType = kADT_ASCII;
  1269. }
  1270. pCurrentOut = (PSTR)pbData;
  1271. cbNeeded = 0;
  1272. cbRemain = (INT)cbSize;
  1273. pEntry = (POA_ENTRY)(&kOATable[0]);
  1274. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  1275. {
  1276. DWORD cbNameSize;
  1277. //
  1278. // If the attribute is specific to a certain feature, check the feature keyword match.
  1279. //
  1280. if (pEntry->pszFeatureKeyword &&
  1281. (strcmp(pEntry->pszFeatureKeyword, pszFeatureKeyword) != EQUAL_STRING))
  1282. continue;
  1283. //
  1284. // If the attribute is specific to a certain option, check the option keyword match.
  1285. //
  1286. if (pEntry->pszOptionKeyword &&
  1287. (strcmp(pEntry->pszOptionKeyword, pszOptionKeyword) != EQUAL_STRING))
  1288. continue;
  1289. //
  1290. // special case: For PageSize's CustomPageSize option, we need to skip attributes
  1291. // that are only available to PageSize's all non-CustomPageSize options.
  1292. //
  1293. if (pEntry->pszFeatureKeyword &&
  1294. !pEntry->pszOptionKeyword &&
  1295. (pFeature->dwFeatureID == GID_PAGESIZE) &&
  1296. (((PPAGESIZE)pOption)->dwPaperSizeID == DMPAPER_CUSTOMSIZE))
  1297. continue;
  1298. //
  1299. // If the attribute only exist when the option has an *OrderDependency entry in PPD,
  1300. // but we didn't find the option's pOrder node, skip it.
  1301. //
  1302. if (pEntry->bNeedOrderDepNode && !pOrder)
  1303. continue;
  1304. //
  1305. // count in the NUL between attribute keywords
  1306. //
  1307. cbNameSize = strlen(pEntry->pszAttributeName) + 1;
  1308. if (pCurrentOut && cbRemain >= (INT)cbNameSize)
  1309. {
  1310. CopyMemory(pCurrentOut, pEntry->pszAttributeName, cbNameSize);
  1311. pCurrentOut += cbNameSize;
  1312. }
  1313. cbRemain -= cbNameSize;
  1314. cbNeeded += cbNameSize;
  1315. }
  1316. //
  1317. // remember the last NUL terminator for the MULTI_SZ output string.
  1318. //
  1319. cbRemain--;
  1320. cbNeeded++;
  1321. if (pcbNeeded)
  1322. {
  1323. *pcbNeeded = cbNeeded;
  1324. }
  1325. if (!pCurrentOut || cbRemain < 0)
  1326. {
  1327. return E_OUTOFMEMORY;
  1328. }
  1329. *pCurrentOut = NUL;
  1330. return S_OK;
  1331. }
  1332. //
  1333. // Client does provide the option attribute name
  1334. //
  1335. //
  1336. // First handle a few special cases (bSpecialHandle == TRUE in the table).
  1337. // Generic case handling is in the last else-part.
  1338. //
  1339. if ((*pszAttribute == kstrDisplayName[0]) &&
  1340. (strcmp(pszAttribute, kstrDisplayName) == EQUAL_STRING))
  1341. {
  1342. //
  1343. // "DisplayName"
  1344. //
  1345. PTSTR ptstrDispName;
  1346. ptstrDispName = OFFSET_TO_POINTER(pInfoHeader, pOption->loDisplayName);
  1347. if (ptstrDispName == NULL)
  1348. {
  1349. return E_FAIL;
  1350. }
  1351. return HGetSingleData((PVOID)ptstrDispName, kADT_UNICODE, SIZE_OF_STRING(ptstrDispName),
  1352. pdwDataType, pbData, cbSize, pcbNeeded);
  1353. }
  1354. else if ((*pszAttribute == kstrInvocation[0]) &&
  1355. (strcmp(pszAttribute, kstrInvocation) == EQUAL_STRING))
  1356. {
  1357. //
  1358. // "Invocation"
  1359. //
  1360. return HGetSingleData(OFFSET_TO_POINTER(pInfoHeader, pOption->Invocation.loOffset),
  1361. kADT_BINARY, pOption->Invocation.dwCount,
  1362. pdwDataType, pbData, cbSize, pcbNeeded);
  1363. }
  1364. else if ((*pszAttribute == kstrOrderDepValue[0]) &&
  1365. (strcmp(pszAttribute, kstrOrderDepValue) == EQUAL_STRING))
  1366. {
  1367. //
  1368. // "OrderDependencyValue"
  1369. //
  1370. if (!pOrder)
  1371. {
  1372. TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
  1373. return E_INVALIDARG;
  1374. }
  1375. return HGetSingleData((PVOID)&(pOrder->lOrder), kADT_LONG, sizeof(LONG),
  1376. pdwDataType, pbData, cbSize, pcbNeeded);
  1377. }
  1378. else if ((*pszAttribute == kstrOrderDepSect[0]) &&
  1379. (strcmp(pszAttribute, kstrOrderDepSect) == EQUAL_STRING))
  1380. {
  1381. //
  1382. // "OrderDependencySection"
  1383. //
  1384. if (!pOrder)
  1385. {
  1386. TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
  1387. return E_INVALIDARG;
  1388. }
  1389. return HGetOrderDepSection(pOrder, pdwDataType, pbData, cbSize, pcbNeeded);
  1390. }
  1391. else if ((*pszAttribute == kstrReqPageRgn[0]) &&
  1392. (strcmp(pszAttribute, kstrReqPageRgn) == EQUAL_STRING))
  1393. {
  1394. //
  1395. // "RequiresPageRegion"
  1396. //
  1397. PINPUTSLOT pInputSlot = (PINPUTSLOT)pOption;
  1398. BOOL bValue;
  1399. //
  1400. // This attribute is only available to *InputSlot options, excluding the first
  1401. // one "*UseFormTrayTable", which is synthesized by PPD parser.
  1402. //
  1403. if (pFeature->dwFeatureID != GID_INPUTSLOT ||
  1404. (dwOptionIndex == 0 && pInputSlot->dwPaperSourceID == DMBIN_FORMSOURCE))
  1405. {
  1406. TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
  1407. return E_INVALIDARG;
  1408. }
  1409. bValue = (pInputSlot->dwFlags & INPUTSLOT_REQ_PAGERGN) ? TRUE : FALSE;
  1410. return HGetSingleData((PVOID)&bValue, kADT_BOOL, sizeof(BOOL),
  1411. pdwDataType, pbData, cbSize, pcbNeeded);
  1412. }
  1413. else if ((*pszAttribute == kstrImgArea[0]) &&
  1414. (strcmp(pszAttribute, kstrImgArea) == EQUAL_STRING))
  1415. {
  1416. //
  1417. // "ImageableArea"
  1418. //
  1419. PPAGESIZE pPageSize = (PPAGESIZE)pOption;
  1420. RECT rcImgArea;
  1421. //
  1422. // This attribute is only available to *PageSize options, excluding CustomPageSize option.
  1423. //
  1424. if (pFeature->dwFeatureID != GID_PAGESIZE || pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE)
  1425. {
  1426. TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
  1427. return E_INVALIDARG;
  1428. }
  1429. //
  1430. // convert GDI coordinate system back to PS coordinate system
  1431. // (see VPackPrinterFeatures() case GID_PAGESIZE)
  1432. //
  1433. rcImgArea.left = pPageSize->rcImgArea.left;
  1434. rcImgArea.right = pPageSize->rcImgArea.right;
  1435. rcImgArea.top = pPageSize->szPaperSize.cy - pPageSize->rcImgArea.top;
  1436. rcImgArea.bottom = pPageSize->szPaperSize.cy - pPageSize->rcImgArea.bottom;
  1437. return HGetSingleData((PVOID)&rcImgArea, kADT_RECT, sizeof(RECT),
  1438. pdwDataType, pbData, cbSize, pcbNeeded);
  1439. }
  1440. else if ((*pszAttribute == kstrParamCustomPS[0]) &&
  1441. (strcmp(pszAttribute, kstrParamCustomPS) == EQUAL_STRING))
  1442. {
  1443. //
  1444. // "ParamCustomPageSize"
  1445. //
  1446. PPAGESIZE pPageSize = (PPAGESIZE)pOption;
  1447. //
  1448. // This attribute is only available to *PageSize feature's CustomPageSize option.
  1449. //
  1450. if (pFeature->dwFeatureID != GID_PAGESIZE || pPageSize->dwPaperSizeID != DMPAPER_CUSTOMSIZE)
  1451. {
  1452. TERSE(("HGetOptionAttribute: attribute %s not available\n", pszAttribute));
  1453. return E_INVALIDARG;
  1454. }
  1455. return HGetSingleData((PVOID)(pPpdData->CustomSizeParams),
  1456. kADT_CUSTOMSIZEPARAMS, sizeof(pPpdData->CustomSizeParams),
  1457. pdwDataType, pbData, cbSize, pcbNeeded);
  1458. }
  1459. else
  1460. {
  1461. //
  1462. // generic case handling
  1463. //
  1464. pEntry = (POA_ENTRY)(&kOATable[0]);
  1465. for (cIndex = 0; cIndex < cTableEntry; cIndex++, pEntry++)
  1466. {
  1467. //
  1468. // skip any entry that has already been specially handled
  1469. //
  1470. if (pEntry->bSpecialHandle)
  1471. continue;
  1472. ASSERT(pEntry->bNeedOrderDepNode == FALSE);
  1473. if ((*pszAttribute == *(pEntry->pszAttributeName)) &&
  1474. (strcmp(pszAttribute, pEntry->pszAttributeName) == EQUAL_STRING))
  1475. {
  1476. //
  1477. // Attribute name matches. We still need to verify feature/option keyword match.
  1478. //
  1479. if (pEntry->pszFeatureKeyword &&
  1480. strcmp(pEntry->pszFeatureKeyword, pszFeatureKeyword) != EQUAL_STRING)
  1481. {
  1482. TERSE(("HGetOptionAttribute: feature keyword mismatch for attribute %s\n", pszAttribute));
  1483. return E_INVALIDARG;
  1484. }
  1485. if (pEntry->pszOptionKeyword &&
  1486. (strcmp(pEntry->pszOptionKeyword, pszOptionKeyword) != EQUAL_STRING))
  1487. {
  1488. TERSE(("HGetOptionAttribute: option keyword mismatch for attribute %s\n", pszAttribute));
  1489. return E_INVALIDARG;
  1490. }
  1491. //
  1492. // special case: For PageSize's CustomPageSize option, we need to skip attributes
  1493. // that are only available to PageSize's all non-CustomPageSize options.
  1494. //
  1495. if (pEntry->pszFeatureKeyword &&
  1496. !pEntry->pszOptionKeyword &&
  1497. (pFeature->dwFeatureID == GID_PAGESIZE) &&
  1498. (((PPAGESIZE)pOption)->dwPaperSizeID == DMPAPER_CUSTOMSIZE))
  1499. continue;
  1500. return HGetSingleData((PVOID)((PBYTE)pOption + pEntry->cbOffset),
  1501. pEntry->dwDataType, pEntry->cbNeeded,
  1502. pdwDataType, pbData, cbSize, pcbNeeded);
  1503. }
  1504. }
  1505. TERSE(("HGetOptionAttribute: unknown option attribute %s\n", pszAttribute));
  1506. return E_INVALIDARG;
  1507. }
  1508. }
  1509. /*++
  1510. Routine Name:
  1511. BIsSupported_PSF
  1512. Routine Description:
  1513. determine if the PS driver synthesized feature is supported or not
  1514. Arguments:
  1515. pszFeature - name of the PS driver synthesized feature
  1516. pUIInfo - pointer to driver's UIINFO structure
  1517. pPpdData - pointer to driver's PPDDATA structure
  1518. bEMFSpooling - whether spooler EMF spooling is enabled or not
  1519. Return Value:
  1520. TRUE if the feature is currently supported
  1521. FALSE otherwise
  1522. Last Error:
  1523. None
  1524. --*/
  1525. BOOL
  1526. BIsSupported_PSF(
  1527. IN PCSTR pszFeature,
  1528. IN PUIINFO pUIInfo,
  1529. IN PPPDDATA pPpdData,
  1530. IN BOOL bEMFSpooling
  1531. )
  1532. {
  1533. #ifdef WINNT_40
  1534. //
  1535. // On NT4, bEMFSpooling should always be FALSE.
  1536. //
  1537. ASSERT(!bEMFSpooling);
  1538. #endif // WINNT_40
  1539. //
  1540. // Note that the first character is always the % prefix.
  1541. //
  1542. if ((pszFeature[1] == kstrPSFAddEuro[1]) &&
  1543. (strcmp(pszFeature, kstrPSFAddEuro) == EQUAL_STRING))
  1544. {
  1545. //
  1546. // AddEuro is only supported for Level 2+ printers.
  1547. //
  1548. return(pUIInfo->dwLangLevel >= 2);
  1549. }
  1550. else if ((pszFeature[1] == kstrPSFEMF[1]) &&
  1551. (strcmp(pszFeature, kstrPSFEMF) == EQUAL_STRING))
  1552. {
  1553. //
  1554. // Driver EMF is always supported on NT4, and only supported
  1555. // when spooler EMF is enabled on Win2K+.
  1556. //
  1557. #ifndef WINNT_40
  1558. return bEMFSpooling;
  1559. #else
  1560. return TRUE;
  1561. #endif // !WINNT_40
  1562. }
  1563. else if ((pszFeature[1] == kstrPSFNegative[1]) &&
  1564. (strcmp(pszFeature, kstrPSFNegative) == EQUAL_STRING))
  1565. {
  1566. //
  1567. // Negative is only supported for b/w printers.
  1568. //
  1569. return(IS_COLOR_DEVICE(pUIInfo) ? FALSE : TRUE);
  1570. }
  1571. else if ((pszFeature[1] == kstrPSFPageOrder[1]) &&
  1572. (strcmp(pszFeature, kstrPSFPageOrder) == EQUAL_STRING))
  1573. {
  1574. //
  1575. // PageOrder is not supported on NT4, and is only supported
  1576. // when spooler EMF is enabled on Win2K+.
  1577. //
  1578. return bEMFSpooling;
  1579. }
  1580. else
  1581. {
  1582. return TRUE;
  1583. }
  1584. }
  1585. /*++
  1586. Routine Name:
  1587. HEnumFeaturesOrOptions
  1588. Routine Description:
  1589. enumerate the feature or option keyword name list
  1590. Arguments:
  1591. hPrinter - printer handle
  1592. pInfoHeader - pointer to driver's INFOHEADER structure
  1593. dwFlags - flags for the enumeration operation
  1594. pszFeatureKeyword - feature keyword name. This should be NULL
  1595. for feature enumeration and non-NULL for
  1596. option enumeration.
  1597. pmszOutputList - pointer to output data buffer
  1598. cbSize - output data buffer size in bytes
  1599. pcbNeeded - buffer size in bytes needed to store the output data
  1600. Return Value:
  1601. S_OK if succeeds
  1602. E_OUTOFMEMORY if output data buffer size is not big enough
  1603. E_INVALIDARG if for option enumeration, feature keyword name is
  1604. not recognized
  1605. E_NOTIMPL if being called to enumerate options of PS driver
  1606. synthesized feature that is not currently supported or
  1607. whose options are not enumerable
  1608. E_FAIL if other internal failures are encountered
  1609. Last Error:
  1610. None
  1611. --*/
  1612. HRESULT
  1613. HEnumFeaturesOrOptions(
  1614. IN HANDLE hPrinter,
  1615. IN PINFOHEADER pInfoHeader,
  1616. IN DWORD dwFlags,
  1617. IN PCSTR pszFeatureKeyword,
  1618. OUT PSTR pmszOutputList,
  1619. IN DWORD cbSize,
  1620. OUT PDWORD pcbNeeded
  1621. )
  1622. {
  1623. PUIINFO pUIInfo;
  1624. PPPDDATA pPpdData;
  1625. PFEATURE pFeature;
  1626. POPTION pOption;
  1627. DWORD cIndex, cPPDFeaturesOrOptions;
  1628. BOOL bEnumFeatures, bEnumPPDOptions;
  1629. PSTR pCurrentOut;
  1630. DWORD cbNeeded;
  1631. INT cbRemain;
  1632. BOOL bEMFSpooling;
  1633. PPSFEATURE_ENTRY pEntry;
  1634. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHeader);
  1635. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHeader);
  1636. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  1637. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  1638. if (pUIInfo == NULL || pPpdData == NULL)
  1639. {
  1640. return E_FAIL;
  1641. }
  1642. pCurrentOut = pmszOutputList;
  1643. cbNeeded = 0;
  1644. cbRemain = (INT)cbSize;
  1645. bEnumFeatures = pszFeatureKeyword ? FALSE : TRUE;
  1646. bEnumPPDOptions = TRUE;
  1647. if (bEnumFeatures)
  1648. {
  1649. //
  1650. // Enumerate driver synthersized features first.
  1651. //
  1652. VGetSpoolerEmfCaps(hPrinter, NULL, &bEMFSpooling, 0, NULL);
  1653. pEntry = (PPSFEATURE_ENTRY)(&kPSFeatureTable[0]);
  1654. while (pEntry->pszPSFeatureName)
  1655. {
  1656. if (BIsSupported_PSF(pEntry->pszPSFeatureName, pUIInfo, pPpdData, bEMFSpooling))
  1657. {
  1658. DWORD cbNameLen;
  1659. cbNameLen = strlen(pEntry->pszPSFeatureName) + 1;
  1660. if (pCurrentOut && cbRemain >= (INT)cbNameLen)
  1661. {
  1662. CopyMemory(pCurrentOut, pEntry->pszPSFeatureName, cbNameLen);
  1663. pCurrentOut += cbNameLen;
  1664. }
  1665. cbRemain -= cbNameLen;
  1666. cbNeeded += cbNameLen;
  1667. }
  1668. pEntry++;
  1669. }
  1670. }
  1671. else
  1672. {
  1673. if (*pszFeatureKeyword == PSFEATURE_PREFIX)
  1674. {
  1675. bEnumPPDOptions = FALSE;
  1676. VGetSpoolerEmfCaps(hPrinter, NULL, &bEMFSpooling, 0, NULL);
  1677. if (!BIsSupported_PSF(pszFeatureKeyword, pUIInfo, pPpdData, bEMFSpooling))
  1678. {
  1679. WARNING(("HEnumFeaturesOrOptions: feature %s is not supported\n", pszFeatureKeyword));
  1680. return E_NOTIMPL;
  1681. }
  1682. }
  1683. }
  1684. if (bEnumFeatures)
  1685. {
  1686. cPPDFeaturesOrOptions = pUIInfo->dwDocumentFeatures + pUIInfo->dwPrinterFeatures;
  1687. pFeature = OFFSET_TO_POINTER(pInfoHeader, pUIInfo->loFeatureList);
  1688. ASSERT(cPPDFeaturesOrOptions == 0 || pFeature != NULL);
  1689. if (pFeature == NULL)
  1690. {
  1691. return E_FAIL;
  1692. }
  1693. }
  1694. else if (bEnumPPDOptions)
  1695. {
  1696. DWORD dwFeatureIndex;
  1697. pFeature = PGetNamedFeature(pUIInfo, pszFeatureKeyword, &dwFeatureIndex);
  1698. if (!pFeature)
  1699. {
  1700. ERR(("HEnumFeaturesOrOptions: unrecognized feature %s\n", pszFeatureKeyword));
  1701. return E_INVALIDARG;
  1702. }
  1703. cPPDFeaturesOrOptions = pFeature->Options.dwCount;
  1704. pOption = OFFSET_TO_POINTER(pInfoHeader, pFeature->Options.loOffset);
  1705. ASSERT(cPPDFeaturesOrOptions == 0 || pOption != NULL);
  1706. if (pOption == NULL)
  1707. {
  1708. return E_FAIL;
  1709. }
  1710. }
  1711. else
  1712. {
  1713. //
  1714. // Enum driver synthersized feature's options.
  1715. //
  1716. pEntry = (PPSFEATURE_ENTRY)(&kPSFeatureTable[0]);
  1717. while (pEntry->pszPSFeatureName)
  1718. {
  1719. if ((*pszFeatureKeyword == *(pEntry->pszPSFeatureName)) &&
  1720. strcmp(pszFeatureKeyword, pEntry->pszPSFeatureName) == EQUAL_STRING)
  1721. {
  1722. if (!pEntry->bEnumerableOptions)
  1723. {
  1724. //
  1725. // This driver feature doesn't support option enumeration.
  1726. //
  1727. WARNING(("HEnumFeaturesOrOptions: enum options not supported for %s\n", pszFeatureKeyword));
  1728. return E_NOTIMPL;
  1729. }
  1730. if (pEntry->bBooleanOptions)
  1731. {
  1732. //
  1733. // This driver feature has True/False boolean options.
  1734. //
  1735. DWORD cbKwdTrueSize, cbKwdFalseSize;
  1736. cbKwdTrueSize = strlen(kstrKwdTrue) + 1;
  1737. cbKwdFalseSize = strlen(kstrKwdFalse) + 1;
  1738. if (pCurrentOut && (cbRemain >= (INT)(cbKwdTrueSize + cbKwdFalseSize)))
  1739. {
  1740. CopyMemory(pCurrentOut, kstrKwdTrue, cbKwdTrueSize);
  1741. pCurrentOut += cbKwdTrueSize;
  1742. CopyMemory(pCurrentOut, kstrKwdFalse, cbKwdFalseSize);
  1743. pCurrentOut += cbKwdFalseSize;
  1744. }
  1745. cbRemain -= (cbKwdTrueSize + cbKwdFalseSize);
  1746. cbNeeded += cbKwdTrueSize + cbKwdFalseSize;
  1747. }
  1748. else
  1749. {
  1750. //
  1751. // This driver feature needs special handler to enumerate its options.
  1752. //
  1753. if (pEntry->pfnPSProc)
  1754. {
  1755. DWORD cbPSFOptionsSize;
  1756. BOOL bResult;
  1757. bResult = (pEntry->pfnPSProc)(hPrinter,
  1758. pUIInfo,
  1759. pPpdData,
  1760. NULL,
  1761. NULL,
  1762. pszFeatureKeyword,
  1763. NULL,
  1764. pCurrentOut,
  1765. cbRemain,
  1766. &cbPSFOptionsSize,
  1767. PSFPROC_ENUMOPTION_MODE);
  1768. if (bResult)
  1769. {
  1770. pCurrentOut += cbPSFOptionsSize;
  1771. }
  1772. else
  1773. {
  1774. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  1775. {
  1776. ERR(("HEnumFeaturesOrOptions: enum options failed for %s\n", pszFeatureKeyword));
  1777. return E_FAIL;
  1778. }
  1779. }
  1780. cbRemain -= cbPSFOptionsSize;
  1781. cbNeeded += cbPSFOptionsSize;
  1782. }
  1783. else
  1784. {
  1785. RIP(("HEnumFeaturesOrOptions: %%-feature handle is NULL for %s\n", pszFeatureKeyword));
  1786. return E_FAIL;
  1787. }
  1788. }
  1789. break;
  1790. }
  1791. pEntry++;
  1792. }
  1793. if (pEntry->pszPSFeatureName == NULL)
  1794. {
  1795. ERR(("HEnumFeaturesOrOptions: unrecognized feature %s\n", pszFeatureKeyword));
  1796. return E_INVALIDARG;
  1797. }
  1798. cPPDFeaturesOrOptions = 0;
  1799. }
  1800. for (cIndex = 0; cIndex < cPPDFeaturesOrOptions; cIndex++)
  1801. {
  1802. //
  1803. // Now enumerate PPD features/options.
  1804. //
  1805. PSTR pszKeyword;
  1806. DWORD cbKeySize;
  1807. if (bEnumFeatures)
  1808. {
  1809. pszKeyword = OFFSET_TO_POINTER(pInfoHeader, pFeature->loKeywordName);
  1810. }
  1811. else
  1812. {
  1813. pszKeyword = OFFSET_TO_POINTER(pInfoHeader, pOption->loKeywordName);
  1814. }
  1815. if (pszKeyword == NULL)
  1816. {
  1817. ASSERT(pszKeyword != NULL);
  1818. return E_FAIL;
  1819. }
  1820. //
  1821. // count in the NUL character between feature/option keywords
  1822. //
  1823. cbKeySize = strlen(pszKeyword) + 1;
  1824. if (pCurrentOut && cbRemain >= (INT)cbKeySize)
  1825. {
  1826. CopyMemory(pCurrentOut, pszKeyword, cbKeySize);
  1827. pCurrentOut += cbKeySize;
  1828. }
  1829. cbRemain -= cbKeySize;
  1830. cbNeeded += cbKeySize;
  1831. if (bEnumFeatures)
  1832. {
  1833. pFeature++;
  1834. }
  1835. else
  1836. {
  1837. pOption = (POPTION)((PBYTE)pOption + pFeature->dwOptionSize);
  1838. }
  1839. }
  1840. //
  1841. // remember the last NUL terminator for the MULTI_SZ output string
  1842. //
  1843. cbRemain--;
  1844. cbNeeded++;
  1845. if (pcbNeeded)
  1846. {
  1847. *pcbNeeded = cbNeeded;
  1848. }
  1849. if (!pCurrentOut || cbRemain < 0)
  1850. {
  1851. return E_OUTOFMEMORY;
  1852. }
  1853. *pCurrentOut = NUL;
  1854. return S_OK;
  1855. }