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.

4255 lines
120 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. ppdparse.c
  5. Abstract:
  6. Parser for converting PPD file from ASCII text to binary data
  7. Environment:
  8. PostScript driver, PPD parser
  9. Revision History:
  10. 12/03/96 -davidx-
  11. Check binary file date against all source printer description files.
  12. 09/30/96 -davidx-
  13. Cleaner handling of ManualFeed and AutoSelect feature.
  14. 09/17/96 -davidx-
  15. Add link field to order dependency structure.
  16. 08/22/96 -davidx-
  17. New binary data format for NT 5.0.
  18. 08/20/96 -davidx-
  19. Common coding style for NT 5.0 drivers.
  20. 03/26/96 -davidx-
  21. Created it.
  22. --*/
  23. #include "lib.h"
  24. #include "ppd.h"
  25. #include "ppdparse.h"
  26. #include "ppdrsrc.h"
  27. //
  28. // Round up n to a multiple of m
  29. //
  30. #define ROUND_UP_MULTIPLE(n, m) ((((n) + (m) - 1) / (m)) * (m))
  31. //
  32. // Round up n to a multiple of sizeof(DWORD) = 4
  33. //
  34. #define DWORD_ALIGN(n) (((n) + 3) & ~3)
  35. //
  36. // Raise an exception to cause VPackBinaryData to fail
  37. //
  38. #define PACK_BINARY_DATA_EXCEPTION() RaiseException(0xC0000000, 0, 0, NULL);
  39. //
  40. // Display a semantic error message
  41. //
  42. #define SEMANTIC_ERROR(arg) { TERSE(arg); pParserData->bErrorFlag = TRUE; }
  43. //
  44. // Data structure to store meta-information about a printer feature
  45. // Note that the default order dependency value is relative to MAX_ORDER_VALUE.
  46. // Explicitly specified order value must be less than MAX_ORDER_VALUE.
  47. //
  48. // We assume all printer-sticky features have higher priority than
  49. // all doc-sticky features. The priority values for printer-sticky
  50. // feature must be >= PRNPROP_BASE_PRIORITY.
  51. //
  52. #define MAX_ORDER_VALUE 0x7fffffff
  53. #define PRNPROP_BASE_PRIORITY 0x10000
  54. typedef struct _FEATUREDATA {
  55. DWORD dwFeatureID; // predefined feature ID
  56. DWORD dwOptionSize; // size of the associated option structure
  57. DWORD dwPriority; // feature priority
  58. DWORD dwFlags; // feature flags
  59. } FEATUREDATA, *PFEATUREDATA;
  60. //
  61. // Special code page value used internally in this file.
  62. // Make sure they don't conflict with standard code page values.
  63. //
  64. #define CP_ERROR 0xffffffff
  65. #define CP_UNICODE 0xfffffffe
  66. PFEATUREDATA
  67. PGetFeatureData(
  68. DWORD dwFeatureID
  69. )
  70. /*++
  71. Routine Description:
  72. Return meta-information about the requested feature
  73. Arguments:
  74. dwFeatureID - Specifies what feature the caller is interested in
  75. Return Value:
  76. Pointer to a FEATUREDATA structure corresponding to the request feature
  77. --*/
  78. {
  79. static FEATUREDATA FeatureData[] =
  80. {
  81. { GID_RESOLUTION, sizeof(RESOLUTION), 10, 0},
  82. { GID_PAGESIZE, sizeof(PAGESIZE), 50, 0},
  83. { GID_PAGEREGION, sizeof(OPTION), 40, FEATURE_FLAG_NOUI},
  84. { GID_DUPLEX, sizeof(DUPLEX), 20, 0},
  85. { GID_INPUTSLOT, sizeof(INPUTSLOT), 30, 0},
  86. { GID_MEDIATYPE, sizeof(MEDIATYPE), 10, 0},
  87. { GID_COLLATE, sizeof(COLLATE), 10, 0},
  88. { GID_OUTPUTBIN, sizeof(OUTPUTBIN), 10, 0},
  89. { GID_MEMOPTION, sizeof(MEMOPTION), 10, 0},
  90. { GID_LEADINGEDGE, sizeof(OPTION), 25, FEATURE_FLAG_NOUI | FEATURE_FLAG_NOINVOCATION},
  91. { GID_USEHWMARGINS, sizeof(OPTION), 25, FEATURE_FLAG_NOUI | FEATURE_FLAG_NOINVOCATION},
  92. { GID_UNKNOWN, sizeof(OPTION), 0, 0},
  93. };
  94. DWORD dwIndex;
  95. for (dwIndex = 0; FeatureData[dwIndex].dwFeatureID != GID_UNKNOWN; dwIndex++)
  96. {
  97. if (FeatureData[dwIndex].dwFeatureID == dwFeatureID)
  98. break;
  99. }
  100. return &FeatureData[dwIndex];
  101. }
  102. VOID
  103. VGrowPackBuffer(
  104. PPARSERDATA pParserData,
  105. DWORD dwBytesNeeded
  106. )
  107. /*++
  108. Routine Description:
  109. Grow the buffer used to hold packed binary data if necessary
  110. Arguments:
  111. pParserData - Points to parser data structure
  112. dwBytesNeeded - Number of bytes needed
  113. Return Value:
  114. NONE
  115. --*/
  116. #define PACK_BUFFER_MAX 1024 // measured in number of pages
  117. {
  118. VALIDATE_PARSER_DATA(pParserData);
  119. //
  120. // We need to commit more memory if the number of bytes needed plus the
  121. // number of bytes used is over the maximum number of bytes committed.
  122. //
  123. if ((dwBytesNeeded += pParserData->dwBufSize) > pParserData->dwCommitSize)
  124. {
  125. //
  126. // Check if we're being called for the first time.
  127. // In that case, we'll need to reserved the virtual address space.
  128. //
  129. if (pParserData->pubBufStart == NULL)
  130. {
  131. SYSTEM_INFO SystemInfo;
  132. PBYTE pbuf;
  133. GetSystemInfo(&SystemInfo);
  134. pParserData->dwPageSize = SystemInfo.dwPageSize;
  135. pbuf = VirtualAlloc(NULL,
  136. PACK_BUFFER_MAX * SystemInfo.dwPageSize,
  137. MEM_RESERVE,
  138. PAGE_READWRITE);
  139. if (pbuf == NULL)
  140. {
  141. ERR(("Cannot reserve memory: %d\n", GetLastError()));
  142. PACK_BINARY_DATA_EXCEPTION();
  143. }
  144. pParserData->pubBufStart = pbuf;
  145. pParserData->pInfoHdr = (PINFOHEADER) pbuf;
  146. pParserData->pUIInfo = (PUIINFO) (pbuf + sizeof(INFOHEADER));
  147. pParserData->pPpdData = (PPPDDATA) (pbuf + sizeof(INFOHEADER) + sizeof(UIINFO));
  148. }
  149. //
  150. // Make sure we're not overflowing
  151. //
  152. if (dwBytesNeeded > (PACK_BUFFER_MAX * pParserData->dwPageSize))
  153. {
  154. ERR(("Binary printer description is too big.\n"));
  155. PACK_BINARY_DATA_EXCEPTION();
  156. }
  157. //
  158. // Commit the extra amount of memory needed (rounded up
  159. // to the next page boundary). Note that the memory allocated
  160. // using VirtualAlloc is zero-initialized.
  161. //
  162. dwBytesNeeded -= pParserData->dwCommitSize;
  163. dwBytesNeeded = ROUND_UP_MULTIPLE(dwBytesNeeded, pParserData->dwPageSize);
  164. pParserData->dwCommitSize += dwBytesNeeded;
  165. if (! VirtualAlloc(pParserData->pubBufStart,
  166. pParserData->dwCommitSize,
  167. MEM_COMMIT,
  168. PAGE_READWRITE))
  169. {
  170. ERR(("Cannot commit memory: %d\n", GetLastError()));
  171. PACK_BINARY_DATA_EXCEPTION();
  172. }
  173. }
  174. }
  175. PVOID
  176. PvFindListItem(
  177. PVOID pvList,
  178. PCSTR pstrName,
  179. PDWORD pdwIndex
  180. )
  181. /*++
  182. Routine Description:
  183. Find a named item from a linked-list
  184. Arguments:
  185. pParserData - Points to parser data structure
  186. pstrName - Specifies the item name to be found
  187. pdwIndex - Points to a variable for returning a zero-based item index
  188. Return Value:
  189. Points to the named listed item, NULL if the named item is not in the list
  190. Note:
  191. We're not bothering with fancy data structures here because the parser
  192. is used infrequently to convert a ASCII printer description file to its
  193. binary version. After that, the driver will access binary data directly.
  194. --*/
  195. {
  196. PLISTOBJ pItem;
  197. DWORD dwIndex;
  198. for (pItem = pvList, dwIndex = 0;
  199. pItem && strcmp(pItem->pstrName, pstrName) != EQUAL_STRING;
  200. pItem = pItem->pNext, dwIndex++)
  201. {
  202. }
  203. if (pdwIndex)
  204. *pdwIndex = dwIndex;
  205. return pItem;
  206. }
  207. DWORD
  208. DwCountListItem(
  209. PVOID pvList
  210. )
  211. /*++
  212. Routine Description:
  213. Count the number of items in a linked-list
  214. Arguments:
  215. pvList - Points to a linked-list
  216. Return Value:
  217. Number of items in a linked-list
  218. --*/
  219. {
  220. PLISTOBJ pItem;
  221. DWORD dwCount;
  222. for (pItem = pvList, dwCount = 0;
  223. pItem != NULL;
  224. pItem = pItem->pNext, dwCount++)
  225. {
  226. }
  227. return dwCount;
  228. }
  229. VOID
  230. VPackStringUnicode(
  231. PPARSERDATA pParserData,
  232. PTRREF *ploDest,
  233. PWSTR pwstrSrc
  234. )
  235. /*++
  236. Routine Description:
  237. Pack a Unicode string into the binary data file
  238. Arguments:
  239. pParserData - Points to the parser data structure
  240. ploDest - Returns the byte offset of the packed Unicode string
  241. pwstrSrc - Specifies the source Unicode string to be packed
  242. Return Value:
  243. NONE
  244. --*/
  245. {
  246. if (pwstrSrc == NULL)
  247. *ploDest = 0;
  248. else
  249. {
  250. DWORD dwSize = (wcslen(pwstrSrc) + 1) * sizeof(WCHAR);
  251. VGrowPackBuffer(pParserData, dwSize);
  252. CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize, pwstrSrc, dwSize);
  253. *ploDest = pParserData->dwBufSize;
  254. pParserData->dwBufSize += DWORD_ALIGN(dwSize);
  255. }
  256. }
  257. VOID
  258. VPackStringRsrc(
  259. PPARSERDATA pParserData,
  260. PTRREF *ploDest,
  261. INT iStringId
  262. )
  263. /*++
  264. Routine Description:
  265. Pack a Unicode string resource into the binary data file
  266. Arguments:
  267. pParserData - Points to the parser data structure
  268. ploDest - Returns the byte offset of the packed Unicode string
  269. iStringId - Specifies the resource ID of the Unicode string to be packed
  270. Return Value:
  271. NONE
  272. --*/
  273. {
  274. WCHAR awchBuffer[MAX_XLATION_LEN];
  275. if (! LoadString(ghInstance, iStringId, awchBuffer, MAX_XLATION_LEN))
  276. awchBuffer[0] = NUL;
  277. VPackStringUnicode(pParserData, ploDest, awchBuffer);
  278. }
  279. VOID
  280. VPackStringAnsi(
  281. PPARSERDATA pParserData,
  282. PTRREF *ploDest,
  283. PSTR pstrSrc
  284. )
  285. /*++
  286. Routine Description:
  287. Pack an ANSI string into the binary data file
  288. Arguments:
  289. pParserData - Points to the parser data structure
  290. ploDest - Returns the byte offset of the packed ANSI string
  291. pstrSrc - Specifies the source ANSI string to be packed
  292. Return Value:
  293. NONE
  294. --*/
  295. {
  296. if (pstrSrc == NULL)
  297. *ploDest = 0;
  298. else
  299. {
  300. DWORD dwSize = strlen(pstrSrc) + 1;
  301. VGrowPackBuffer(pParserData, dwSize);
  302. CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize, pstrSrc, dwSize);
  303. *ploDest = pParserData->dwBufSize;
  304. pParserData->dwBufSize += DWORD_ALIGN(dwSize);
  305. }
  306. }
  307. INT
  308. ITranslateToUnicodeString(
  309. PWSTR pwstr,
  310. PCSTR pstr,
  311. INT iLength,
  312. UINT uCodePage
  313. )
  314. /*++
  315. Routine Description:
  316. Translate an ANSI string to Unicode string
  317. Arguments:
  318. pwstr - Buffer for storing Unicode string
  319. pstr - Pointer to ANSI string to be translated
  320. iLength - Length of ANSI string, in bytes
  321. uCodePage - Code page used to do the translation
  322. Return Value:
  323. Number of Unicode characters translated
  324. 0 if there is an error
  325. --*/
  326. {
  327. ASSERT(iLength >= 0);
  328. if (uCodePage == CP_UNICODE)
  329. {
  330. INT i;
  331. //
  332. // Make sure the Unicode translation string has even number of bytes
  333. //
  334. if (iLength & 1)
  335. {
  336. TERSE(("Odd number of bytes in Unicode translation string.\n"));
  337. iLength--;
  338. }
  339. //
  340. // We assume Unicode values are specified in big-endian format in
  341. // the PPD file. Internally we store Unicode values in little-endian
  342. // format. So we need to swap bytes here.
  343. //
  344. iLength /= sizeof(WCHAR);
  345. for (i=iLength; i--; pstr += 2)
  346. *pwstr++ = (pstr[0] << 8) | ((BYTE) pstr[1]);
  347. }
  348. else
  349. {
  350. if (uCodePage == CP_ERROR)
  351. uCodePage = CP_ACP;
  352. iLength = MultiByteToWideChar(uCodePage, 0, pstr, iLength, pwstr, iLength);
  353. ASSERT(iLength >= 0);
  354. }
  355. return iLength;
  356. }
  357. VOID
  358. VPackStringAnsiToUnicode(
  359. PPARSERDATA pParserData,
  360. PTRREF *ploDest,
  361. PSTR pstrSrc,
  362. INT iLength
  363. )
  364. /*++
  365. Routine Description:
  366. Convert an ANSI string to Unicode and pack it into the binary data file
  367. Arguments:
  368. pParserData - Points to the parser data structure
  369. ploDest - Returns the byte offset of the packed Unicode string
  370. pstrSrc - Specifies the source ANSI string to be packed
  371. iLength - Specifies the byte length of the ANSI string
  372. Return Value:
  373. NONE
  374. --*/
  375. {
  376. INT iSize;
  377. PTSTR ptstr;
  378. //
  379. // Source string is NULL
  380. //
  381. if (pstrSrc == NULL)
  382. {
  383. *ploDest = 0;
  384. return;
  385. }
  386. //
  387. // If source string length is -1, it means
  388. // the source string is null-terminated.
  389. //
  390. if (iLength == -1)
  391. iLength = strlen(pstrSrc);
  392. if (pParserData->uCodePage == CP_UNICODE)
  393. {
  394. //
  395. // Source string is Unicode string
  396. //
  397. iSize = iLength + sizeof(WCHAR);
  398. }
  399. else
  400. {
  401. //
  402. // Source string is ANSI string
  403. //
  404. iSize = (iLength + 1) * sizeof(WCHAR);
  405. }
  406. VGrowPackBuffer(pParserData, iSize);
  407. ptstr = (PTSTR) (pParserData->pubBufStart + pParserData->dwBufSize);
  408. *ploDest = pParserData->dwBufSize;
  409. pParserData->dwBufSize += DWORD_ALIGN(iSize);
  410. ITranslateToUnicodeString(ptstr, pstrSrc, iLength, pParserData->uCodePage);
  411. }
  412. VOID
  413. VPackStringXlation(
  414. PPARSERDATA pParserData,
  415. PTRREF *ploDest,
  416. PSTR pstrName,
  417. PINVOCOBJ pXlation
  418. )
  419. /*++
  420. Routine Description:
  421. Figure out the display name of an item, convert it from ANSI
  422. to Unicode string, and pack it into the binary data
  423. Arguments:
  424. pParserData - Points to the parser data structure
  425. ploDest - Returns the byte offset of the packed Unicode string
  426. pstrName - Specifies the name string associated with the item
  427. pXlation - Specifies the translation string associated with the item
  428. Return Value:
  429. NONE
  430. --*/
  431. {
  432. //
  433. // The display name of an item is its translation string if there is one.
  434. // Otherwise, the display name is the same as the name of the item.
  435. //
  436. // If the translation is present, use the current language encoding
  437. // to convert it to Unicode. Otherwise, we always use the ISOLatin1
  438. // encoding to convert the name of the item to Unicode.
  439. //
  440. if (pXlation && pXlation->pvData && pParserData->uCodePage != CP_ERROR)
  441. VPackStringAnsiToUnicode(pParserData, ploDest, pXlation->pvData, pXlation->dwLength);
  442. else
  443. {
  444. UINT uCodePage = pParserData->uCodePage;
  445. pParserData->uCodePage = 1252;
  446. VPackStringAnsiToUnicode(pParserData, ploDest, pstrName, -1);
  447. pParserData->uCodePage = uCodePage;
  448. }
  449. }
  450. VOID
  451. VPackInvocation(
  452. PPARSERDATA pParserData,
  453. PINVOCATION pInvocation,
  454. PINVOCOBJ pInvocObj
  455. )
  456. /*++
  457. Routine Description:
  458. Pack an invocation string into the binary data
  459. Arguments:
  460. pParserData - Points to the parser data structure
  461. pInvocation - Returns information about the packed invocation string
  462. pInvocObj - Points to the invocation string to be packed
  463. Return Value:
  464. NONE
  465. --*/
  466. {
  467. if (IS_SYMBOL_INVOC(pInvocObj))
  468. {
  469. //
  470. // The invocation is a symbol reference
  471. //
  472. PSYMBOLOBJ pSymbol = pInvocObj->pvData;
  473. pInvocation->dwCount = pSymbol->Invocation.dwLength;
  474. //
  475. // For symbol invocation, Invocation.pvData actually stores the
  476. // 32-bit offset value (See function VPackSymbolDefinitions), so
  477. // it's safe to cast it into ULONG/DWORD.
  478. //
  479. pInvocation->loOffset = (PTRREF) PtrToUlong(pSymbol->Invocation.pvData);
  480. }
  481. else if (pInvocObj->dwLength == 0)
  482. {
  483. pInvocation->dwCount = 0;
  484. pInvocation->loOffset = 0;
  485. }
  486. else
  487. {
  488. //
  489. // Notice that we're always padding a zero byte at the end of
  490. // the invocation string. This byte is not counted in dwLength.
  491. //
  492. VGrowPackBuffer(pParserData, pInvocObj->dwLength+1);
  493. CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize,
  494. pInvocObj->pvData,
  495. pInvocObj->dwLength);
  496. pInvocation->dwCount = pInvocObj->dwLength;
  497. pInvocation->loOffset = pParserData->dwBufSize;
  498. pParserData->dwBufSize += DWORD_ALIGN(pInvocObj->dwLength+1);
  499. }
  500. }
  501. VOID
  502. VPackPatch(
  503. PPARSERDATA pParserData,
  504. PJOBPATCHFILE pPackedPatch,
  505. PJOBPATCHFILEOBJ pPatchObj
  506. )
  507. /*++
  508. Routine Description:
  509. Pack an job file patch invocation string into the binary data
  510. Arguments:
  511. pParserData - Points to the parser data structure
  512. pInvocation - Returns information about the packed invocation string
  513. pInvocObj - Points to the invocation string to be packed
  514. Return Value:
  515. NONE
  516. --*/
  517. {
  518. if (pPatchObj->Invocation.dwLength == 0)
  519. {
  520. pPackedPatch->dwCount = 0;
  521. pPackedPatch->loOffset = 0;
  522. }
  523. else
  524. {
  525. //
  526. // Notice that we're always padding a zero byte at the end of
  527. // the invocation string. This byte is not counted in dwLength.
  528. //
  529. VGrowPackBuffer(pParserData, pPatchObj->Invocation.dwLength+1);
  530. CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize,
  531. pPatchObj->Invocation.pvData,
  532. pPatchObj->Invocation.dwLength);
  533. pPackedPatch->loOffset = pParserData->dwBufSize;
  534. pPackedPatch->dwCount = pPatchObj->Invocation.dwLength;
  535. pParserData->dwBufSize += DWORD_ALIGN(pPatchObj->Invocation.dwLength+1);
  536. }
  537. pPackedPatch->lJobPatchNo = pPatchObj->lPatchNo;
  538. }
  539. VOID
  540. VPackSymbolDefinitions(
  541. PPARSERDATA pParserData
  542. )
  543. /*++
  544. Routine Description:
  545. Pack all symbol definitions into the binary data
  546. Arguments:
  547. pParserData - Points to the parser data structure
  548. Return Value:
  549. NONE
  550. --*/
  551. {
  552. PINVOCOBJ pInvocObj;
  553. PSYMBOLOBJ pSymbol;
  554. VALIDATE_PARSER_DATA(pParserData);
  555. for (pSymbol = pParserData->pSymbols;
  556. pSymbol != NULL;
  557. pSymbol = pSymbol->pNext)
  558. {
  559. pInvocObj = &pSymbol->Invocation;
  560. ASSERT(! IS_SYMBOL_INVOC(pInvocObj));
  561. if (pInvocObj->dwLength == 0)
  562. pInvocObj->pvData = NULL;
  563. else
  564. {
  565. //
  566. // Notice that we're always padding a zero byte at the end of
  567. // the invocation string. This byte is not counted in dwLength.
  568. //
  569. VGrowPackBuffer(pParserData, pInvocObj->dwLength+1);
  570. CopyMemory(pParserData->pubBufStart + pParserData->dwBufSize,
  571. pInvocObj->pvData,
  572. pInvocObj->dwLength);
  573. pInvocObj->pvData = (PVOID)ULongToPtr(pParserData->dwBufSize);
  574. pParserData->dwBufSize += DWORD_ALIGN(pInvocObj->dwLength+1);
  575. }
  576. }
  577. }
  578. VOID
  579. VResolveSymbolInvocation(
  580. PPARSERDATA pParserData,
  581. PINVOCOBJ pInvocObj
  582. )
  583. /*++
  584. Routine Description:
  585. Check if an invocation string is a symbol reference and resolve it if necessary
  586. Arguments:
  587. pParserData - Points to the parser data structure
  588. pInvocObj - Specifies the invocation string to be resolved
  589. Return Value:
  590. NONE
  591. --*/
  592. {
  593. if (IS_SYMBOL_INVOC(pInvocObj))
  594. {
  595. PSTR pstrName;
  596. PSYMBOLOBJ pSymbol;
  597. pstrName = (PSTR) pInvocObj->pvData;
  598. if ((pSymbol = PvFindListItem(pParserData->pSymbols, pstrName, NULL)) == NULL)
  599. {
  600. SEMANTIC_ERROR(("Undefined symbol: %s\n", pstrName));
  601. pInvocObj->dwLength = 0;
  602. pInvocObj->pvData = NULL;
  603. }
  604. else
  605. pInvocObj->pvData = (PVOID) pSymbol;
  606. }
  607. }
  608. VOID
  609. VResolveSymbolReferences(
  610. PPARSERDATA pParserData
  611. )
  612. /*++
  613. Routine Description:
  614. Resolve all symbol references in the parsed PPD data
  615. Arguments:
  616. pParserData - Points to the parser data structure
  617. Return Value:
  618. NONE
  619. --*/
  620. {
  621. PFEATUREOBJ pFeature;
  622. POPTIONOBJ pOption;
  623. PJOBPATCHFILEOBJ pJobPatchFile;
  624. VALIDATE_PARSER_DATA(pParserData);
  625. VResolveSymbolInvocation(pParserData, &pParserData->Password);
  626. VResolveSymbolInvocation(pParserData, &pParserData->ExitServer);
  627. VResolveSymbolInvocation(pParserData, &pParserData->PatchFile);
  628. VResolveSymbolInvocation(pParserData, &pParserData->JclBegin);
  629. VResolveSymbolInvocation(pParserData, &pParserData->JclEnterPS);
  630. VResolveSymbolInvocation(pParserData, &pParserData->JclEnd);
  631. VResolveSymbolInvocation(pParserData, &pParserData->ManualFeedFalse);
  632. for (pFeature = pParserData->pFeatures;
  633. pFeature != NULL;
  634. pFeature = pFeature->pNext)
  635. {
  636. VResolveSymbolInvocation(pParserData, &pFeature->QueryInvoc);
  637. for (pOption = pFeature->pOptions;
  638. pOption != NULL;
  639. pOption = pOption->pNext)
  640. {
  641. VResolveSymbolInvocation(pParserData, &pOption->Invocation);
  642. }
  643. }
  644. for (pJobPatchFile = pParserData->pJobPatchFiles;
  645. pJobPatchFile != NULL;
  646. pJobPatchFile = pJobPatchFile->pNext)
  647. {
  648. VResolveSymbolInvocation(pParserData, &pJobPatchFile->Invocation);
  649. }
  650. }
  651. BOOL
  652. BFindUIConstraintFeatureOption(
  653. PPARSERDATA pParserData,
  654. PCSTR pstrKeyword,
  655. PFEATUREOBJ *ppFeature,
  656. PDWORD pdwFeatureIndex,
  657. PCSTR pstrOption,
  658. POPTIONOBJ *ppOption,
  659. PDWORD pdwOptionIndex
  660. )
  661. /*++
  662. Routine Description:
  663. Find the feature/option specified in UIConstraints and OrderDependency entries
  664. Arguments:
  665. pParserData - Points to the parser data structure
  666. pstrKeyword - Specifies the feature keyword string
  667. ppFeature - Return a pointer to the feature structure found
  668. pdwFeatureIndex - Return the index of the feature found
  669. pstrOption - Specifies the option keyword string
  670. ppOption - Return a pointer to the option structure found
  671. pdwOptionIndex - Return the index of the option found
  672. Return Value:
  673. TRUE if successful, FALSE if the specified feature/option is not found
  674. --*/
  675. {
  676. if (! (pstrKeyword = PstrStripKeywordChar(pstrKeyword)))
  677. return FALSE;
  678. //
  679. // HACK:
  680. // replace *ManualFeed True option with *InputSlot ManualFeed option
  681. // replace *CustomPageSize True option with *PageSize CustomPageSize option
  682. //
  683. if ((strcmp(pstrKeyword, gstrManualFeedKwd) == EQUAL_STRING) &&
  684. (*pstrOption == NUL ||
  685. strcmp(pstrOption, gstrTrueKwd) == EQUAL_STRING ||
  686. strcmp(pstrOption, gstrOnKwd) == EQUAL_STRING))
  687. {
  688. pstrKeyword = gstrInputSlotKwd;
  689. pstrOption = gstrManualFeedKwd;
  690. }
  691. else if ((strcmp(pstrKeyword, gstrCustomSizeKwd) == EQUAL_STRING) &&
  692. (*pstrOption == NUL || strcmp(pstrOption, gstrTrueKwd) == EQUAL_STRING))
  693. {
  694. pstrKeyword = gstrPageSizeKwd;
  695. pstrOption = gstrCustomSizeKwd;
  696. }
  697. else if (strcmp(pstrKeyword, gstrVMOptionKwd) == EQUAL_STRING)
  698. pstrKeyword = gstrInstallMemKwd;
  699. //
  700. // Find the specified feature
  701. //
  702. if (! (*ppFeature = PvFindListItem(pParserData->pFeatures, pstrKeyword, pdwFeatureIndex)))
  703. return FALSE;
  704. //
  705. // Find the specified option
  706. //
  707. if (*pstrOption)
  708. {
  709. return (*ppOption = PvFindListItem((*ppFeature)->pOptions,
  710. pstrOption,
  711. pdwOptionIndex)) != NULL;
  712. }
  713. else
  714. {
  715. *ppOption = NULL;
  716. *pdwOptionIndex = OPTION_INDEX_ANY;
  717. return TRUE;
  718. }
  719. }
  720. VOID
  721. VPackUIConstraints(
  722. PPARSERDATA pParserData
  723. )
  724. /*++
  725. Routine Description:
  726. Pack UIConstraints information into binary data
  727. Arguments:
  728. pParserData - Points to the parser data structure
  729. Return Value:
  730. NONE
  731. --*/
  732. {
  733. PUICONSTRAINT pPackedConstraint;
  734. PFEATUREOBJ pFeature;
  735. POPTIONOBJ pOption;
  736. PLISTOBJ pConstraint;
  737. DWORD dwConstraints, dwConstraintBufStart;
  738. VALIDATE_PARSER_DATA(pParserData);
  739. //
  740. // By default, there is no constaint for all features and options
  741. //
  742. for (pFeature = pParserData->pFeatures;
  743. pFeature != NULL;
  744. pFeature = pFeature->pNext)
  745. {
  746. pFeature->dwConstraint = NULL_CONSTRAINT;
  747. for (pOption = pFeature->pOptions;
  748. pOption != NULL;
  749. pOption = pOption->pNext)
  750. {
  751. pOption->dwConstraint = NULL_CONSTRAINT;
  752. }
  753. }
  754. //
  755. // Count the number of *UIConstraints entries
  756. //
  757. dwConstraints = DwCountListItem(pParserData->pUIConstraints);
  758. if (dwConstraints == 0)
  759. return;
  760. //
  761. // Don't yet grow the buffer, we only number the number of constraints after we
  762. // evaluated the *ManualFeed: False constraints. pPackedConstraint points right
  763. // after the end of the current buffer
  764. //
  765. pPackedConstraint = (PUICONSTRAINT) (pParserData->pubBufStart + pParserData->dwBufSize);
  766. dwConstraintBufStart = pParserData->dwBufSize;
  767. //
  768. // Interpret each *UIConstraints entry
  769. //
  770. dwConstraints = 0;
  771. for (pConstraint = pParserData->pUIConstraints;
  772. pConstraint != NULL;
  773. pConstraint = pConstraint->pNext)
  774. {
  775. PFEATUREOBJ pFeature2;
  776. POPTIONOBJ pOption2;
  777. DWORD dwFeatureIndex, dwOptionIndex, dwManFeedFalsePos = 0;
  778. CHAR achWord1[MAX_WORD_LEN];
  779. CHAR achWord2[MAX_WORD_LEN];
  780. CHAR achWord3[MAX_WORD_LEN];
  781. CHAR achWord4[MAX_WORD_LEN];
  782. PSTR pstr = pConstraint->pstrName;
  783. BOOL bSuccess = FALSE;
  784. //
  785. // The value for a UIConstraints entry consists of four separate components:
  786. // featureName1 [optionName1] featureName2 [optionName2]
  787. //
  788. (VOID) BFindNextWord(&pstr, achWord1);
  789. if (IS_KEYWORD_CHAR(*pstr))
  790. achWord2[0] = NUL;
  791. else
  792. (VOID) BFindNextWord(&pstr, achWord2);
  793. (VOID) BFindNextWord(&pstr, achWord3);
  794. (VOID) BFindNextWord(&pstr, achWord4);
  795. //
  796. // hack the *ManualFeed False constraints
  797. //
  798. if ((IS_KEYWORD_CHAR(achWord1[0])) &&
  799. (strcmp(&(achWord1[1]), gstrManualFeedKwd) == EQUAL_STRING) &&
  800. (strcmp(achWord2, gstrFalseKwd) == EQUAL_STRING))
  801. {
  802. //
  803. // check the validity of the constraint feature/option. Fall through if invalid
  804. //
  805. if (BFindUIConstraintFeatureOption(pParserData,
  806. achWord3,
  807. &pFeature,
  808. &dwFeatureIndex,
  809. achWord4,
  810. &pOption,
  811. &dwOptionIndex))
  812. dwManFeedFalsePos = 1;
  813. }
  814. else if ((IS_KEYWORD_CHAR(achWord3[0])) &&
  815. (strcmp(&(achWord3[1]), gstrManualFeedKwd) == EQUAL_STRING) &&
  816. (strcmp(achWord4, gstrFalseKwd) == EQUAL_STRING))
  817. {
  818. //
  819. // check the validity of the constraint feature/option. Fall through if invalid
  820. //
  821. if (BFindUIConstraintFeatureOption(pParserData,
  822. achWord1,
  823. &pFeature,
  824. &dwFeatureIndex,
  825. achWord2,
  826. &pOption,
  827. &dwOptionIndex))
  828. dwManFeedFalsePos = 2;
  829. }
  830. if (dwManFeedFalsePos)
  831. {
  832. //
  833. // get the index of the manual feed input slot
  834. //
  835. DWORD dwInputSlotFeatIndex, dwManFeedSlotIndex, dwInputSlotCount, dwSlotIndex;
  836. PFEATUREOBJ pInputSlotFeature;
  837. if ((pInputSlotFeature = PvFindListItem(pParserData->pFeatures, gstrInputSlotKwd, &dwInputSlotFeatIndex)) == NULL)
  838. {
  839. ERR(("Input slot feature not found !!!"));
  840. continue;
  841. }
  842. //
  843. // get the number of input slots. Note that this includes the dummy "*UseFormTrayTable" slot.
  844. //
  845. dwInputSlotCount = DwCountListItem((PVOID) pInputSlotFeature->pOptions);
  846. if (dwInputSlotCount <= 2) // to make sense there must be at least 3 slot, incl. UseFormTrayTable+ManualFeed
  847. {
  848. ERR(("ManualFeed used - internally at least 3 input slots expected !"));
  849. continue;
  850. }
  851. //
  852. // grow the buffer for constraints. Two less than input slots because
  853. // 1 input slot is the dummy UseFormTrayTable slot
  854. // 1 input slot is the ManualFeed slot that I don't want to constraint
  855. //
  856. VGrowPackBuffer(pParserData, (dwInputSlotCount -2) * sizeof(UICONSTRAINT));
  857. if (dwManFeedFalsePos == 1)
  858. {
  859. //
  860. // add constraints to each input slot for the constrained feature
  861. //
  862. POPTIONOBJ pNextObj = pInputSlotFeature->pOptions;
  863. ASSERT(strcmp(pNextObj->pstrName, "*UseFormTrayTable") == EQUAL_STRING); // in case we change the logic some time later...
  864. //
  865. // since the UseFormTrayTable is the first option, start with the second
  866. //
  867. pNextObj = pNextObj->pNext;
  868. ASSERT(pNextObj != NULL);
  869. while (pNextObj)
  870. {
  871. //
  872. // skip the manual feed input slot, don't constrain that
  873. //
  874. if (strcmp(pNextObj->pstrName, gstrManualFeedKwd) == EQUAL_STRING)
  875. {
  876. pNextObj = pNextObj->pNext;
  877. continue;
  878. }
  879. pPackedConstraint[dwConstraints].dwNextConstraint = pNextObj->dwConstraint;
  880. pNextObj->dwConstraint = dwConstraints;
  881. pPackedConstraint[dwConstraints].dwFeatureIndex = dwFeatureIndex;
  882. pPackedConstraint[dwConstraints].dwOptionIndex = dwOptionIndex;
  883. dwConstraints++;
  884. pNextObj = pNextObj->pNext;
  885. }
  886. }
  887. else
  888. {
  889. //
  890. // find the option index of the manual feed slot
  891. //
  892. if (PvFindListItem(pInputSlotFeature->pOptions, gstrManualFeedKwd, &dwManFeedSlotIndex) == NULL)
  893. {
  894. ERR(("ManualFeed slot not found among InputSlots !!!"));
  895. continue;
  896. }
  897. //
  898. // add constraints to the affected feature for all input slots BUT the manual feed slot
  899. // and the UseFormTrayTable slot
  900. // start with slot index 1, because the first slot is always *UseFormTrayTable
  901. //
  902. for (dwSlotIndex = 1; dwSlotIndex < dwInputSlotCount; dwSlotIndex++)
  903. {
  904. if (dwSlotIndex == dwManFeedSlotIndex)
  905. continue;
  906. if (pOption == NULL)
  907. {
  908. //
  909. // OptionKeyword1 field is not present
  910. //
  911. pPackedConstraint[dwConstraints].dwNextConstraint = pFeature->dwConstraint;
  912. pFeature->dwConstraint = dwConstraints;
  913. }
  914. else
  915. {
  916. //
  917. // OptionKeyword1 field is present
  918. //
  919. pPackedConstraint[dwConstraints].dwNextConstraint = pOption->dwConstraint;
  920. pOption->dwConstraint = dwConstraints;
  921. }
  922. pPackedConstraint[dwConstraints].dwFeatureIndex = dwInputSlotFeatIndex;
  923. pPackedConstraint[dwConstraints].dwOptionIndex = dwSlotIndex;
  924. dwConstraints++;
  925. }
  926. }
  927. //
  928. // increase the committed buffer size so additional VGrowPackBuffer calls can allocate
  929. // additional pages if needed for more *ManualFeed False constraints
  930. //
  931. pParserData->dwBufSize += DWORD_ALIGN((dwInputSlotCount -2) * sizeof(UICONSTRAINT));
  932. continue;
  933. } // back to the normal course of events.
  934. if (BFindUIConstraintFeatureOption(pParserData,
  935. achWord1,
  936. &pFeature,
  937. &dwFeatureIndex,
  938. achWord2,
  939. &pOption,
  940. &dwOptionIndex) &&
  941. BFindUIConstraintFeatureOption(pParserData,
  942. achWord3,
  943. &pFeature2,
  944. &dwFeatureIndex,
  945. achWord4,
  946. &pOption2,
  947. &dwOptionIndex))
  948. {
  949. VGrowPackBuffer(pParserData, sizeof(UICONSTRAINT));
  950. if (pOption == NULL)
  951. {
  952. //
  953. // OptionKeyword1 field is not present
  954. //
  955. pPackedConstraint[dwConstraints].dwNextConstraint = pFeature->dwConstraint;
  956. pFeature->dwConstraint = dwConstraints;
  957. }
  958. else
  959. {
  960. //
  961. // OptionKeyword1 field is present
  962. //
  963. pPackedConstraint[dwConstraints].dwNextConstraint = pOption->dwConstraint;
  964. pOption->dwConstraint = dwConstraints;
  965. }
  966. pPackedConstraint[dwConstraints].dwFeatureIndex = dwFeatureIndex;
  967. pPackedConstraint[dwConstraints].dwOptionIndex = dwOptionIndex;
  968. dwConstraints++;
  969. bSuccess = TRUE;
  970. //
  971. // increase the committed buffer size so additional VGrowPackBuffer calls can allocate
  972. // additional pages if needed for more *ManualFeed False constraints
  973. //
  974. pParserData->dwBufSize += DWORD_ALIGN(sizeof(UICONSTRAINT));
  975. }
  976. if (! bSuccess)
  977. SEMANTIC_ERROR(("Invalid *UIConstraints entry: %s\n", pConstraint->pstrName));
  978. }
  979. //
  980. // Save the packed UIConstraints information in the binary data
  981. //
  982. if (dwConstraints == 0)
  983. {
  984. pParserData->pUIInfo->UIConstraints.dwCount = 0;
  985. pParserData->pUIInfo->UIConstraints.loOffset = 0;
  986. }
  987. else
  988. {
  989. pParserData->pUIInfo->UIConstraints.dwCount = dwConstraints;
  990. pParserData->pUIInfo->UIConstraints.loOffset = dwConstraintBufStart;
  991. }
  992. }
  993. VOID
  994. VPackOrderDependency(
  995. PPARSERDATA pParserData,
  996. PARRAYREF parefDest,
  997. PLISTOBJ pOrderDep
  998. )
  999. /*++
  1000. Routine Description:
  1001. Pack OrderDependency/QueryOrderDependency information into binary data
  1002. Arguments:
  1003. pParserData - Points to the parser data structure
  1004. parefDest - Stores information about where the order dependency info is packed
  1005. pOrderDep - Specifies the list of order dependencies to be packed
  1006. Return Value:
  1007. NONE
  1008. --*/
  1009. {
  1010. static const STRTABLE SectionStrs[] =
  1011. {
  1012. { "DocumentSetup", SECTION_DOCSETUP},
  1013. { "AnySetup", SECTION_ANYSETUP},
  1014. { "PageSetup", SECTION_PAGESETUP},
  1015. { "Prolog", SECTION_PROLOG},
  1016. { "ExitServer", SECTION_EXITSERVER},
  1017. { "JCLSetup", SECTION_JCLSETUP},
  1018. { NULL, SECTION_UNASSIGNED}
  1019. };
  1020. PORDERDEPEND pPackedDep;
  1021. PFEATUREOBJ pFeature;
  1022. POPTIONOBJ pOption;
  1023. DWORD dwOrderDep, dwFeatures, dwIndex;
  1024. DWORD dwFeatureIndex, dwOptionIndex, dwSection;
  1025. LONG lOrder;
  1026. VALIDATE_PARSER_DATA(pParserData);
  1027. //
  1028. // The maximum number of entries we need is:
  1029. // number of printer features + number of order dependency entries
  1030. //
  1031. dwFeatures = pParserData->pInfoHdr->RawData.dwDocumentFeatures +
  1032. pParserData->pInfoHdr->RawData.dwPrinterFeatures;
  1033. dwOrderDep = dwFeatures + DwCountListItem(pOrderDep);
  1034. VGrowPackBuffer(pParserData, dwOrderDep * sizeof(ORDERDEPEND));
  1035. pPackedDep = (PORDERDEPEND) (pParserData->pubBufStart + pParserData->dwBufSize);
  1036. //
  1037. // Create a default order dependency entry for each feature
  1038. //
  1039. for (pFeature = pParserData->pFeatures, dwFeatureIndex = 0;
  1040. pFeature != NULL;
  1041. pFeature = pFeature->pNext, dwFeatureIndex++)
  1042. {
  1043. pPackedDep[dwFeatureIndex].lOrder = MAX_ORDER_VALUE;
  1044. pPackedDep[dwFeatureIndex].dwSection = SECTION_UNASSIGNED;
  1045. pPackedDep[dwFeatureIndex].dwPPDSection = SECTION_UNASSIGNED;
  1046. pPackedDep[dwFeatureIndex].dwFeatureIndex = dwFeatureIndex;
  1047. pPackedDep[dwFeatureIndex].dwOptionIndex = OPTION_INDEX_ANY;
  1048. }
  1049. //
  1050. // Interpret each order dependency entry
  1051. //
  1052. for (dwOrderDep = dwFeatures; pOrderDep != NULL; pOrderDep = pOrderDep->pNext)
  1053. {
  1054. CHAR achWord1[MAX_WORD_LEN];
  1055. CHAR achWord2[MAX_WORD_LEN];
  1056. PSTR pstr = pOrderDep->pstrName;
  1057. BOOL bSuccess = FALSE;
  1058. //
  1059. // Each order dependency entry has the following components:
  1060. // order section mainKeyword [optionKeyword]
  1061. //
  1062. if (BGetFloatFromString(&pstr, &lOrder, FLTYPE_INT) &&
  1063. BFindNextWord(&pstr, achWord1) &&
  1064. BSearchStrTable(SectionStrs, achWord1, &dwSection) &&
  1065. BFindNextWord(&pstr, achWord1))
  1066. {
  1067. (VOID) BFindNextWord(&pstr, achWord2);
  1068. if (BFindUIConstraintFeatureOption(pParserData,
  1069. achWord1,
  1070. &pFeature,
  1071. &dwFeatureIndex,
  1072. achWord2,
  1073. &pOption,
  1074. &dwOptionIndex))
  1075. {
  1076. //
  1077. // Check if an OrderDependency for the same feature/option
  1078. // has appeared before.
  1079. //
  1080. for (dwIndex = 0; dwIndex < dwOrderDep; dwIndex++)
  1081. {
  1082. if (pPackedDep[dwIndex].dwFeatureIndex == dwFeatureIndex &&
  1083. pPackedDep[dwIndex].dwOptionIndex == dwOptionIndex)
  1084. {
  1085. break;
  1086. }
  1087. }
  1088. if (dwIndex < dwOrderDep && pPackedDep[dwIndex].lOrder < MAX_ORDER_VALUE)
  1089. {
  1090. TERSE(("Duplicate order dependency entry: %s\n", pOrderDep->pstrName));
  1091. }
  1092. else
  1093. {
  1094. if (dwIndex >= dwOrderDep)
  1095. dwIndex = dwOrderDep++;
  1096. //
  1097. // Ensure the specified order value is less than MAX_ORDER_VALUE
  1098. //
  1099. if (lOrder >= MAX_ORDER_VALUE)
  1100. {
  1101. WARNING(("Order dependency value too big: %s\n", pOrderDep->pstrName));
  1102. lOrder = MAX_ORDER_VALUE - 1;
  1103. }
  1104. pPackedDep[dwIndex].dwSection = dwSection;
  1105. pPackedDep[dwIndex].dwPPDSection = dwSection;
  1106. pPackedDep[dwIndex].lOrder = lOrder;
  1107. pPackedDep[dwIndex].dwFeatureIndex = dwFeatureIndex;
  1108. pPackedDep[dwIndex].dwOptionIndex = dwOptionIndex;
  1109. }
  1110. bSuccess = TRUE;
  1111. }
  1112. }
  1113. if (! bSuccess)
  1114. SEMANTIC_ERROR(("Invalid order dependency: %s\n", pOrderDep->pstrName));
  1115. }
  1116. //
  1117. // Tell the caller where the packed order dependency information is stored
  1118. //
  1119. if (dwOrderDep == 0)
  1120. {
  1121. parefDest->dwCount = 0;
  1122. parefDest->loOffset = 0;
  1123. return;
  1124. }
  1125. parefDest->dwCount = dwOrderDep;
  1126. parefDest->loOffset = pParserData->dwBufSize;
  1127. pParserData->dwBufSize += DWORD_ALIGN(dwOrderDep * sizeof(ORDERDEPEND));
  1128. //
  1129. // Sort order dependency information using the order value
  1130. //
  1131. for (dwIndex = 0; dwIndex+1 < dwOrderDep; dwIndex++)
  1132. {
  1133. DWORD dwMinIndex, dwLoop;
  1134. //
  1135. // Nothing fancy here - straight-forward selection sort
  1136. //
  1137. dwMinIndex = dwIndex;
  1138. for (dwLoop = dwIndex+1; dwLoop < dwOrderDep; dwLoop++)
  1139. {
  1140. if ((pPackedDep[dwLoop].lOrder < pPackedDep[dwMinIndex].lOrder) ||
  1141. (pPackedDep[dwLoop].lOrder == pPackedDep[dwMinIndex].lOrder &&
  1142. pPackedDep[dwLoop].dwSection < pPackedDep[dwMinIndex].dwSection))
  1143. {
  1144. dwMinIndex = dwLoop;
  1145. }
  1146. }
  1147. if (dwMinIndex != dwIndex)
  1148. {
  1149. ORDERDEPEND TempDep;
  1150. TempDep = pPackedDep[dwIndex];
  1151. pPackedDep[dwIndex] = pPackedDep[dwMinIndex];
  1152. pPackedDep[dwMinIndex] = TempDep;
  1153. }
  1154. }
  1155. //
  1156. // Resolve AnySetup into either DocumentSetup or PageSetup
  1157. //
  1158. dwSection = SECTION_DOCSETUP;
  1159. for (dwIndex = 0; dwIndex < dwOrderDep; dwIndex++)
  1160. {
  1161. if (pPackedDep[dwIndex].dwSection == SECTION_PAGESETUP)
  1162. dwSection = SECTION_PAGESETUP;
  1163. else if (pPackedDep[dwIndex].dwSection == SECTION_ANYSETUP)
  1164. pPackedDep[dwIndex].dwSection = dwSection;
  1165. }
  1166. //
  1167. // Maintain a linked-list of order dependency entries for each feature
  1168. // starting with the entry whose dwOptionIndex = OPTION_INDEX_ANY.
  1169. //
  1170. for (dwIndex = 0; dwIndex < dwOrderDep; dwIndex++)
  1171. pPackedDep[dwIndex].dwNextOrderDep = NULL_ORDERDEP;
  1172. for (dwIndex = 0; dwIndex < dwOrderDep; dwIndex++)
  1173. {
  1174. DWORD dwLastIndex, dwLoop;
  1175. if (pPackedDep[dwIndex].dwOptionIndex != OPTION_INDEX_ANY)
  1176. continue;
  1177. dwLastIndex = dwIndex;
  1178. for (dwLoop = 0; dwLoop < dwOrderDep; dwLoop++)
  1179. {
  1180. if (pPackedDep[dwLoop].dwFeatureIndex == pPackedDep[dwIndex].dwFeatureIndex &&
  1181. pPackedDep[dwLoop].dwOptionIndex != OPTION_INDEX_ANY)
  1182. {
  1183. pPackedDep[dwLastIndex].dwNextOrderDep = dwLoop;
  1184. dwLastIndex = dwLoop;
  1185. }
  1186. }
  1187. pPackedDep[dwLastIndex].dwNextOrderDep = NULL_ORDERDEP;
  1188. }
  1189. //
  1190. // !!!CR
  1191. // Needs to flag out-of-order OrderDependency.
  1192. //
  1193. }
  1194. VOID
  1195. VCountAndSortPrinterFeatures(
  1196. PPARSERDATA pParserData
  1197. )
  1198. /*++
  1199. Routine Description:
  1200. Count the number of doc- and printer-sticky features
  1201. and sort them into two separate groups
  1202. Arguments:
  1203. pParserData - Points to the parser data structure
  1204. Return Value:
  1205. NONE
  1206. --*/
  1207. {
  1208. PFEATUREOBJ pFeature, pNext, pDocFeatures, pPrinterFeatures;
  1209. DWORD dwDocFeatures, dwPrinterFeatures;
  1210. VALIDATE_PARSER_DATA(pParserData);
  1211. //
  1212. // Count the number of doc- and printer-sticky features
  1213. //
  1214. pDocFeatures = pPrinterFeatures = NULL;
  1215. dwDocFeatures = dwPrinterFeatures = 0;
  1216. pFeature = pParserData->pFeatures;
  1217. while (pFeature != NULL)
  1218. {
  1219. pNext = pFeature->pNext;
  1220. if (pFeature->bInstallable)
  1221. {
  1222. pFeature->pNext = pPrinterFeatures;
  1223. pPrinterFeatures = pFeature;
  1224. dwPrinterFeatures++;
  1225. }
  1226. else
  1227. {
  1228. pFeature->pNext = pDocFeatures;
  1229. pDocFeatures = pFeature;
  1230. dwDocFeatures++;
  1231. }
  1232. pFeature = pNext;
  1233. }
  1234. ASSERTMSG((dwDocFeatures + dwPrinterFeatures <= MAX_PRINTER_OPTIONS),
  1235. ("Too many printer features.\n"));
  1236. //
  1237. // Rearrange the features so that all doc-sticky features
  1238. // are in front of printer-sticky features
  1239. //
  1240. pFeature = NULL;
  1241. while (pPrinterFeatures != NULL)
  1242. {
  1243. pNext = pPrinterFeatures->pNext;
  1244. pPrinterFeatures->pNext = pFeature;
  1245. pFeature = pPrinterFeatures;
  1246. pPrinterFeatures = pNext;
  1247. }
  1248. while (pDocFeatures != NULL)
  1249. {
  1250. pNext = pDocFeatures->pNext;
  1251. pDocFeatures->pNext = pFeature;
  1252. pFeature = pDocFeatures;
  1253. pDocFeatures = pNext;
  1254. }
  1255. pParserData->pFeatures = pFeature;
  1256. pParserData->pInfoHdr->RawData.dwDocumentFeatures = dwDocFeatures;
  1257. pParserData->pInfoHdr->RawData.dwPrinterFeatures = dwPrinterFeatures;
  1258. }
  1259. VOID
  1260. VProcessPrinterFeatures(
  1261. PPARSERDATA pParserData
  1262. )
  1263. /*++
  1264. Routine Description:
  1265. Process printer features and handle any special glitches
  1266. Arguments:
  1267. pParserData - Points to parser data structure
  1268. Return Value:
  1269. NONE
  1270. --*/
  1271. {
  1272. PFEATUREOBJ pFeature;
  1273. POPTIONOBJ pOption;
  1274. for (pFeature = pParserData->pFeatures; pFeature; pFeature = pFeature->pNext)
  1275. {
  1276. //
  1277. // If a feature has no option but has a default specified, then
  1278. // synthesize an option with empty invocation string.
  1279. //
  1280. if (pFeature->pstrDefault && pFeature->pOptions == NULL)
  1281. {
  1282. pOption = ALLOC_PARSER_MEM(pParserData, pFeature->dwOptionSize);
  1283. if (pOption == NULL)
  1284. {
  1285. ERR(("Memory allocation failed: %d\n", GetLastError()));
  1286. PACK_BINARY_DATA_EXCEPTION();
  1287. }
  1288. //
  1289. // NOTE: it's ok for both pOption->pstrName and pFeature->pstrDefault
  1290. // to point to the same string here. The memory is deallocated when
  1291. // the parser heap is destroyed.
  1292. //
  1293. pOption->pstrName = pFeature->pstrDefault;
  1294. pFeature->pOptions = pOption;
  1295. }
  1296. //
  1297. // Special handling of *InputSlot feature
  1298. // Make sure the very first option is always "*UseFormTrayTable"
  1299. //
  1300. if (pFeature->dwFeatureID == GID_INPUTSLOT)
  1301. {
  1302. pOption = ALLOC_PARSER_MEM(pParserData, pFeature->dwOptionSize);
  1303. if (pOption == NULL)
  1304. {
  1305. ERR(("Memory allocation failed: %d\n", GetLastError()));
  1306. PACK_BINARY_DATA_EXCEPTION();
  1307. }
  1308. pOption->pstrName = "*UseFormTrayTable";
  1309. pOption->pNext = pFeature->pOptions;
  1310. pFeature->pOptions = pOption;
  1311. ((PTRAYOBJ) pOption)->dwTrayIndex = DMBIN_FORMSOURCE;
  1312. }
  1313. }
  1314. }
  1315. VOID
  1316. VPackPrinterFeatures(
  1317. PPARSERDATA pParserData
  1318. )
  1319. /*++
  1320. Routine Description:
  1321. Pack printer feature and option information into binary data
  1322. Arguments:
  1323. pParserData - Points to the parser data structure
  1324. Return Value:
  1325. NONE
  1326. --*/
  1327. {
  1328. PFEATUREOBJ pFeature;
  1329. PFEATURE pPackedFeature;
  1330. POPTIONOBJ pOption;
  1331. POPTION pPackedOption;
  1332. DWORD dwFeatureIndex, dwOptionIndex, dwCount;
  1333. VALIDATE_PARSER_DATA(pParserData);
  1334. //
  1335. // Reserve space in the binary data for an array of FEATURE structures
  1336. //
  1337. dwCount = pParserData->pInfoHdr->RawData.dwDocumentFeatures +
  1338. pParserData->pInfoHdr->RawData.dwPrinterFeatures;
  1339. VGrowPackBuffer(pParserData, dwCount * sizeof(FEATURE));
  1340. pPackedFeature = (PFEATURE) (pParserData->pubBufStart + pParserData->dwBufSize);
  1341. pParserData->pUIInfo->loFeatureList = pParserData->dwBufSize;
  1342. pParserData->dwBufSize += DWORD_ALIGN(dwCount * sizeof(FEATURE));
  1343. for (pFeature = pParserData->pFeatures, dwFeatureIndex = 0;
  1344. pFeature != NULL;
  1345. pFeature = pFeature->pNext, dwFeatureIndex++, pPackedFeature++)
  1346. {
  1347. PFEATUREDATA pFeatureData;
  1348. //
  1349. // Pack feature information
  1350. //
  1351. VPackStringAnsi(pParserData, &pPackedFeature->loKeywordName, pFeature->pstrName);
  1352. VPackStringXlation(pParserData,
  1353. &pPackedFeature->loDisplayName,
  1354. pFeature->pstrName,
  1355. &pFeature->Translation);
  1356. VPackInvocation(pParserData, &pPackedFeature->QueryInvocation, &pFeature->QueryInvoc);
  1357. pFeatureData = PGetFeatureData(pFeature->dwFeatureID);
  1358. pPackedFeature->dwFlags = pFeatureData->dwFlags;
  1359. pPackedFeature->dwOptionSize = pFeatureData->dwOptionSize;
  1360. pPackedFeature->dwFeatureID = pFeature->dwFeatureID;
  1361. pPackedFeature->dwUIType = pFeature->dwUIType;
  1362. pPackedFeature->dwUIConstraintList = pFeature->dwConstraint;
  1363. pPackedFeature->dwNoneFalseOptIndex = OPTION_INDEX_ANY;
  1364. if (pFeature->bInstallable)
  1365. {
  1366. pPackedFeature->dwPriority = pFeatureData->dwPriority + PRNPROP_BASE_PRIORITY;
  1367. pPackedFeature->dwFeatureType = FEATURETYPE_PRINTERPROPERTY;
  1368. }
  1369. else
  1370. {
  1371. ASSERT(pFeatureData->dwPriority < PRNPROP_BASE_PRIORITY);
  1372. pPackedFeature->dwPriority = pFeatureData->dwPriority;
  1373. pPackedFeature->dwFeatureType = FEATURETYPE_DOCPROPERTY;
  1374. }
  1375. //
  1376. // For non-PickMany features, use the very first option as the default
  1377. // if none is explicitly specified. Otherwise, default to OPTION_INDEX_ANY.
  1378. //
  1379. pPackedFeature->dwDefaultOptIndex =
  1380. (pFeature->dwUIType == UITYPE_PICKMANY) ? OPTION_INDEX_ANY : 0;
  1381. //
  1382. // If this feature is a predefined feature, save a reference to it
  1383. //
  1384. if (pFeature->dwFeatureID < MAX_GID)
  1385. {
  1386. pParserData->pUIInfo->aloPredefinedFeatures[pFeature->dwFeatureID] =
  1387. pParserData->pUIInfo->loFeatureList + (dwFeatureIndex * sizeof(FEATURE));
  1388. }
  1389. //
  1390. // Reserve space in the binary data for an array of OPTION structures
  1391. //
  1392. if ((dwCount = DwCountListItem(pFeature->pOptions)) == 0)
  1393. {
  1394. TERSE(("No options for feature: %s\n", pFeature->pstrName));
  1395. pPackedFeature->Options.loOffset = 0;
  1396. pPackedFeature->Options.dwCount = 0;
  1397. continue;
  1398. }
  1399. ASSERTMSG((dwCount < OPTION_INDEX_ANY),
  1400. ("Too many options for feature: %s\n", pFeature->pstrName));
  1401. VGrowPackBuffer(pParserData, dwCount * pFeatureData->dwOptionSize);
  1402. pPackedOption = (POPTION) (pParserData->pubBufStart + pParserData->dwBufSize);
  1403. pPackedFeature->Options.loOffset = pParserData->dwBufSize;
  1404. pPackedFeature->Options.dwCount = dwCount;
  1405. pParserData->dwBufSize += DWORD_ALIGN(dwCount * pFeatureData->dwOptionSize);
  1406. for (pOption = pFeature->pOptions, dwOptionIndex = 0;
  1407. pOption != NULL;
  1408. pOption = pOption->pNext, dwOptionIndex++)
  1409. {
  1410. BOOL bIsDefaultOption = FALSE; // TRUE if current option is default
  1411. //
  1412. // Pack option information
  1413. //
  1414. VPackStringAnsi(pParserData,
  1415. &pPackedOption->loKeywordName,
  1416. pOption->pstrName);
  1417. VPackStringXlation(pParserData,
  1418. &pPackedOption->loDisplayName,
  1419. pOption->pstrName,
  1420. &pOption->Translation);
  1421. VPackInvocation(pParserData,
  1422. &pPackedOption->Invocation,
  1423. &pOption->Invocation);
  1424. pPackedOption->dwUIConstraintList = pOption->dwConstraint;
  1425. //
  1426. // Check if the current option is the default option
  1427. // or if it's the None/False option
  1428. //
  1429. if (pFeature->pstrDefault &&
  1430. strcmp(pOption->pstrName, pFeature->pstrDefault) == EQUAL_STRING)
  1431. {
  1432. pPackedFeature->dwDefaultOptIndex = dwOptionIndex;
  1433. bIsDefaultOption = TRUE;
  1434. }
  1435. if (strcmp(pOption->pstrName, gstrNoneKwd) == EQUAL_STRING ||
  1436. strcmp(pOption->pstrName, gstrFalseKwd) == EQUAL_STRING)
  1437. {
  1438. pPackedFeature->dwNoneFalseOptIndex = dwOptionIndex;
  1439. }
  1440. //
  1441. // Handle extra fields after the generic OPTION structure
  1442. //
  1443. switch (pFeature->dwFeatureID)
  1444. {
  1445. case GID_PAGESIZE:
  1446. {
  1447. PPAGESIZE pPageSize = (PPAGESIZE) pPackedOption;
  1448. PPAPEROBJ pPaper = (PPAPEROBJ) pOption;
  1449. PRECT prect;
  1450. PSIZE psize;
  1451. if (strcmp(pOption->pstrName, gstrCustomSizeKwd) == EQUAL_STRING)
  1452. {
  1453. PPPDDATA pPpdData;
  1454. LONG lMax;
  1455. //
  1456. // Special case for CustomPageSize option
  1457. //
  1458. pPpdData = pParserData->pPpdData;
  1459. psize = &pPageSize->szPaperSize;
  1460. prect = &pPageSize->rcImgArea;
  1461. pPageSize->szPaperSize = pPaper->szDimension;
  1462. pPageSize->rcImgArea = pPaper->rcImageArea;
  1463. pPageSize->dwPaperSizeID = DMPAPER_CUSTOMSIZE;
  1464. VPackStringRsrc(pParserData,
  1465. &pPackedOption->loDisplayName,
  1466. IDS_PSCRIPT_CUSTOMSIZE);
  1467. //
  1468. // If either MaxMediaWidth or MaxMediaHeight is missing,
  1469. // we'll use the max width or height values from
  1470. // ParamCustomPageSize.
  1471. //
  1472. if (psize->cx <= 0)
  1473. psize->cx = MAXCUSTOMPARAM_WIDTH(pPpdData);
  1474. if (psize->cy <= 0)
  1475. psize->cy = MAXCUSTOMPARAM_HEIGHT(pPpdData);
  1476. if (psize->cx > 0 &&
  1477. psize->cy > 0 &&
  1478. MINCUSTOMPARAM_ORIENTATION(pPpdData) <= 3)
  1479. {
  1480. pParserData->pUIInfo->dwFlags |= FLAG_CUSTOMSIZE_SUPPORT;
  1481. pParserData->pUIInfo->dwCustomSizeOptIndex = dwOptionIndex;
  1482. //
  1483. // Make sure the hardware margins are not larger than
  1484. // the maximum media width or height.
  1485. //
  1486. // This is only significant for cut-sheet device.
  1487. //
  1488. if (pParserData->dwCustomSizeFlags & CUSTOMSIZE_CUTSHEET)
  1489. {
  1490. lMax = min(psize->cx, psize->cy);
  1491. if (prect->left < 0 || prect->left >= lMax)
  1492. prect->left = 0;
  1493. if (prect->right < 0 || prect->right >= lMax)
  1494. prect->right = 0;
  1495. if (prect->top < 0 || prect->top >= lMax)
  1496. prect->top = 0;
  1497. if (prect->bottom < 0 || prect->bottom >= lMax)
  1498. prect->bottom = 0;
  1499. }
  1500. //
  1501. // Validate custom page size parameters
  1502. //
  1503. if (MAXCUSTOMPARAM_WIDTH(pPpdData) > psize->cx)
  1504. MAXCUSTOMPARAM_WIDTH(pPpdData) = psize->cx;
  1505. if (MINCUSTOMPARAM_WIDTH(pPpdData) <= MICRONS_PER_INCH)
  1506. MINCUSTOMPARAM_WIDTH(pPpdData) = MICRONS_PER_INCH;
  1507. if (MAXCUSTOMPARAM_HEIGHT(pPpdData) > psize->cy)
  1508. MAXCUSTOMPARAM_HEIGHT(pPpdData) = psize->cy;
  1509. if (MINCUSTOMPARAM_HEIGHT(pPpdData) <= MICRONS_PER_INCH)
  1510. MINCUSTOMPARAM_HEIGHT(pPpdData) = MICRONS_PER_INCH;
  1511. }
  1512. }
  1513. else
  1514. {
  1515. psize = &pPaper->szDimension;
  1516. prect = &pPaper->rcImageArea;
  1517. if (strcmp(pOption->pstrName, gstrLetterSizeKwd) == EQUAL_STRING)
  1518. {
  1519. if ((abs(psize->cx - LETTER_PAPER_WIDTH) < 1000) &&
  1520. (abs(psize->cy - LETTER_PAPER_LENGTH) < 1000))
  1521. {
  1522. pParserData->pUIInfo->dwFlags |= FLAG_LETTER_SIZE_EXISTS;
  1523. }
  1524. }
  1525. else if (strcmp(pOption->pstrName, gstrA4SizeKwd) == EQUAL_STRING)
  1526. {
  1527. if ((abs(psize->cx - A4_PAPER_WIDTH) < 1000) &&
  1528. (abs(psize->cy - A4_PAPER_LENGTH) < 1000))
  1529. {
  1530. pParserData->pUIInfo->dwFlags |= FLAG_A4_SIZE_EXISTS;
  1531. }
  1532. }
  1533. //
  1534. // Verify paper dimension
  1535. //
  1536. if (psize->cx <= 0 || psize->cy <= 0)
  1537. {
  1538. SEMANTIC_ERROR(("Invalid PaperDimension for: %s\n",
  1539. pOption->pstrName));
  1540. psize->cx = DEFAULT_PAPER_WIDTH;
  1541. psize->cy = DEFAULT_PAPER_LENGTH;
  1542. }
  1543. pPageSize->szPaperSize = pPaper->szDimension;
  1544. //
  1545. // Verify imageable area
  1546. //
  1547. if (prect->left < 0 || prect->left >= prect->right ||
  1548. prect->bottom < 0|| prect->bottom >= prect->top ||
  1549. prect->right > psize->cx ||
  1550. prect->top > psize->cy)
  1551. {
  1552. SEMANTIC_ERROR(("Invalid ImageableArea for: %s\n",
  1553. pOption->pstrName));
  1554. prect->left = prect->bottom = 0;
  1555. prect->right = psize->cx;
  1556. prect->top = psize->cy;
  1557. }
  1558. //
  1559. // Convert from PS to GDI coordinate system
  1560. //
  1561. pPageSize->rcImgArea.left = prect->left;
  1562. pPageSize->rcImgArea.right = prect->right;
  1563. pPageSize->rcImgArea.top = psize->cy - prect->top;
  1564. pPageSize->rcImgArea.bottom = psize->cy - prect->bottom;
  1565. //
  1566. // Driver paper size ID starts at DRIVER_PAPERSIZE_ID
  1567. //
  1568. pPageSize->dwPaperSizeID = dwOptionIndex + DRIVER_PAPERSIZE_ID;
  1569. }
  1570. }
  1571. break;
  1572. case GID_RESOLUTION:
  1573. {
  1574. PRESOLUTION pResolution = (PRESOLUTION) pPackedOption;
  1575. PRESOBJ pResObj = (PRESOBJ) pOption;
  1576. PSTR pstr = pOption->pstrName;
  1577. LONG lXdpi, lYdpi;
  1578. BOOL bValid;
  1579. pResolution->iXdpi = pResolution->iYdpi = DEFAULT_RESOLUTION;
  1580. pResolution->fxScreenFreq = pResObj->fxScreenFreq;
  1581. pResolution->fxScreenAngle = pResObj->fxScreenAngle;
  1582. if (BGetIntegerFromString(&pstr, &lXdpi))
  1583. {
  1584. lYdpi = lXdpi;
  1585. while (*pstr && !IS_DIGIT(*pstr))
  1586. pstr++;
  1587. if ((*pstr == NUL || BGetIntegerFromString(&pstr, &lYdpi)) &&
  1588. (lXdpi > 0 && lXdpi <= MAX_SHORT) &&
  1589. (lYdpi > 0 && lYdpi <= MAX_SHORT))
  1590. {
  1591. pResolution->iXdpi = (INT) lXdpi;
  1592. pResolution->iYdpi = (INT) lYdpi;
  1593. bValid = TRUE;
  1594. }
  1595. }
  1596. if (! bValid)
  1597. SEMANTIC_ERROR(("Invalid resolution option: %s\n", pOption->pstrName));
  1598. }
  1599. break;
  1600. case GID_DUPLEX:
  1601. {
  1602. PDUPLEX pDuplex = (PDUPLEX) pPackedOption;
  1603. if (strcmp(pOption->pstrName, gstrDuplexTumble) == EQUAL_STRING)
  1604. {
  1605. //
  1606. // Horizontal == ShortEdge == Tumble
  1607. //
  1608. pDuplex->dwDuplexID = DMDUP_HORIZONTAL;
  1609. }
  1610. else if (strcmp(pOption->pstrName, gstrDuplexNoTumble) == EQUAL_STRING)
  1611. {
  1612. //
  1613. // Vertical == LongEdge == NoTumble
  1614. //
  1615. pDuplex->dwDuplexID = DMDUP_VERTICAL;
  1616. }
  1617. else
  1618. pDuplex->dwDuplexID = DMDUP_SIMPLEX;
  1619. }
  1620. break;
  1621. case GID_COLLATE:
  1622. {
  1623. PCOLLATE pCollate = (PCOLLATE) pPackedOption;
  1624. pCollate->dwCollateID =
  1625. (strcmp(pOption->pstrName, gstrTrueKwd) == EQUAL_STRING ||
  1626. strcmp(pOption->pstrName, gstrOnKwd) == EQUAL_STRING) ?
  1627. DMCOLLATE_TRUE :
  1628. DMCOLLATE_FALSE;
  1629. }
  1630. break;
  1631. case GID_MEDIATYPE:
  1632. ((PMEDIATYPE) pPackedOption)->dwMediaTypeID = dwOptionIndex + DMMEDIA_USER;
  1633. break;
  1634. case GID_INPUTSLOT:
  1635. {
  1636. PINPUTSLOT pInputSlot = (PINPUTSLOT) pPackedOption;
  1637. PTRAYOBJ pTray = (PTRAYOBJ) pOption;
  1638. DWORD dwReqPageRgn;
  1639. if ((dwReqPageRgn = pTray->dwReqPageRgn) == REQRGN_UNKNOWN)
  1640. dwReqPageRgn = pParserData->dwReqPageRgn;
  1641. if (dwReqPageRgn != REQRGN_FALSE)
  1642. pInputSlot->dwFlags |= INPUTSLOT_REQ_PAGERGN;
  1643. //
  1644. // Special handling of predefined input slots:
  1645. // ManualFeed and AutoSelect
  1646. //
  1647. switch (pTray->dwTrayIndex)
  1648. {
  1649. case DMBIN_FORMSOURCE:
  1650. pInputSlot->dwPaperSourceID = pTray->dwTrayIndex;
  1651. break;
  1652. case DMBIN_MANUAL:
  1653. pInputSlot->dwPaperSourceID = pTray->dwTrayIndex;
  1654. VPackStringRsrc(pParserData,
  1655. &pPackedOption->loDisplayName,
  1656. IDS_TRAY_MANUALFEED);
  1657. break;
  1658. default:
  1659. pInputSlot->dwPaperSourceID = dwOptionIndex + DMBIN_USER;
  1660. break;
  1661. }
  1662. }
  1663. break;
  1664. case GID_OUTPUTBIN:
  1665. {
  1666. PBINOBJ pBinObj = (PBINOBJ) pOption;
  1667. //
  1668. // if this is the default bin, set the default output order, if specified
  1669. // by the DefaultOutputOrder entry in the PPD-file
  1670. //
  1671. if (bIsDefaultOption && pParserData->bDefOutputOrderSet)
  1672. {
  1673. //
  1674. // If multiple bins: warn if different options specified
  1675. //
  1676. if ((dwCount > 1) &&
  1677. (pBinObj->bReversePrint != pParserData->bDefReversePrint))
  1678. {
  1679. TERSE(("Warning: explicit *DefaultPageOrder overwrites PageStackOrder of OutputBin\n"));
  1680. }
  1681. ((POUTPUTBIN) pPackedOption)->bOutputOrderReversed = pParserData->bDefReversePrint;
  1682. }
  1683. else
  1684. {
  1685. //
  1686. // for non-default bins, the default output order has no effect - the PPD spec says
  1687. // "*DefaultOutputOrder indicates the default stacking order of the default output bin."
  1688. //
  1689. ((POUTPUTBIN) pPackedOption)->bOutputOrderReversed = pBinObj->bReversePrint;
  1690. }
  1691. }
  1692. break;
  1693. case GID_MEMOPTION:
  1694. {
  1695. PMEMOPTION pMemOption = (PMEMOPTION) pPackedOption;
  1696. PMEMOBJ pMemObj = (PMEMOBJ) pOption;
  1697. DWORD dwMinFreeMem;
  1698. //
  1699. // Store PPD's original *VMOption value into dwInstalledMem.
  1700. // This is only used for the new PPD helper function GetOptionAttribute().
  1701. // (see comments in inc\parser.h)
  1702. //
  1703. pMemOption->dwInstalledMem = pMemObj->dwFreeVM;
  1704. dwMinFreeMem = pParserData->dwLangLevel <= 1 ? MIN_FREEMEM_L1 : MIN_FREEMEM_L2;
  1705. if (pMemObj->dwFreeVM < dwMinFreeMem)
  1706. {
  1707. SEMANTIC_ERROR(("Invalid memory option: %s\n", pOption->pstrName));
  1708. pMemObj->dwFreeVM = dwMinFreeMem;
  1709. }
  1710. pMemOption->dwFreeMem = pMemObj->dwFreeVM;
  1711. pMemOption->dwFreeFontMem = pMemObj->dwFontMem;
  1712. }
  1713. break;
  1714. case GID_LEADINGEDGE:
  1715. if (strcmp(pOption->pstrName, gstrLongKwd) == EQUAL_STRING)
  1716. {
  1717. pParserData->pPpdData->dwLeadingEdgeLong = dwOptionIndex;
  1718. if (dwOptionIndex == pPackedFeature->dwDefaultOptIndex)
  1719. pParserData->pPpdData->dwCustomSizeFlags &= ~CUSTOMSIZE_SHORTEDGEFEED;
  1720. }
  1721. else if (strcmp(pOption->pstrName, gstrShortKwd) == EQUAL_STRING)
  1722. {
  1723. pParserData->pPpdData->dwLeadingEdgeShort = dwOptionIndex;
  1724. if (dwOptionIndex == pPackedFeature->dwDefaultOptIndex)
  1725. pParserData->pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_SHORTEDGEFEED;
  1726. }
  1727. break;
  1728. case GID_USEHWMARGINS:
  1729. if (strcmp(pOption->pstrName, gstrTrueKwd) == EQUAL_STRING)
  1730. {
  1731. pParserData->pPpdData->dwUseHWMarginsTrue = dwOptionIndex;
  1732. pParserData->pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_CUTSHEET;
  1733. if (dwOptionIndex == pPackedFeature->dwDefaultOptIndex)
  1734. pParserData->pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_DEFAULTCUTSHEET;
  1735. }
  1736. else if (strcmp(pOption->pstrName, gstrFalseKwd) == EQUAL_STRING)
  1737. {
  1738. pParserData->pPpdData->dwUseHWMarginsFalse = dwOptionIndex;
  1739. pParserData->pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_ROLLFED;
  1740. if (dwOptionIndex == pPackedFeature->dwDefaultOptIndex)
  1741. pParserData->pPpdData->dwCustomSizeFlags &= ~CUSTOMSIZE_DEFAULTCUTSHEET;
  1742. }
  1743. break;
  1744. }
  1745. pPackedOption = (POPTION) ((PBYTE) pPackedOption + pFeatureData->dwOptionSize);
  1746. }
  1747. }
  1748. }
  1749. VOID
  1750. VPackNt4Mapping(
  1751. PPARSERDATA pParserData
  1752. )
  1753. /*++
  1754. Routine Description:
  1755. Pack NT4 feature index mapping information
  1756. Arguments:
  1757. pParserData - Points to the parser data structure
  1758. Return Value:
  1759. NONE
  1760. --*/
  1761. {
  1762. PPPDDATA pPpdData;
  1763. PFEATURE pPackedFeatures;
  1764. PBYTE pubNt4Mapping;
  1765. DWORD dwCount, dwIndex, dwNt4Index;
  1766. INT iInputSlotIndex;
  1767. BYTE ubInputSlotOld, ubInputSlotNew;
  1768. pPpdData = pParserData->pPpdData;
  1769. pPpdData->dwNt4Checksum = pParserData->wNt4Checksum;
  1770. pPpdData->dwNt4DocFeatures = pParserData->pUIInfo->dwDocumentFeatures;
  1771. pPpdData->dwNt4PrnFeatures = pParserData->pUIInfo->dwPrinterFeatures;
  1772. iInputSlotIndex = -1;
  1773. ubInputSlotNew = 0xff;
  1774. if (pParserData->iDefInstallMemIndex >= 0)
  1775. pParserData->iDefInstallMemIndex += pPpdData->dwNt4DocFeatures;
  1776. dwCount = pPpdData->dwNt4DocFeatures + pPpdData->dwNt4PrnFeatures;
  1777. pPpdData->Nt4Mapping.dwCount = dwCount;
  1778. VGrowPackBuffer(pParserData, dwCount * sizeof(BYTE));
  1779. pubNt4Mapping = (PBYTE) (pParserData->pubBufStart + pParserData->dwBufSize);
  1780. pPpdData->Nt4Mapping.loOffset = pParserData->dwBufSize;
  1781. pParserData->dwBufSize += DWORD_ALIGN(dwCount * sizeof(BYTE));
  1782. pPackedFeatures = (PFEATURE) (pParserData->pubBufStart + pParserData->pUIInfo->loFeatureList);
  1783. for (dwIndex=dwNt4Index=0; dwIndex <= dwCount; dwIndex++)
  1784. {
  1785. BOOL bMapped = TRUE;
  1786. //
  1787. // ManualFeed used to be a feature in NT4,
  1788. // but not anymore in NT5
  1789. //
  1790. if (pParserData->iReqPageRgnIndex == (INT) dwIndex)
  1791. ubInputSlotNew = (BYTE) dwNt4Index;
  1792. if (pParserData->iManualFeedIndex == (INT) dwIndex)
  1793. {
  1794. pPpdData->dwNt4DocFeatures++;
  1795. dwNt4Index++;
  1796. }
  1797. //
  1798. // DefaultInstalledMemory causes a bogus feature to be added on NT4
  1799. //
  1800. if (pParserData->iDefInstallMemIndex == (INT) dwIndex)
  1801. {
  1802. pPpdData->dwNt4PrnFeatures++;
  1803. dwNt4Index++;
  1804. }
  1805. if (dwIndex == dwCount)
  1806. break;
  1807. switch (pPackedFeatures[dwIndex].dwFeatureID)
  1808. {
  1809. case GID_MEDIATYPE:
  1810. case GID_OUTPUTBIN:
  1811. // a feature in NT4 only if within Open/CloseUI
  1812. if (pParserData->aubOpenUIFeature[pPackedFeatures[dwIndex].dwFeatureID])
  1813. break;
  1814. // fall through
  1815. case GID_PAGEREGION:
  1816. case GID_LEADINGEDGE:
  1817. case GID_USEHWMARGINS:
  1818. // not a feature in NT4
  1819. bMapped = FALSE;
  1820. break;
  1821. case GID_INPUTSLOT:
  1822. iInputSlotIndex = dwIndex;
  1823. break;
  1824. }
  1825. if (bMapped)
  1826. {
  1827. pubNt4Mapping[dwIndex] = (BYTE) dwNt4Index;
  1828. dwNt4Index++;
  1829. }
  1830. else
  1831. {
  1832. pPpdData->dwNt4DocFeatures--;
  1833. pubNt4Mapping[dwIndex] = 0xff;
  1834. }
  1835. }
  1836. //
  1837. // RequiresPageRegion causes InputSlot feature to be created on NT4
  1838. //
  1839. if (iInputSlotIndex >= 0 && pParserData->iReqPageRgnIndex >= 0)
  1840. {
  1841. ubInputSlotOld = pubNt4Mapping[iInputSlotIndex];
  1842. if (ubInputSlotOld > ubInputSlotNew)
  1843. {
  1844. for (dwIndex=0; dwIndex < dwCount; dwIndex++)
  1845. {
  1846. if (pubNt4Mapping[dwIndex] >= ubInputSlotNew &&
  1847. pubNt4Mapping[dwIndex] < ubInputSlotOld)
  1848. {
  1849. pubNt4Mapping[dwIndex]++;
  1850. }
  1851. }
  1852. }
  1853. else if (ubInputSlotOld < ubInputSlotNew)
  1854. {
  1855. for (dwIndex=0; dwIndex < dwCount; dwIndex++)
  1856. {
  1857. if (pubNt4Mapping[dwIndex] > ubInputSlotOld &&
  1858. pubNt4Mapping[dwIndex] <= ubInputSlotNew)
  1859. {
  1860. pubNt4Mapping[dwIndex]--;
  1861. }
  1862. }
  1863. }
  1864. pubNt4Mapping[iInputSlotIndex] = ubInputSlotNew;
  1865. }
  1866. }
  1867. VOID
  1868. VPackDeviceFonts(
  1869. PPARSERDATA pParserData
  1870. )
  1871. /*++
  1872. Routine Description:
  1873. Pack device font information into binary data
  1874. Arguments:
  1875. pParserData - Points to the parser data structure
  1876. Return Value:
  1877. NONE
  1878. --*/
  1879. {
  1880. PDEVFONT pDevFont;
  1881. PFONTREC pFontObj;
  1882. DWORD dwIndex, dwFonts;
  1883. VALIDATE_PARSER_DATA(pParserData);
  1884. //
  1885. // Count the number of device fonts and
  1886. // reserve enough space in the packed binary data
  1887. //
  1888. if ((dwFonts = DwCountListItem(pParserData->pFonts)) == 0)
  1889. return;
  1890. VGrowPackBuffer(pParserData, dwFonts * sizeof(DEVFONT));
  1891. pParserData->pPpdData->DeviceFonts.dwCount = dwFonts;
  1892. pParserData->pPpdData->DeviceFonts.loOffset = pParserData->dwBufSize;
  1893. pDevFont = (PDEVFONT) (pParserData->pubBufStart + pParserData->dwBufSize);
  1894. pParserData->dwBufSize += DWORD_ALIGN(dwFonts * sizeof(DEVFONT));
  1895. //
  1896. // Pack information about each device font
  1897. //
  1898. for (pFontObj = pParserData->pFonts;
  1899. pFontObj != NULL;
  1900. pFontObj = pFontObj->pNext)
  1901. {
  1902. VPackStringAnsi(pParserData, &pDevFont->loFontName, pFontObj->pstrName);
  1903. VPackStringXlation(pParserData,
  1904. &pDevFont->loDisplayName,
  1905. pFontObj->pstrName,
  1906. &pFontObj->Translation);
  1907. VPackStringAnsi(pParserData, &pDevFont->loEncoding, pFontObj->pstrEncoding);
  1908. VPackStringAnsi(pParserData, &pDevFont->loCharset, pFontObj->pstrCharset);
  1909. VPackStringAnsi(pParserData, &pDevFont->loVersion, pFontObj->pstrVersion);
  1910. pDevFont->dwStatus = pFontObj->dwStatus;
  1911. pDevFont++;
  1912. }
  1913. //
  1914. // Calculate the byte-offset to the default DEVFONT structure (if any)
  1915. //
  1916. if (pParserData->pstrDefaultFont &&
  1917. PvFindListItem(pParserData->pFonts, pParserData->pstrDefaultFont, &dwIndex))
  1918. {
  1919. pParserData->pPpdData->loDefaultFont = pParserData->pPpdData->DeviceFonts.loOffset +
  1920. (dwIndex * sizeof(DEVFONT));
  1921. }
  1922. }
  1923. VOID
  1924. VPackJobPatchFiles(
  1925. PPARSERDATA pParserData
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. Pack *JobPatchFile information into binary data
  1930. Arguments:
  1931. pParserData - Points to the parser data structure
  1932. Return Value:
  1933. NONE
  1934. --*/
  1935. {
  1936. PJOBPATCHFILE pPackedPatch;
  1937. PJOBPATCHFILEOBJ pJobPatchFile;
  1938. DWORD dwJobPatchFiles;
  1939. VALIDATE_PARSER_DATA(pParserData);
  1940. //
  1941. // Count the number of *JobPatchFile entries
  1942. //
  1943. dwJobPatchFiles = DwCountListItem((PVOID) pParserData->pJobPatchFiles);
  1944. if (dwJobPatchFiles > 0)
  1945. {
  1946. //
  1947. // Reserve enough space in the packed binary data
  1948. //
  1949. VGrowPackBuffer(pParserData, dwJobPatchFiles * sizeof(JOBPATCHFILE));
  1950. pParserData->pPpdData->JobPatchFiles.dwCount = dwJobPatchFiles;
  1951. pParserData->pPpdData->JobPatchFiles.loOffset = pParserData->dwBufSize;
  1952. pPackedPatch = (PJOBPATCHFILE) (pParserData->pubBufStart + pParserData->dwBufSize);
  1953. pParserData->dwBufSize += DWORD_ALIGN(dwJobPatchFiles * sizeof(JOBPATCHFILE));
  1954. //
  1955. // Pack each *JobPatchFile invocation string
  1956. //
  1957. for (pJobPatchFile = pParserData->pJobPatchFiles;
  1958. pJobPatchFile != NULL;
  1959. pJobPatchFile = pJobPatchFile->pNext)
  1960. {
  1961. VPackPatch(pParserData, pPackedPatch, pJobPatchFile);
  1962. pPackedPatch++;
  1963. }
  1964. }
  1965. }
  1966. typedef struct _TTFSUBSTRESINFO
  1967. {
  1968. BOOL bCJK;
  1969. WORD wIDBegin;
  1970. WORD wIDEnd;
  1971. }
  1972. TTFSUBSTRESINFO;
  1973. static TTFSUBSTRESINFO TTFSubstResInfo[] =
  1974. {
  1975. { FALSE, IDS_1252_BEGIN, IDS_1252_END},
  1976. { TRUE, IDS_932_BEGIN, IDS_932_END},
  1977. { TRUE, IDS_936_BEGIN, IDS_936_END},
  1978. { TRUE, IDS_949_BEGIN, IDS_949_END},
  1979. };
  1980. VOID
  1981. VPackDefaultTrueTypeSubstTable(
  1982. PPARSERDATA pParserData
  1983. )
  1984. /*++
  1985. Routine Description:
  1986. Pack the default TrueType font substitution table into the binary data
  1987. Arguments:
  1988. pParserData - Points to the parser data structure
  1989. Return Value:
  1990. NONE
  1991. --*/
  1992. #define MAX_FONT_NAME 256
  1993. {
  1994. INT iNumInfo, iInfo, iCount, iLenTT, iLenPS, i;
  1995. DWORD dwSize, dwLeft, dw;
  1996. TCHAR tchBuf[MAX_FONT_NAME];
  1997. PTSTR ptstrTable;
  1998. HRSRC hrRcData;
  1999. HGLOBAL hgRcData;
  2000. PWORD pwRcData;
  2001. VALIDATE_PARSER_DATA(pParserData);
  2002. //
  2003. // Calculate how much memory we need to hold the default TrueType to
  2004. // PostScript substitution names. The counter is initialized to 1, instead
  2005. // of 0, for the last NUL terminator. Count the names from the STRING
  2006. // resource, then from RCDATA resource.
  2007. //
  2008. //
  2009. dwSize = 1;
  2010. iNumInfo = sizeof(TTFSubstResInfo) / sizeof(TTFSUBSTRESINFO);
  2011. for (iInfo = 0; iInfo < iNumInfo; iInfo++)
  2012. {
  2013. iCount = TTFSubstResInfo[iInfo].wIDEnd - TTFSubstResInfo[iInfo].wIDBegin + 1;
  2014. for (i = 0; i < iCount; i++)
  2015. {
  2016. iLenTT = LoadString(ghInstance,
  2017. TTFSubstResInfo[iInfo].wIDBegin + i,
  2018. tchBuf, MAX_FONT_NAME);
  2019. if (iLenTT == 0)
  2020. {
  2021. ERR(("VPackDefaultTrueTypeSubstTable: load TT string failed: %d\n", GetLastError()));
  2022. return;
  2023. }
  2024. iLenPS = LoadString(ghInstance,
  2025. TTFSubstResInfo[iInfo].wIDBegin + i + TT2PS_INTERVAL,
  2026. tchBuf, MAX_FONT_NAME);
  2027. if (iLenPS == 0)
  2028. {
  2029. ERR(("VPackDefaultTrueTypeSubstTable: load PS string failed: %d\n", GetLastError()));
  2030. return;
  2031. }
  2032. dwSize += (iLenTT + 1) + (iLenPS + 1);
  2033. if (TTFSubstResInfo[iInfo].bCJK == TRUE)
  2034. {
  2035. // We need names beginning with '@' too for CJK.
  2036. dwSize += (1 + iLenTT + 1) + (1 + iLenPS + 1);
  2037. }
  2038. }
  2039. if (TTFSubstResInfo[iInfo].bCJK == TRUE)
  2040. {
  2041. hrRcData = FindResource(ghInstance, (LPCTSTR)TTFSubstResInfo[iInfo].wIDBegin, RT_RCDATA);
  2042. if (hrRcData == NULL)
  2043. {
  2044. ERR(("VPackDefaultTrueTypeSubstTable: find RCDATA failed: %d\n", GetLastError()));
  2045. return;
  2046. }
  2047. // Load the resource and get its size.
  2048. hgRcData = LoadResource(ghInstance, hrRcData);
  2049. if (hgRcData == NULL)
  2050. {
  2051. ERR(("VPackDefaultTrueTypeSubstTable: load RCDATA failed: %d\n", GetLastError()));
  2052. return;
  2053. }
  2054. // The first WORD of the IDR resource tells the size of the strings.
  2055. pwRcData = (PWORD)LockResource(hgRcData);
  2056. if (pwRcData == NULL)
  2057. {
  2058. ERR(("VPackDefaultTrueTypeSubstTable: lock RCDATA failed: %d\n", GetLastError()));
  2059. return;
  2060. }
  2061. dw = *pwRcData;
  2062. if (dw % 2)
  2063. {
  2064. ERR(("VPackDefaultTrueTypeSubstTable: RCDATA size is odd.\n"));
  2065. return;
  2066. }
  2067. dwSize += dw / 2;
  2068. }
  2069. }
  2070. //
  2071. // Reserve enough space in the packed binary data
  2072. //
  2073. dwSize *= sizeof(TCHAR);
  2074. VGrowPackBuffer(pParserData, dwSize);
  2075. ptstrTable = (PTSTR) (pParserData->pubBufStart + pParserData->dwBufSize);
  2076. pParserData->pUIInfo->loFontSubstTable = pParserData->dwBufSize;
  2077. pParserData->pUIInfo->dwFontSubCount = dwSize;
  2078. pParserData->dwBufSize += DWORD_ALIGN(dwSize);
  2079. //
  2080. // Save the default substitution table in the binary data
  2081. //
  2082. dwLeft = dwSize;
  2083. for (iInfo = 0; iInfo < iNumInfo; iInfo++)
  2084. {
  2085. iCount = TTFSubstResInfo[iInfo].wIDEnd - TTFSubstResInfo[iInfo].wIDBegin + 1;
  2086. for (i = 0; i < iCount; i++)
  2087. {
  2088. iLenTT = LoadString(ghInstance,
  2089. TTFSubstResInfo[iInfo].wIDBegin + i,
  2090. ptstrTable, dwLeft);
  2091. if (iLenTT == 0)
  2092. {
  2093. ERR(("VPackDefaultTrueTypeSubstTable: load TT string failed: %d\n", GetLastError()));
  2094. goto fail_cleanup;
  2095. }
  2096. ptstrTable += iLenTT + 1;
  2097. dwLeft -= (iLenTT + 1) * sizeof (TCHAR);
  2098. iLenPS = LoadString(ghInstance,
  2099. TTFSubstResInfo[iInfo].wIDBegin + i + TT2PS_INTERVAL,
  2100. ptstrTable, dwLeft);
  2101. if (iLenPS == 0)
  2102. {
  2103. ERR(("VPackDefaultTrueTypeSubstTable: load PS string failed: %d\n", GetLastError()));
  2104. goto fail_cleanup;
  2105. }
  2106. ptstrTable += iLenPS + 1;
  2107. dwLeft -= (iLenPS + 1) * sizeof (TCHAR);
  2108. if (TTFSubstResInfo[iInfo].bCJK == TRUE)
  2109. {
  2110. // We need names beginning with '@' too for CJK.
  2111. *ptstrTable++ = L'@';
  2112. dwLeft -= sizeof (TCHAR);
  2113. if (!LoadString(ghInstance, TTFSubstResInfo[iInfo].wIDBegin + i,
  2114. ptstrTable, dwLeft))
  2115. {
  2116. ERR(("VPackDefaultTrueTypeSubstTable: load TT string failed: %d\n", GetLastError()));
  2117. goto fail_cleanup;
  2118. }
  2119. ptstrTable += iLenTT + 1;
  2120. dwLeft -= (iLenTT + 1) * sizeof (TCHAR);
  2121. *ptstrTable++ = L'@';
  2122. dwLeft -= sizeof (TCHAR);
  2123. if (!LoadString(ghInstance, TTFSubstResInfo[iInfo].wIDBegin + i + TT2PS_INTERVAL,
  2124. ptstrTable, dwLeft))
  2125. {
  2126. ERR(("VPackDefaultTrueTypeSubstTable: load PS string failed: %d\n", GetLastError()));
  2127. goto fail_cleanup;
  2128. }
  2129. ptstrTable += iLenPS + 1;
  2130. dwLeft -= (iLenPS + 1) * sizeof (TCHAR);
  2131. }
  2132. }
  2133. if (TTFSubstResInfo[iInfo].bCJK == TRUE)
  2134. {
  2135. hrRcData = FindResource(ghInstance, (LPCTSTR)TTFSubstResInfo[iInfo].wIDBegin, RT_RCDATA);
  2136. if (hrRcData == NULL)
  2137. {
  2138. ERR(("VPackDefaultTrueTypeSubstTable: find RCDATA failed: %d\n", GetLastError()));
  2139. goto fail_cleanup;
  2140. }
  2141. hgRcData = LoadResource(ghInstance, hrRcData);
  2142. if (hgRcData == NULL)
  2143. {
  2144. ERR(("VPackDefaultTrueTypeSubstTable: load RCDATA failed: %d\n", GetLastError()));
  2145. goto fail_cleanup;
  2146. }
  2147. pwRcData = (PWORD)LockResource(hgRcData);
  2148. if (pwRcData == NULL)
  2149. {
  2150. ERR(("VPackDefaultTrueTypeSubstTable: lock RCDATA failed: %d\n", GetLastError()));
  2151. goto fail_cleanup;
  2152. }
  2153. dw = *pwRcData++;
  2154. if (dw % 2)
  2155. {
  2156. ERR(("VPackDefaultTrueTypeSubstTable: RCDATA size is odd.\n"));
  2157. goto fail_cleanup;
  2158. }
  2159. memcpy(ptstrTable, pwRcData, dw);
  2160. ptstrTable += dw / 2;
  2161. dwLeft -= dw;
  2162. }
  2163. }
  2164. //
  2165. // Succeed
  2166. //
  2167. return;
  2168. //
  2169. // Fail
  2170. //
  2171. fail_cleanup:
  2172. pParserData->pUIInfo->loFontSubstTable = 0;
  2173. pParserData->pUIInfo->dwFontSubCount = 0;
  2174. }
  2175. VOID
  2176. VPackTrueTypeSubstTable(
  2177. PPARSERDATA pParserData
  2178. )
  2179. /*++
  2180. Routine Description:
  2181. Pack the TrueType font substitution table into the binary data
  2182. Arguments:
  2183. pParserData - Points to the parser data structure
  2184. Return Value:
  2185. NONE
  2186. --*/
  2187. {
  2188. PTTFONTSUB pTTFontSub;
  2189. DWORD dwSize;
  2190. PTSTR ptstrTable, ptstrStart;
  2191. //
  2192. // Figure out how much space we'll need to store the font substitution table.
  2193. // This is an estimate and may be a little higher than what we actually need.
  2194. //
  2195. ASSERT(pParserData->pTTFontSubs != NULL);
  2196. for (pTTFontSub = pParserData->pTTFontSubs, dwSize = 1;
  2197. pTTFontSub != NULL;
  2198. pTTFontSub = pTTFontSub->pNext)
  2199. {
  2200. if (pTTFontSub->Translation.dwLength)
  2201. dwSize += pTTFontSub->Translation.dwLength + 1;
  2202. else
  2203. dwSize += strlen(pTTFontSub->pstrName) + 1;
  2204. dwSize += pTTFontSub->PSName.dwLength + 1;
  2205. }
  2206. //
  2207. // Reserve enough space in the packed binary data
  2208. //
  2209. dwSize *= sizeof(TCHAR);
  2210. VGrowPackBuffer(pParserData, dwSize);
  2211. ptstrStart = ptstrTable = (PTSTR) (pParserData->pubBufStart + pParserData->dwBufSize);
  2212. pParserData->pUIInfo->loFontSubstTable = pParserData->dwBufSize;
  2213. pParserData->dwBufSize += DWORD_ALIGN(dwSize);
  2214. for (pTTFontSub = pParserData->pTTFontSubs;
  2215. pTTFontSub != NULL;
  2216. pTTFontSub = pTTFontSub->pNext)
  2217. {
  2218. INT iChars;
  2219. //
  2220. // TrueType font family name
  2221. //
  2222. if (pTTFontSub->Translation.dwLength)
  2223. {
  2224. iChars = ITranslateToUnicodeString(
  2225. ptstrTable,
  2226. pTTFontSub->Translation.pvData,
  2227. pTTFontSub->Translation.dwLength,
  2228. pParserData->uCodePage);
  2229. }
  2230. else
  2231. {
  2232. iChars = ITranslateToUnicodeString(
  2233. ptstrTable,
  2234. pTTFontSub->pstrName,
  2235. strlen(pTTFontSub->pstrName),
  2236. 1252);
  2237. }
  2238. if (iChars <= 0)
  2239. break;
  2240. ptstrTable += iChars + 1;
  2241. //
  2242. // PS font family name
  2243. //
  2244. iChars = ITranslateToUnicodeString(
  2245. ptstrTable,
  2246. pTTFontSub->PSName.pvData,
  2247. pTTFontSub->PSName.dwLength,
  2248. pParserData->uCodePage);
  2249. if (iChars <= 0)
  2250. break;
  2251. ptstrTable += iChars + 1;
  2252. }
  2253. if (pTTFontSub != NULL)
  2254. {
  2255. ERR(("Error packing font substitution table\n"));
  2256. ptstrTable = ptstrStart;
  2257. }
  2258. *ptstrTable++ = NUL;
  2259. pParserData->pUIInfo->dwFontSubCount = (DWORD)(ptstrTable - ptstrStart) * sizeof(TCHAR);
  2260. }
  2261. VOID
  2262. VPackFileDateInfo(
  2263. PPARSERDATA pParserData
  2264. )
  2265. /*++
  2266. Routine Description:
  2267. Pack source PPD filenames and dates
  2268. Arguments:
  2269. pParserData - Points to parser data structure
  2270. Return Value:
  2271. NONE
  2272. --*/
  2273. {
  2274. PRAWBINARYDATA pRawData;
  2275. DWORD dwCount;
  2276. PFILEDATEINFO pFileDateInfo;
  2277. PTSTR ptstrFullname;
  2278. PLISTOBJ pItem;
  2279. HANDLE hFile;
  2280. pRawData = &pParserData->pInfoHdr->RawData;
  2281. dwCount = DwCountListItem(pParserData->pPpdFileNames);
  2282. if (pRawData->FileDateInfo.dwCount = dwCount)
  2283. {
  2284. VGrowPackBuffer(pParserData, dwCount * sizeof(FILEDATEINFO));
  2285. pRawData->FileDateInfo.loOffset = pParserData->dwBufSize;
  2286. pFileDateInfo = (PFILEDATEINFO) (pParserData->pubBufStart + pParserData->dwBufSize);
  2287. pParserData->dwBufSize += DWORD_ALIGN(dwCount * sizeof(FILEDATEINFO));
  2288. for (pItem = pParserData->pPpdFileNames; pItem; pItem = pItem->pNext)
  2289. {
  2290. dwCount--;
  2291. ptstrFullname = (PTSTR) pItem->pstrName;
  2292. VPackStringUnicode(pParserData,
  2293. &pFileDateInfo[dwCount].loFileName,
  2294. ptstrFullname);
  2295. hFile = CreateFile(ptstrFullname,
  2296. GENERIC_READ,
  2297. FILE_SHARE_READ,
  2298. NULL,
  2299. OPEN_EXISTING,
  2300. FILE_ATTRIBUTE_NORMAL | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
  2301. NULL);
  2302. if ((hFile == INVALID_HANDLE_VALUE) ||
  2303. !GetFileTime(hFile, NULL, NULL, &pFileDateInfo[dwCount].FileTime))
  2304. {
  2305. ERR(("GetFileTime '%ws' failed: %d\n", ptstrFullname, GetLastError()));
  2306. GetSystemTimeAsFileTime(&pFileDateInfo[dwCount].FileTime);
  2307. }
  2308. if (hFile != INVALID_HANDLE_VALUE)
  2309. CloseHandle(hFile);
  2310. }
  2311. }
  2312. }
  2313. VOID
  2314. VMapLangEncodingToCodePage(
  2315. PPARSERDATA pParserData
  2316. )
  2317. /*++
  2318. Routine Description:
  2319. Map LanguageEncoding to code page
  2320. Arguments:
  2321. pParserData - Points to parser data structure
  2322. Return Value:
  2323. NONE
  2324. --*/
  2325. {
  2326. UINT uCodePage = CP_ACP;
  2327. CPINFO cpinfo;
  2328. switch (pParserData->dwLangEncoding)
  2329. {
  2330. case LANGENC_ISOLATIN1:
  2331. uCodePage = 1252;
  2332. break;
  2333. case LANGENC_JIS83_RKSJ:
  2334. uCodePage = 932;
  2335. break;
  2336. case LANGENC_UNICODE:
  2337. uCodePage = CP_UNICODE;
  2338. break;
  2339. case LANGENC_NONE:
  2340. break;
  2341. default:
  2342. RIP(("Unknown language encoding: %d\n", pParserData->dwLangEncoding));
  2343. break;
  2344. }
  2345. //
  2346. // Make sure the requested code page is available
  2347. //
  2348. if (uCodePage != CP_UNICODE &&
  2349. uCodePage != CP_ACP &&
  2350. !GetCPInfo(uCodePage, &cpinfo))
  2351. {
  2352. WARNING(("Code page %d is not available\n", uCodePage));
  2353. uCodePage = CP_ERROR;
  2354. }
  2355. pParserData->uCodePage = uCodePage;
  2356. }
  2357. BOOL
  2358. BPackBinaryData(
  2359. PPARSERDATA pParserData
  2360. )
  2361. /*++
  2362. Routine Description:
  2363. Pack the parsed PPD information into binary format
  2364. Arguments:
  2365. pParserData - Points to parser data structure
  2366. Return Value:
  2367. TRUE if successful, FALSE if there is an error
  2368. --*/
  2369. {
  2370. DWORD dwSize;
  2371. DWORD dwMinFreeMem;
  2372. BOOL bResult = FALSE;
  2373. VALIDATE_PARSER_DATA(pParserData);
  2374. __try
  2375. {
  2376. //
  2377. // Quick-access pointers to various data structures.
  2378. //
  2379. PINFOHEADER pInfoHdr;
  2380. PUIINFO pUIInfo;
  2381. PPPDDATA pPpdData;
  2382. //
  2383. // Pack fixed header data structures
  2384. //
  2385. dwSize = sizeof(INFOHEADER) + sizeof(UIINFO) + sizeof(PPDDATA);
  2386. VGrowPackBuffer(pParserData, dwSize);
  2387. pParserData->dwBufSize = DWORD_ALIGN(dwSize);
  2388. pInfoHdr = pParserData->pInfoHdr;
  2389. pUIInfo = pParserData->pUIInfo;
  2390. pPpdData = pParserData->pPpdData;
  2391. pInfoHdr->RawData.dwParserSignature = PPD_PARSER_SIGNATURE;
  2392. pInfoHdr->RawData.dwParserVersion = PPD_PARSER_VERSION;
  2393. #if 0
  2394. pInfoHdr->RawData.dwChecksum32 = pParserData->dwChecksum32;
  2395. #endif
  2396. pInfoHdr->loUIInfoOffset = sizeof(INFOHEADER);
  2397. pInfoHdr->loDriverOffset = sizeof(INFOHEADER) + sizeof(UIINFO);
  2398. //
  2399. // Pack source PPD filenames and dates
  2400. //
  2401. VPackFileDateInfo(pParserData);
  2402. //
  2403. // Perform a few miscellaneous checks
  2404. //
  2405. if (pParserData->pOpenFeature)
  2406. SEMANTIC_ERROR(("Missing CloseUI for: %s\n", pParserData->pOpenFeature->pstrName));
  2407. if (pParserData->bInstallableGroup)
  2408. SEMANTIC_ERROR(("Missing CloseGroup: InstallableOptions\n"));
  2409. if (pParserData->NickName.dwLength == 0)
  2410. SEMANTIC_ERROR(("Missing *NickName and *ShortNickName entry\n"));
  2411. if (pParserData->Product.dwLength == 0)
  2412. SEMANTIC_ERROR(("Missing *Product entry\n"));
  2413. if (pParserData->dwSpecVersion == 0)
  2414. SEMANTIC_ERROR(("Missing *PPD-Adobe and *FormatVersion entry\n"));
  2415. if (pParserData->dwLangLevel == 0)
  2416. {
  2417. SEMANTIC_ERROR(("Missing *LanguageLevel entry\n"));
  2418. pParserData->dwLangLevel = 1;
  2419. }
  2420. dwMinFreeMem = pParserData->dwLangLevel <= 1 ? MIN_FREEMEM_L1 : MIN_FREEMEM_L2;
  2421. if (pParserData->dwFreeMem < dwMinFreeMem)
  2422. {
  2423. SEMANTIC_ERROR(("Invalid *FreeVM entry\n"));
  2424. pParserData->dwFreeMem = dwMinFreeMem;
  2425. }
  2426. //
  2427. // Map LanguageEncoding to code page
  2428. //
  2429. VMapLangEncodingToCodePage(pParserData);
  2430. //
  2431. // Count the number of doc- and printer-sticky features
  2432. // and sort them into two separate groups
  2433. //
  2434. VCountAndSortPrinterFeatures(pParserData);
  2435. //
  2436. // Fill out fields in the UIINFO structure
  2437. //
  2438. pUIInfo->dwSize = sizeof(UIINFO);
  2439. pUIInfo->dwDocumentFeatures = pInfoHdr->RawData.dwDocumentFeatures;
  2440. pUIInfo->dwPrinterFeatures = pInfoHdr->RawData.dwPrinterFeatures;
  2441. pUIInfo->dwTechnology = DT_RASPRINTER;
  2442. pUIInfo->dwMaxCopies = MAX_COPIES;
  2443. pUIInfo->dwMinScale = MIN_SCALE;
  2444. pUIInfo->dwMaxScale = MAX_SCALE;
  2445. pUIInfo->dwSpecVersion = pParserData->dwSpecVersion;
  2446. pUIInfo->dwLangEncoding = pParserData->dwLangEncoding;
  2447. pUIInfo->dwLangLevel = pParserData->dwLangLevel;
  2448. pUIInfo->dwPrintRate = pUIInfo->dwPrintRatePPM = pParserData->dwThroughput;
  2449. #ifndef WINNT_40
  2450. pUIInfo->dwPrintRateUnit = PRINTRATEUNIT_PPM;
  2451. #endif
  2452. //
  2453. // Note: We assume all printers can support binary protocol
  2454. //
  2455. pUIInfo->dwProtocols = pParserData->dwProtocols | PROTOCOL_BINARY;
  2456. pUIInfo->dwJobTimeout = pParserData->dwJobTimeout;
  2457. pUIInfo->dwWaitTimeout = pParserData->dwWaitTimeout;
  2458. pUIInfo->dwTTRasterizer = pParserData->dwTTRasterizer;
  2459. pUIInfo->dwFreeMem = pParserData->dwFreeMem;
  2460. pUIInfo->fxScreenAngle = pParserData->fxScreenAngle;
  2461. pUIInfo->fxScreenFreq = pParserData->fxScreenFreq;
  2462. pUIInfo->dwCustomSizeOptIndex = OPTION_INDEX_ANY;
  2463. pPpdData->dwPpdFilever = pParserData->dwPpdFilever;
  2464. pPpdData->dwFlags = pParserData->dwPpdFlags;
  2465. //
  2466. // Our internal unit is microns, thus 25400 units per inch.
  2467. //
  2468. pUIInfo->ptMasterUnits.x =
  2469. pUIInfo->ptMasterUnits.y = 25400;
  2470. pUIInfo->dwFlags = FLAG_FONT_DOWNLOADABLE |
  2471. FLAG_ORIENT_SUPPORT;
  2472. if (pParserData->dwColorDevice)
  2473. pUIInfo->dwFlags |= FLAG_COLOR_DEVICE;
  2474. if (pParserData->dwLSOrientation != LSO_MINUS90)
  2475. pUIInfo->dwFlags |= FLAG_ROTATE90;
  2476. if (PvFindListItem(pParserData->pFeatures, "StapleLocation", NULL) ||
  2477. PvFindListItem(pParserData->pFeatures, "StapleX", NULL) &&
  2478. PvFindListItem(pParserData->pFeatures, "StapleY", NULL))
  2479. {
  2480. pUIInfo->dwFlags |= FLAG_STAPLE_SUPPORT;
  2481. }
  2482. if (pParserData->bDefReversePrint)
  2483. pUIInfo->dwFlags |= FLAG_REVERSE_PRINT;
  2484. if (pParserData->dwLangLevel > 1)
  2485. {
  2486. if (pParserData->bEuroInformationSet)
  2487. {
  2488. if (!pParserData->bHasEuro)
  2489. pUIInfo->dwFlags |= FLAG_ADD_EURO;
  2490. }
  2491. else if (pParserData->dwPSVersion < 3011)
  2492. pUIInfo->dwFlags |= FLAG_ADD_EURO;
  2493. }
  2494. if (pParserData->bTrueGray)
  2495. pUIInfo->dwFlags |= FLAG_TRUE_GRAY;
  2496. VPackStringAnsiToUnicode(
  2497. pParserData,
  2498. &pUIInfo->loNickName,
  2499. pParserData->NickName.pvData,
  2500. pParserData->NickName.dwLength);
  2501. //
  2502. // Pack symbol definitions and resolve symbol references
  2503. //
  2504. VPackSymbolDefinitions(pParserData);
  2505. VResolveSymbolReferences(pParserData);
  2506. VPackInvocation(pParserData, &pUIInfo->Password, &pParserData->Password);
  2507. VPackInvocation(pParserData, &pUIInfo->ExitServer, &pParserData->ExitServer);
  2508. //
  2509. // Copy and validate custom page size parameters
  2510. //
  2511. pPpdData->dwUseHWMarginsTrue =
  2512. pPpdData->dwUseHWMarginsFalse =
  2513. pPpdData->dwLeadingEdgeLong =
  2514. pPpdData->dwLeadingEdgeShort = OPTION_INDEX_ANY;
  2515. pPpdData->dwCustomSizeFlags = pParserData->dwCustomSizeFlags;
  2516. CopyMemory(pPpdData->CustomSizeParams,
  2517. pParserData->CustomSizeParams,
  2518. sizeof(pPpdData->CustomSizeParams));
  2519. //
  2520. // Process the printer features and handle any special glitches
  2521. //
  2522. VProcessPrinterFeatures(pParserData);
  2523. //
  2524. // Pack UIConstraints information
  2525. //
  2526. VPackUIConstraints(pParserData);
  2527. //
  2528. // Pack OrderDependency and QueryOrderDependency information
  2529. //
  2530. VPackOrderDependency(pParserData, &pPpdData->OrderDeps, pParserData->pOrderDep);
  2531. VPackOrderDependency(pParserData, &pPpdData->QueryOrderDeps, pParserData->pQueryOrderDep);
  2532. //
  2533. // Pack printer features and options
  2534. //
  2535. VPackPrinterFeatures(pParserData);
  2536. //
  2537. // Fill out fields in PPDDATA structure
  2538. //
  2539. pPpdData->dwSizeOfStruct = sizeof(PPDDATA);
  2540. pPpdData->dwExtensions = pParserData->dwExtensions;
  2541. pPpdData->dwSetResType = pParserData->dwSetResType;
  2542. pPpdData->dwPSVersion = pParserData->dwPSVersion;
  2543. //
  2544. // Scan the document-sticky feature list to check if "OutputOrder" is available.
  2545. // If it is, remember its feature index, which will be used by UI code.
  2546. //
  2547. {
  2548. PFEATURE pFeature;
  2549. DWORD dwIndex;
  2550. PCSTR pstrKeywordName;
  2551. pPpdData->dwOutputOrderIndex = INVALID_FEATURE_INDEX;
  2552. pFeature = OFFSET_TO_POINTER(pInfoHdr, pUIInfo->loFeatureList);
  2553. ASSERT(pFeature != NULL);
  2554. for (dwIndex = 0; dwIndex < pUIInfo->dwDocumentFeatures; dwIndex++, pFeature++)
  2555. {
  2556. if ((pstrKeywordName = OFFSET_TO_POINTER(pInfoHdr, pFeature->loKeywordName)) &&
  2557. strcmp(pstrKeywordName, "OutputOrder") == EQUAL_STRING)
  2558. {
  2559. pPpdData->dwOutputOrderIndex = dwIndex;
  2560. break;
  2561. }
  2562. }
  2563. }
  2564. VPackInvocation(pParserData, &pPpdData->PSVersion, &pParserData->PSVersion);
  2565. VPackInvocation(pParserData, &pPpdData->Product, &pParserData->Product);
  2566. if (SUPPORT_CUSTOMSIZE(pUIInfo))
  2567. {
  2568. //
  2569. // If neither roll-fed nor cut-sheet flag is set, assume to be roll-fed
  2570. //
  2571. if (! (pPpdData->dwCustomSizeFlags & (CUSTOMSIZE_CUTSHEET|CUSTOMSIZE_ROLLFED)))
  2572. pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_ROLLFED;
  2573. //
  2574. // If roll-fed flag is not set, default must be cut-sheet
  2575. //
  2576. if (! (pPpdData->dwCustomSizeFlags & CUSTOMSIZE_ROLLFED))
  2577. pPpdData->dwCustomSizeFlags |= CUSTOMSIZE_DEFAULTCUTSHEET;
  2578. }
  2579. VPackInvocation(pParserData, &pPpdData->PatchFile, &pParserData->PatchFile);
  2580. VPackInvocation(pParserData, &pPpdData->JclBegin, &pParserData->JclBegin);
  2581. VPackInvocation(pParserData, &pPpdData->JclEnterPS, &pParserData->JclEnterPS);
  2582. VPackInvocation(pParserData, &pPpdData->JclEnd, &pParserData->JclEnd);
  2583. VPackInvocation(pParserData, &pPpdData->ManualFeedFalse, &pParserData->ManualFeedFalse);
  2584. //
  2585. // Pack NT4 feature index mapping information
  2586. //
  2587. VPackNt4Mapping(pParserData);
  2588. //
  2589. // Pack device font information
  2590. //
  2591. VPackDeviceFonts(pParserData);
  2592. //
  2593. // Pack JobPatchFile information
  2594. //
  2595. VPackJobPatchFiles(pParserData);
  2596. //
  2597. // Pack default TrueType font substitution table
  2598. //
  2599. if (pParserData->pTTFontSubs == NULL || pParserData->uCodePage == CP_ERROR)
  2600. VPackDefaultTrueTypeSubstTable(pParserData);
  2601. else
  2602. VPackTrueTypeSubstTable(pParserData);
  2603. pInfoHdr->RawData.dwFileSize = pParserData->dwBufSize;
  2604. bResult = TRUE;
  2605. }
  2606. __except(EXCEPTION_EXECUTE_HANDLER)
  2607. {
  2608. ERR(("PackBinaryData failed.\n"));
  2609. }
  2610. return bResult;
  2611. }
  2612. BOOL
  2613. BSaveBinaryDataToFile(
  2614. PPARSERDATA pParserData,
  2615. PTSTR ptstrPpdFilename
  2616. )
  2617. /*++
  2618. Routine Description:
  2619. Cache the binary PPD data in a file
  2620. Arguments:
  2621. pParserData - Points to parser data structure
  2622. ptstrPpdFilename - Specifies the PPD filename
  2623. Return Value:
  2624. TRUE if successful, FALSE if there is an error
  2625. --*/
  2626. {
  2627. PTSTR ptstrBpdFilename;
  2628. HANDLE hFile;
  2629. DWORD dwBytesWritten;
  2630. BOOL bResult = FALSE;
  2631. VALIDATE_PARSER_DATA(pParserData);
  2632. //
  2633. // Generate a binary file name based the original filename
  2634. // Create a file and write data to it
  2635. //
  2636. if ((ptstrBpdFilename = GenerateBpdFilename(ptstrPpdFilename)) != NULL &&
  2637. (hFile = CreateFile(ptstrBpdFilename,
  2638. GENERIC_WRITE,
  2639. 0,
  2640. NULL,
  2641. CREATE_ALWAYS,
  2642. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS,
  2643. NULL)) != INVALID_HANDLE_VALUE)
  2644. {
  2645. bResult = WriteFile(hFile,
  2646. pParserData->pubBufStart,
  2647. pParserData->dwBufSize,
  2648. &dwBytesWritten,
  2649. NULL) &&
  2650. (pParserData->dwBufSize == dwBytesWritten);
  2651. CloseHandle(hFile);
  2652. }
  2653. if (! bResult)
  2654. ERR(("Couldn't cache binary PPD data: %d\n", GetLastError()));
  2655. MemFree(ptstrBpdFilename);
  2656. return bResult;
  2657. }
  2658. VOID
  2659. VFreeParserData(
  2660. PPARSERDATA pParserData
  2661. )
  2662. /*++
  2663. Routine Description:
  2664. Free up memory used to hold parser data structure
  2665. Arguments:
  2666. pParserData - Points to parser data structure
  2667. Return Value:
  2668. NONE
  2669. --*/
  2670. {
  2671. VALIDATE_PARSER_DATA(pParserData);
  2672. if (pParserData->pubBufStart)
  2673. VirtualFree(pParserData->pubBufStart, 0, MEM_RELEASE);
  2674. MemFree(pParserData->Value.pbuf);
  2675. HeapDestroy(pParserData->hHeap);
  2676. }
  2677. PPARSERDATA
  2678. PAllocParserData(
  2679. VOID
  2680. )
  2681. /*++
  2682. Routine Description:
  2683. Allocate memory to hold PPD parser data
  2684. Arguments:
  2685. NONE
  2686. Return Value:
  2687. Pointer to allocated parser data structure
  2688. NULL if there is an error
  2689. --*/
  2690. {
  2691. PPARSERDATA pParserData;
  2692. HANDLE hHeap;
  2693. //
  2694. // Create a heap and allocate memory space from it
  2695. //
  2696. if (! (hHeap = HeapCreate(0, 16*1024, 0)) ||
  2697. ! (pParserData = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(PARSERDATA))))
  2698. {
  2699. ERR(("Memory allocation failed: %d\n", GetLastError()));
  2700. if (hHeap)
  2701. HeapDestroy(hHeap);
  2702. return NULL;
  2703. }
  2704. pParserData->hHeap = hHeap;
  2705. pParserData->pvStartSig = pParserData->pvEndSig = pParserData;
  2706. //
  2707. // Initialize the parser data structure - we only need to worry
  2708. // about non-zero fields here.
  2709. //
  2710. pParserData->dwChecksum32 = 0xFFFFFFFF;
  2711. pParserData->dwFreeMem = min(MIN_FREEMEM_L1, MIN_FREEMEM_L2);
  2712. pParserData->dwJobTimeout = DEFAULT_JOB_TIMEOUT;
  2713. pParserData->dwWaitTimeout = DEFAULT_WAIT_TIMEOUT;
  2714. pParserData->iManualFeedIndex =
  2715. pParserData->iReqPageRgnIndex =
  2716. pParserData->iDefInstallMemIndex = -1;
  2717. pParserData->wNt4Checksum = 0;
  2718. pParserData->dwPpdFlags = PPDFLAG_PRINTPSERROR;
  2719. //
  2720. // Initialize buffers for storing keyword, option, translation, and value.
  2721. // Build up data structures to speed up keyword lookup
  2722. //
  2723. SET_BUFFER(&pParserData->Keyword, pParserData->achKeyword);
  2724. SET_BUFFER(&pParserData->Option, pParserData->achOption);
  2725. SET_BUFFER(&pParserData->Xlation, pParserData->achXlation);
  2726. if (IGrowValueBuffer(&pParserData->Value) != PPDERR_NONE ||
  2727. ! BInitKeywordLookup(pParserData))
  2728. {
  2729. VFreeParserData(pParserData);
  2730. return NULL;
  2731. }
  2732. return pParserData;
  2733. }
  2734. BOOL
  2735. BRememberSourceFilename(
  2736. PPARSERDATA pParserData,
  2737. PTSTR ptstrFilename
  2738. )
  2739. /*++
  2740. Routine Description:
  2741. Remember the full pathname to the source PPD file
  2742. Arguments:
  2743. pParserData - Points to parser data structure
  2744. ptstrFilename - Specifies the source PPD filename
  2745. Return Value:
  2746. TRUE if successful, FALSE if there is an error
  2747. --*/
  2748. {
  2749. PLISTOBJ pItem;
  2750. TCHAR ptstrFullname[MAX_PATH];
  2751. PTSTR ptstrFilePart;
  2752. DWORD dwSizeChars, dwSizeChars2;
  2753. DWORD dwSizeBytes; // size of buffer to hold pathname
  2754. //
  2755. // Get the full pathname to the specified source PPD file
  2756. //
  2757. dwSizeChars = GetFullPathName(ptstrFilename, MAX_PATH, ptstrFullname, &ptstrFilePart);
  2758. if (dwSizeChars == 0)
  2759. {
  2760. ERR(("GetFullPathName failed: %d\n", GetLastError()));
  2761. return FALSE;
  2762. }
  2763. //
  2764. // Remember the source PPD filenames
  2765. //
  2766. dwSizeBytes = (dwSizeChars + 1) * sizeof(TCHAR);
  2767. if (! (pItem = ALLOC_PARSER_MEM(pParserData, sizeof(LISTOBJ) + dwSizeBytes)))
  2768. return FALSE;
  2769. pItem->pstrName = (PSTR) ((PBYTE) pItem + sizeof(LISTOBJ));
  2770. // let GetFullPathName write directly into the real buffer!
  2771. dwSizeChars2 = GetFullPathName(ptstrFilename, dwSizeChars + 1, (PTSTR)pItem->pstrName, &ptstrFilePart);
  2772. if((dwSizeChars2 == 0) || (dwSizeChars2 > dwSizeChars))
  2773. {
  2774. ERR(("GetFullPathName failed: %d\n", GetLastError()));
  2775. return FALSE; // no need to free pItem since Heap is destroyed automatically.
  2776. }
  2777. pItem->pNext = pParserData->pPpdFileNames;
  2778. pParserData->pPpdFileNames = pItem;
  2779. return TRUE;
  2780. }
  2781. // 16-bit crc checksum table - copied from win95
  2782. static const WORD Crc16Table[] =
  2783. {
  2784. 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  2785. 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  2786. 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  2787. 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  2788. 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  2789. 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  2790. 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  2791. 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  2792. 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  2793. 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  2794. 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  2795. 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  2796. 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  2797. 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  2798. 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  2799. 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  2800. 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  2801. 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  2802. 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  2803. 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  2804. 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  2805. 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  2806. 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  2807. 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  2808. 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  2809. 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  2810. 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  2811. 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  2812. 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  2813. 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  2814. 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  2815. 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  2816. };
  2817. WORD
  2818. WComputeCrc16Checksum(
  2819. IN PBYTE pbuf,
  2820. IN DWORD dwCount,
  2821. IN WORD wChecksum
  2822. )
  2823. /*++
  2824. Routine Description:
  2825. Compute the 16-bit CRC checksum on a buffer of data
  2826. Arguments:
  2827. pbuf - Points to a data buffer
  2828. dwCount - Number of bytes in the data buffer
  2829. wChecksum - Initial checksum value
  2830. Return Value:
  2831. Resulting checksum value
  2832. --*/
  2833. {
  2834. while (dwCount--)
  2835. wChecksum = Crc16Table[(wChecksum >> 8) ^ *pbuf++] ^ (wChecksum << 8);
  2836. return wChecksum;
  2837. }
  2838. DWORD
  2839. dwComputeFeatureOptionChecksum(
  2840. PPARSERDATA pParserData
  2841. )
  2842. /*++
  2843. Routine Description:
  2844. Compute checksum for only feature/option keyword strings.
  2845. Arguments:
  2846. pParserData - Points to parser data structure
  2847. Return Value:
  2848. 32bit checksum value
  2849. --*/
  2850. {
  2851. PINFOHEADER pInfoHdr;
  2852. PUIINFO pUIInfo;
  2853. PFEATURE pFeature;
  2854. POPTION pOption;
  2855. DWORD dwFeatureCount, dwFeatureIndex, dwOptionCount, dwOptionIndex;
  2856. PBYTE pBuf;
  2857. DWORD dwBufSize;
  2858. VALIDATE_PARSER_DATA(pParserData);
  2859. pInfoHdr = pParserData->pInfoHdr;
  2860. pUIInfo = (PUIINFO)((PBYTE)pInfoHdr + sizeof(INFOHEADER));
  2861. dwFeatureCount = pInfoHdr->RawData.dwDocumentFeatures + pInfoHdr->RawData.dwPrinterFeatures;
  2862. pFeature = OFFSET_TO_POINTER(pInfoHdr, pUIInfo->loFeatureList);
  2863. ASSERT(dwFeatureCount == 0 || pFeature != NULL);
  2864. for (dwFeatureIndex = 0; dwFeatureIndex < dwFeatureCount; dwFeatureIndex++, pFeature++)
  2865. {
  2866. pBuf = OFFSET_TO_POINTER(pInfoHdr, pFeature->loKeywordName);
  2867. ASSERT(pBuf != NULL);
  2868. dwBufSize = strlen((PSTR)pBuf) + 1;
  2869. pParserData->dwChecksum32 = ComputeCrc32Checksum(pBuf, dwBufSize, pParserData->dwChecksum32);
  2870. if (dwOptionCount = pFeature->Options.dwCount)
  2871. {
  2872. pOption = OFFSET_TO_POINTER(pInfoHdr, pFeature->Options.loOffset);
  2873. ASSERT(pOption != NULL);
  2874. for (dwOptionIndex = 0; dwOptionIndex < dwOptionCount; dwOptionIndex++)
  2875. {
  2876. pBuf = OFFSET_TO_POINTER(pInfoHdr, pOption->loKeywordName);
  2877. dwBufSize = strlen((PSTR)pBuf) + 1;
  2878. pParserData->dwChecksum32 = ComputeCrc32Checksum(pBuf, dwBufSize, pParserData->dwChecksum32);
  2879. pOption = (POPTION)((PBYTE)pOption + pFeature->dwOptionSize);
  2880. }
  2881. }
  2882. }
  2883. return pParserData->dwChecksum32;
  2884. }
  2885. DWORD
  2886. dwCalcMaxKeywordSize(
  2887. IN PPARSERDATA pParserData,
  2888. IN INT iMode
  2889. )
  2890. /*++
  2891. Routine Description:
  2892. Calculate the maximum buffer size for storing feature/option
  2893. keyword pairs in Registry.
  2894. Arguments:
  2895. pParserData - Points to parser data structure
  2896. iMode - For either doc- or printer- sticky features
  2897. Return Value:
  2898. The maximum buffer size needed for storing feature/option keyword paris.
  2899. --*/
  2900. {
  2901. PINFOHEADER pInfoHdr;
  2902. PUIINFO pUIInfo;
  2903. PFEATURE pFeature;
  2904. POPTION pOption;
  2905. DWORD dwStart, dwFeatureCount, dwFeatureIndex, dwOptionCount, dwOptionIndex;
  2906. PSTR pBuf;
  2907. DWORD dwMaxSize, dwOptionSize, dwOptionMax;
  2908. VALIDATE_PARSER_DATA(pParserData);
  2909. dwMaxSize = 0;
  2910. pInfoHdr = pParserData->pInfoHdr;
  2911. pUIInfo = pParserData->pUIInfo;
  2912. if (iMode == MODE_DOCUMENT_STICKY)
  2913. {
  2914. dwStart = 0;
  2915. dwFeatureCount = pUIInfo->dwDocumentFeatures;
  2916. }
  2917. else
  2918. {
  2919. ASSERT(iMode == MODE_PRINTER_STICKY);
  2920. dwStart = pUIInfo->dwDocumentFeatures;
  2921. dwFeatureCount = pUIInfo->dwPrinterFeatures;
  2922. }
  2923. pFeature = OFFSET_TO_POINTER(pInfoHdr, pUIInfo->loFeatureList);
  2924. ASSERT(dwFeatureCount == 0 || pFeature != NULL);
  2925. pFeature += dwStart;
  2926. for (dwFeatureIndex = 0; dwFeatureIndex < dwFeatureCount; dwFeatureIndex++, pFeature++)
  2927. {
  2928. pBuf = OFFSET_TO_POINTER(pInfoHdr, pFeature->loKeywordName);
  2929. ASSERT(pBuf != NULL);
  2930. dwMaxSize += strlen(pBuf) + 1;
  2931. dwOptionMax = 0;
  2932. if (dwOptionCount = pFeature->Options.dwCount)
  2933. {
  2934. pOption = OFFSET_TO_POINTER(pInfoHdr, pFeature->Options.loOffset);
  2935. ASSERT(pOption != NULL);
  2936. for (dwOptionIndex = 0; dwOptionIndex < dwOptionCount; dwOptionIndex++)
  2937. {
  2938. pBuf = OFFSET_TO_POINTER(pInfoHdr, pOption->loKeywordName);
  2939. dwOptionSize = strlen(pBuf) + 1;
  2940. if (pFeature->dwUIType != UITYPE_PICKMANY)
  2941. {
  2942. if (dwOptionMax < dwOptionSize)
  2943. dwOptionMax = dwOptionSize;
  2944. }
  2945. else // count all options for PickMany feature
  2946. dwMaxSize += dwOptionSize;
  2947. pOption = (POPTION)((PBYTE)pOption + pFeature->dwOptionSize);
  2948. }
  2949. }
  2950. //
  2951. // Add the max option keyword size here for non-PickMany feature
  2952. //
  2953. if (pFeature->dwUIType != UITYPE_PICKMANY)
  2954. dwMaxSize += dwOptionMax;
  2955. //
  2956. // One extra byte for the \0x0A delimiter between features
  2957. //
  2958. dwMaxSize += 1;
  2959. }
  2960. dwMaxSize += KEYWORD_SIZE_EXTRA;
  2961. return dwMaxSize;
  2962. }
  2963. PPDERROR
  2964. IParseFile(
  2965. PPARSERDATA pParserData,
  2966. PTSTR ptstrFilename
  2967. )
  2968. /*++
  2969. Routine Description:
  2970. Parse a PPD file
  2971. Arguments:
  2972. pParserData - Points to parser data structure
  2973. ptstrFilename - Specifies the name of the file to be parsed
  2974. Return Value:
  2975. PPDERR_NONE if successful, error code otherwise
  2976. --*/
  2977. {
  2978. PPDERROR iStatus;
  2979. PFILEOBJ pFile;
  2980. INT iSyntaxErrors = 0;
  2981. //
  2982. // Map the file into memory for read-only access
  2983. //
  2984. VALIDATE_PARSER_DATA(pParserData);
  2985. ASSERT(ptstrFilename != NULL);
  2986. if (! BRememberSourceFilename(pParserData, ptstrFilename) ||
  2987. ! (pFile = PCreateFileObj(ptstrFilename)))
  2988. {
  2989. return PPDERR_FILE;
  2990. }
  2991. pParserData->pFile = pFile;
  2992. #if 0
  2993. //
  2994. // Compute the 32-bit CRC checksum of the file content
  2995. //
  2996. pParserData->dwChecksum32 =
  2997. ComputeCrc32Checksum(pFile->pubStart, pFile->dwFileSize, pParserData->dwChecksum32);
  2998. #endif
  2999. //
  3000. // Compute the 16-bit CRC checksum as well for PS4 compatibility
  3001. //
  3002. pParserData->wNt4Checksum =
  3003. WComputeCrc16Checksum(pFile->pubStart, pFile->dwFileSize, pParserData->wNt4Checksum);
  3004. //
  3005. // Process entries in the file
  3006. //
  3007. while ((iStatus = IParseEntry(pParserData)) != PPDERR_EOF)
  3008. {
  3009. if (iStatus == PPDERR_SYNTAX)
  3010. iSyntaxErrors++;
  3011. else if (iStatus != PPDERR_NONE)
  3012. {
  3013. VDeleteFileObj(pFile);
  3014. return iStatus;
  3015. }
  3016. }
  3017. if (END_OF_FILE(pFile) && !END_OF_LINE(pFile))
  3018. TERSE(("Incomplete last line ignored.\n"));
  3019. //
  3020. // Unmap the file and return to the caller
  3021. //
  3022. VDeleteFileObj(pFile);
  3023. return (iSyntaxErrors > 0) ? PPDERR_SYNTAX : PPDERR_NONE;
  3024. }
  3025. PRAWBINARYDATA
  3026. PpdParseTextFile(
  3027. PTSTR ptstrPpdFilename
  3028. )
  3029. /*++
  3030. Routine Description:
  3031. PPD parser main entry point
  3032. Arguments:
  3033. ptstrPpdFilename - Specifies the PPD file to be parsed
  3034. Return Value:
  3035. Pointer to parsed binary PPD data, NULL if there is an error
  3036. --*/
  3037. {
  3038. PPARSERDATA pParserData;
  3039. PPDERROR iStatus;
  3040. PRAWBINARYDATA pRawData = NULL;
  3041. //
  3042. // Allocate parser data structure
  3043. //
  3044. ASSERT(ptstrPpdFilename != NULL);
  3045. if (! (pParserData = PAllocParserData()))
  3046. return NULL;
  3047. //
  3048. // Parse the PPD file
  3049. //
  3050. iStatus = IParseFile(pParserData, ptstrPpdFilename);
  3051. if (iStatus == PPDERR_NONE || iStatus == PPDERR_SYNTAX)
  3052. {
  3053. //
  3054. // Pack the parsed information into binary format
  3055. //
  3056. pParserData->bErrorFlag = FALSE;
  3057. if (BPackBinaryData(pParserData))
  3058. {
  3059. //
  3060. // After binary data is packed, we calculate the 32bit checksum
  3061. // for only feature/option keyword strings (instead of for the
  3062. // whole PPD file). Doing this will enable us to retain option
  3063. // selections when the PPD file is modified without feature/option
  3064. // changes.
  3065. //
  3066. pParserData->pInfoHdr->RawData.dwChecksum32 = dwComputeFeatureOptionChecksum(pParserData);
  3067. //
  3068. // Calculate the maximum buffer sizes for storing feature/option
  3069. // keyword pairs in Registry
  3070. //
  3071. pParserData->pUIInfo->dwMaxDocKeywordSize = dwCalcMaxKeywordSize(pParserData, MODE_DOCUMENT_STICKY);
  3072. pParserData->pUIInfo->dwMaxPrnKeywordSize = dwCalcMaxKeywordSize(pParserData, MODE_PRINTER_STICKY);
  3073. #ifndef WINNT_40
  3074. pParserData->pPpdData->dwUserDefUILangID = (DWORD)GetUserDefaultUILanguage();
  3075. #else
  3076. pParserData->pPpdData->dwUserDefUILangID = 0;
  3077. #endif
  3078. //
  3079. // Save binary data to a file
  3080. //
  3081. (VOID) BSaveBinaryDataToFile(pParserData, ptstrPpdFilename);
  3082. //
  3083. // Here we'll copy the packed binary data to a different buffer.
  3084. // This is necessary because the packed data buffer was allocated
  3085. // using VirtualAlloc. If we return that pointer back to the caller,
  3086. // the caller would need to call VirtualFree to release it.
  3087. //
  3088. if (pRawData = MemAlloc(pParserData->dwBufSize))
  3089. {
  3090. CopyMemory(pRawData, pParserData->pubBufStart, pParserData->dwBufSize);
  3091. }
  3092. else
  3093. ERR(("Memory allocation failed: %d\n", GetLastError()));
  3094. }
  3095. }
  3096. if (iStatus == PPDERR_SYNTAX || pParserData->bErrorFlag)
  3097. WARNING(("Errors found in %ws\n", ptstrPpdFilename));
  3098. VFreeParserData(pParserData);
  3099. return pRawData;
  3100. }
  3101. PPDERROR
  3102. IGrowValueBuffer(
  3103. PBUFOBJ pBufObj
  3104. )
  3105. /*++
  3106. Routine Description:
  3107. Grow the buffer used for holding the entry value
  3108. Arguments:
  3109. pBufObj - Specifies the buffer to be enlarged
  3110. Return Value:
  3111. PPDERR_NONE if successful, error code otherwise
  3112. --*/
  3113. #define VALUE_BUFFER_INCREMENT (1*KBYTES)
  3114. {
  3115. DWORD dwNewLen = pBufObj->dwMaxLen + VALUE_BUFFER_INCREMENT;
  3116. PBYTE pbuf;
  3117. if (! IS_BUFFER_FULL(pBufObj))
  3118. WARNING(("Trying to grow buffer while it's not yet full.\n"));
  3119. if (! (pbuf = MemAllocZ(dwNewLen)))
  3120. {
  3121. ERR(("Memory allocation failed: %d\n", GetLastError()));
  3122. return PPDERR_MEMORY;
  3123. }
  3124. if (pBufObj->pbuf)
  3125. {
  3126. CopyMemory(pbuf, pBufObj->pbuf, pBufObj->dwSize);
  3127. MemFree(pBufObj->pbuf);
  3128. }
  3129. pBufObj->pbuf = pbuf;
  3130. pBufObj->dwMaxLen = dwNewLen;
  3131. return PPDERR_NONE;
  3132. }