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.

3150 lines
85 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. ppd.c
  5. Abstract:
  6. Public interface to the PPD parser
  7. Environment:
  8. Windows NT PostScript driver
  9. Revision History:
  10. 10/14/96 -davidx-
  11. Add new interface function MapToDeviceOptIndex.
  12. 09/30/96 -davidx-
  13. Cleaner handling of ManualFeed and AutoSelect feature.
  14. 09/24/96 -davidx-
  15. Implement ResolveUIConflicts.
  16. 09/23/96 -davidx-
  17. Implement ChangeOptionsViaID.
  18. 08/30/96 -davidx-
  19. Changes after the 1st code review.
  20. 08/19/96 -davidx-
  21. Implemented most of the interface functions except:
  22. ChangeOptionsViaID
  23. ResolveUIConflicts
  24. 08/16/96 -davidx-
  25. Created it.
  26. --*/
  27. #include "lib.h"
  28. #include "ppd.h"
  29. #ifndef KERNEL_MODE
  30. #ifndef WINNT_40
  31. #include "appcompat.h"
  32. #else // WINNT_40
  33. #endif // !WINNT_40
  34. #endif // !KERNEL_MODE
  35. //
  36. // Forward declaration of local static functions
  37. //
  38. BOOL BCheckFeatureConflict(PUIINFO, POPTSELECT, DWORD, PDWORD, DWORD, DWORD);
  39. BOOL BCheckFeatureOptionConflict(PUIINFO, DWORD, DWORD, DWORD, DWORD);
  40. BOOL BSearchConstraintList(PUIINFO, DWORD, DWORD, DWORD);
  41. DWORD DwReplaceFeatureOption(PUIINFO, POPTSELECT, DWORD, DWORD, DWORD);
  42. DWORD DwInternalMapToOptIndex(PUIINFO, PFEATURE, LONG, LONG, PDWORD);
  43. //
  44. // DeleteRawBinaryData only called from driverui
  45. //
  46. #ifndef KERNEL_MODE
  47. void
  48. DeleteRawBinaryData(
  49. IN PTSTR ptstrPpdFilename
  50. )
  51. /*++
  52. Routine Description:
  53. Delete raw binary printer description data.
  54. Arguments:
  55. ptstrDataFilename - Specifies the name of the original printer description file
  56. Return Value:
  57. none
  58. --*/
  59. {
  60. PTSTR ptstrBpdFilename;
  61. // only for test purposes. Upgrades are hard to debug...
  62. ERR(("Deleting .bpd file\n"));
  63. //
  64. // Sanity check
  65. //
  66. if (ptstrPpdFilename == NULL)
  67. {
  68. RIP(("PPD filename is NULL.\n"));
  69. return;
  70. }
  71. //
  72. // Generate BPD filename from the specified PPD filename
  73. //
  74. if (! (ptstrBpdFilename = GenerateBpdFilename(ptstrPpdFilename)))
  75. return;
  76. if (!DeleteFile(ptstrBpdFilename))
  77. ERR(("DeleteRawBinaryData failed: %d\n", GetLastError()));
  78. MemFree(ptstrBpdFilename);
  79. }
  80. #endif
  81. PRAWBINARYDATA
  82. LoadRawBinaryData(
  83. IN PTSTR ptstrDataFilename
  84. )
  85. /*++
  86. Routine Description:
  87. Load raw binary printer description data.
  88. Arguments:
  89. ptstrDataFilename - Specifies the name of the original printer description file
  90. Return Value:
  91. Pointer to raw binary printer description data
  92. NULL if there is an error
  93. --*/
  94. {
  95. PRAWBINARYDATA pRawData;
  96. //
  97. // Sanity check
  98. //
  99. if (ptstrDataFilename == NULL)
  100. {
  101. RIP(("PPD filename is NULL.\n"));
  102. return NULL;
  103. }
  104. //
  105. // Attempt to load cached binary printer description data first
  106. //
  107. if ((pRawData = PpdLoadCachedBinaryData(ptstrDataFilename)) == NULL)
  108. {
  109. #if !defined(KERNEL_MODE) || defined(USERMODE_DRIVER)
  110. //
  111. // If there is no cached binary data or it's out-of-date, we'll parse
  112. // the ASCII text file and cache the resulting binary data.
  113. //
  114. pRawData = PpdParseTextFile(ptstrDataFilename);
  115. #endif
  116. }
  117. //
  118. // Initialize various pointer fields inside the printer description data
  119. //
  120. if (pRawData)
  121. {
  122. PINFOHEADER pInfoHdr;
  123. PUIINFO pUIInfo;
  124. PPPDDATA pPpdData;
  125. pInfoHdr = (PINFOHEADER) pRawData;
  126. pUIInfo = GET_UIINFO_FROM_INFOHEADER(pInfoHdr);
  127. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER(pInfoHdr);
  128. ASSERT(pUIInfo != NULL && pUIInfo->dwSize == sizeof(UIINFO));
  129. ASSERT(pPpdData != NULL && pPpdData->dwSizeOfStruct == sizeof(PPDDATA));
  130. pRawData->pvReserved = NULL;
  131. pRawData->pvPrivateData = pRawData;
  132. pUIInfo->pubResourceData = (PBYTE) pInfoHdr;
  133. pUIInfo->pInfoHeader = pInfoHdr;
  134. #ifndef KERNEL_MODE
  135. #ifndef WINNT_40 // Win2K user mode driver
  136. if (GetAppCompatFlags2(VER40) & GACF2_NOCUSTOMPAPERSIZES)
  137. {
  138. pUIInfo->dwFlags &= ~FLAG_CUSTOMSIZE_SUPPORT;
  139. }
  140. #else // WINNT_40
  141. /* NT4 solution here */
  142. #endif // !WINNT_40
  143. #endif // !KERNEL_MODE
  144. }
  145. if (pRawData == NULL)
  146. ERR(("LoadRawBinaryData failed: %d\n", GetLastError()));
  147. return pRawData;
  148. }
  149. VOID
  150. UnloadRawBinaryData(
  151. IN PRAWBINARYDATA pRawData
  152. )
  153. /*++
  154. Routine Description:
  155. Unload raw binary printer description data previously loaded using LoadRawBinaryData
  156. Arguments:
  157. pRawData - Points to raw binary printer description data
  158. Return Value:
  159. NONE
  160. --*/
  161. {
  162. ASSERT(pRawData != NULL);
  163. MemFree(pRawData);
  164. }
  165. PINFOHEADER
  166. InitBinaryData(
  167. IN PRAWBINARYDATA pRawData,
  168. IN PINFOHEADER pInfoHdr,
  169. IN POPTSELECT pOptions
  170. )
  171. /*++
  172. Routine Description:
  173. Initialize and return an instance of binary printer description data
  174. Arguments:
  175. pRawData - Points to raw binary printer description data
  176. pInfoHdr - Points to an existing of binary data instance
  177. pOptions - Specifies the options used to initialize the binary data instance
  178. Return Value:
  179. Pointer to an initialized binary data instance
  180. Note:
  181. If pInfoHdr parameter is NULL, the parser returns a new binary data instance
  182. which should be freed by calling FreeBinaryData. If pInfoHdr parameter is not
  183. NULL, the existing binary data instance is reinitialized.
  184. If pOption parameter is NULL, the parser should use the default option values
  185. for generating the binary data instance. The parser may have special case
  186. optimization to handle this case.
  187. --*/
  188. {
  189. //
  190. // For PPD parser, all instances of the binary printer description
  191. // are the same as the original raw binary data.
  192. //
  193. ASSERT(pRawData != NULL && pRawData == pRawData->pvPrivateData);
  194. ASSERT(pInfoHdr == NULL || pInfoHdr == (PINFOHEADER) pRawData);
  195. return (PINFOHEADER) pRawData;
  196. }
  197. VOID
  198. FreeBinaryData(
  199. IN PINFOHEADER pInfoHdr
  200. )
  201. /*++
  202. Routine Description:
  203. Free an instance of the binary printer description data
  204. Arguments:
  205. pInfoHdr - Points to a binary data instance previously returned from an
  206. InitBinaryData(pRawData, NULL, pOptions) call
  207. Return Value:
  208. NONE
  209. --*/
  210. {
  211. //
  212. // For PPD parser, there is nothing to be done here.
  213. //
  214. ASSERT(pInfoHdr != NULL);
  215. }
  216. PINFOHEADER
  217. UpdateBinaryData(
  218. IN PRAWBINARYDATA pRawData,
  219. IN PINFOHEADER pInfoHdr,
  220. IN POPTSELECT pOptions
  221. )
  222. /*++
  223. Routine Description:
  224. Update an instance of binary printer description data
  225. Arguments:
  226. pRawData - Points to raw binary printer description data
  227. pInfoHdr - Points to an existing of binary data instance
  228. pOptions - Specifies the options used to update the binary data instance
  229. Return Value:
  230. Pointer to the updated binary data instance
  231. NULL if there is an error
  232. --*/
  233. {
  234. //
  235. // For PPD parser, there is nothing to be done here.
  236. //
  237. ASSERT(pRawData != NULL && pRawData == pRawData->pvPrivateData);
  238. ASSERT(pInfoHdr == NULL || pInfoHdr == (PINFOHEADER) pRawData);
  239. return pInfoHdr;
  240. }
  241. BOOL
  242. InitDefaultOptions(
  243. IN PRAWBINARYDATA pRawData,
  244. OUT POPTSELECT pOptions,
  245. IN INT iMaxOptions,
  246. IN INT iMode
  247. )
  248. /*++
  249. Routine Description:
  250. Initialize the option array with default settings from the printer description file
  251. Arguments:
  252. pRawData - Points to raw binary printer description data
  253. pOptions - Points to an array of OPTSELECT structures for storing the default settings
  254. iMaxOptions - Max number of entries in pOptions array
  255. iMode - Specifies what the caller is interested in:
  256. MODE_DOCUMENT_STICKY
  257. MODE_PRINTER_STICKY
  258. MODE_DOCANDPRINTER_STICKY
  259. Return Value:
  260. FALSE if the input option array is not large enough to hold
  261. all default option values, TRUE otherwise.
  262. --*/
  263. {
  264. INT iStart, iOptions, iIndex;
  265. PINFOHEADER pInfoHdr;
  266. PUIINFO pUIInfo;
  267. PFEATURE pFeature;
  268. POPTSELECT pTempOptions;
  269. BOOL bResult = TRUE;
  270. ASSERT(pOptions != NULL);
  271. //
  272. // Get pointers to various data structures
  273. //
  274. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  275. ASSERT(pUIInfo != NULL);
  276. iOptions = pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures;
  277. ASSERT(iOptions <= MAX_PRINTER_OPTIONS);
  278. if ((pTempOptions = MemAllocZ(MAX_PRINTER_OPTIONS*sizeof(OPTSELECT))) == NULL)
  279. {
  280. ERR(("Memory allocation failed\n"));
  281. ZeroMemory(pOptions, iMaxOptions*sizeof(OPTSELECT));
  282. return FALSE;
  283. }
  284. //
  285. // Construct the default option array
  286. //
  287. ASSERT(NULL_OPTSELECT == 0);
  288. for (iIndex = 0; iIndex < iOptions; iIndex++)
  289. {
  290. pFeature = PGetIndexedFeature(pUIInfo, iIndex);
  291. ASSERT(pFeature != NULL);
  292. pTempOptions[iIndex].ubCurOptIndex = (BYTE)
  293. ((pFeature->dwFlags & FEATURE_FLAG_NOUI) ?
  294. OPTION_INDEX_ANY :
  295. pFeature->dwDefaultOptIndex);
  296. }
  297. //
  298. // Resolve any conflicts between default option selections
  299. //
  300. ResolveUIConflicts(pRawData, pTempOptions, MAX_PRINTER_OPTIONS, iMode);
  301. //
  302. // Determine if the caller is interested in doc- and/or printer-sticky options
  303. //
  304. switch (iMode)
  305. {
  306. case MODE_DOCUMENT_STICKY:
  307. iStart = 0;
  308. iOptions = pRawData->dwDocumentFeatures;
  309. break;
  310. case MODE_PRINTER_STICKY:
  311. iStart = pRawData->dwDocumentFeatures;
  312. iOptions = pRawData->dwPrinterFeatures;
  313. break;
  314. default:
  315. ASSERT(iMode == MODE_DOCANDPRINTER_STICKY);
  316. iStart = 0;
  317. break;
  318. }
  319. //
  320. // Make sure the input option array is large enough
  321. //
  322. if (iOptions > iMaxOptions)
  323. {
  324. RIP(("Option array too small: %d < %d\n", iMaxOptions, iOptions));
  325. iOptions = iMaxOptions;
  326. bResult = FALSE;
  327. }
  328. //
  329. // Copy the default option array
  330. //
  331. CopyMemory(pOptions, pTempOptions+iStart, iOptions*sizeof(OPTSELECT));
  332. MemFree(pTempOptions);
  333. return bResult;
  334. }
  335. VOID
  336. ValidateDocOptions(
  337. IN PRAWBINARYDATA pRawData,
  338. IN OUT POPTSELECT pOptions,
  339. IN INT iMaxOptions
  340. )
  341. /*++
  342. Routine Description:
  343. Validate the devmode option array and correct any invalid option selections
  344. Arguments:
  345. pRawData - Points to raw binary printer description data
  346. pOptions - Points to an array of OPTSELECT structures that need validation
  347. iMaxOptions - Max number of entries in pOptions array
  348. Return Value:
  349. None
  350. --*/
  351. {
  352. INT cFeatures, iIndex;
  353. PINFOHEADER pInfoHdr;
  354. PUIINFO pUIInfo;
  355. ASSERT(pOptions != NULL);
  356. //
  357. // Get pointers to various data structures
  358. //
  359. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  360. ASSERT(pUIInfo != NULL);
  361. cFeatures = pRawData->dwDocumentFeatures;
  362. ASSERT(cFeatures <= MAX_PRINTER_OPTIONS);
  363. if (cFeatures > iMaxOptions)
  364. {
  365. RIP(("Option array too small: %d < %d\n", iMaxOptions, cFeatures));
  366. cFeatures = iMaxOptions;
  367. }
  368. //
  369. // loop through doc-sticky features to validate each option selection(s)
  370. //
  371. for (iIndex = 0; iIndex < cFeatures; iIndex++)
  372. {
  373. PFEATURE pFeature;
  374. INT cAllOptions, cSelectedOptions, iNext;
  375. BOOL bValid;
  376. if ((pOptions[iIndex].ubCurOptIndex == OPTION_INDEX_ANY) &&
  377. (pOptions[iIndex].ubNext == NULL_OPTSELECT))
  378. {
  379. //
  380. // We use OPTION_INDEX_ANY intentionally, so don't change it.
  381. //
  382. continue;
  383. }
  384. pFeature = PGetIndexedFeature(pUIInfo, iIndex);
  385. ASSERT(pFeature != NULL);
  386. //
  387. // number of available options
  388. //
  389. cAllOptions = pFeature->Options.dwCount;
  390. //
  391. // number of selected options
  392. //
  393. cSelectedOptions = 0;
  394. iNext = iIndex;
  395. bValid = TRUE;
  396. do
  397. {
  398. cSelectedOptions++;
  399. if ((iNext >= iMaxOptions) ||
  400. (pOptions[iNext].ubCurOptIndex >= cAllOptions) ||
  401. (cSelectedOptions > cAllOptions))
  402. {
  403. //
  404. // either the option index is out of range,
  405. // or the current option selection is invalid,
  406. // or the number of selected options (for PICKMANY)
  407. // exceeds available options
  408. //
  409. bValid = FALSE;
  410. break;
  411. }
  412. iNext = pOptions[iNext].ubNext;
  413. } while (iNext != NULL_OPTSELECT);
  414. if (!bValid)
  415. {
  416. ERR(("Corrected invalid option array value for feature %d\n", iIndex));
  417. pOptions[iIndex].ubCurOptIndex = (BYTE)
  418. ((pFeature->dwFlags & FEATURE_FLAG_NOUI) ?
  419. OPTION_INDEX_ANY :
  420. pFeature->dwDefaultOptIndex);
  421. pOptions[iIndex].ubNext = NULL_OPTSELECT;
  422. }
  423. }
  424. }
  425. BOOL
  426. CheckFeatureOptionConflict(
  427. IN PRAWBINARYDATA pRawData,
  428. IN DWORD dwFeature1,
  429. IN DWORD dwOption1,
  430. IN DWORD dwFeature2,
  431. IN DWORD dwOption2
  432. )
  433. /*++
  434. Routine Description:
  435. Check if (dwFeature1, dwOption1) constrains (dwFeature2, dwOption2)
  436. Arguments:
  437. pRawData - Points to raw binary printer description data
  438. dwFeature1, dwOption1 - Feature and option indices of the first feature/option pair
  439. dwFeature2, dwOption2 - Feature and option indices of the second feature/option pair
  440. Return Value:
  441. TRUE if (dwFeature1, dwOption1) constrains (dwFeature2, dwOption2)
  442. FALSE otherwise
  443. --*/
  444. {
  445. PINFOHEADER pInfoHdr;
  446. PUIINFO pUIInfo;
  447. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  448. ASSERT(pUIInfo != NULL);
  449. return BCheckFeatureOptionConflict(pUIInfo, dwFeature1, dwOption1, dwFeature2, dwOption2);
  450. }
  451. BOOL
  452. ResolveUIConflicts(
  453. IN PRAWBINARYDATA pRawData,
  454. IN OUT POPTSELECT pOptions,
  455. IN INT iMaxOptions,
  456. IN INT iMode
  457. )
  458. /*++
  459. Routine Description:
  460. Resolve any conflicts between printer feature option selections
  461. Arguments:
  462. pRawData - Points to raw binary printer description data
  463. pOptions - Points to an array of OPTSELECT structures for storing the modified options
  464. iMaxOptions - Max number of entries in pOptions array
  465. iMode - Specifies how the conflicts should be resolved:
  466. MODE_DOCUMENT_STICKY - only resolve conflicts between doc-sticky features
  467. MODE_PRINTER_STICKY - only resolve conflicts between printer-sticky features
  468. MODE_DOCANDPRINTER_STICKY - resolve conflicts all features
  469. Return Value:
  470. TRUE if there is no conflicts between printer feature option selection
  471. FALSE otherwise
  472. --*/
  473. {
  474. PINFOHEADER pInfoHdr;
  475. PUIINFO pUIInfo;
  476. PFEATURE pFeatures;
  477. PDWORD pdwFlags;
  478. POPTSELECT pTempOptions;
  479. DWORD dwStart, dwOptions, dwIndex, dwTotalFeatureCount;
  480. BOOL bReturnValue = TRUE;
  481. BOOL bCheckConflictOnly;
  482. struct _PRIORITY_INFO {
  483. DWORD dwFeatureIndex;
  484. DWORD dwPriority;
  485. } *pPriorityInfo;
  486. ASSERT(pOptions);
  487. //
  488. // Initialize pointers to various data structures
  489. //
  490. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  491. ASSERT(pUIInfo != NULL);
  492. pFeatures = OFFSET_TO_POINTER(pInfoHdr, pUIInfo->loFeatureList);
  493. dwTotalFeatureCount = pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures;
  494. if (iMaxOptions < (INT) dwTotalFeatureCount)
  495. {
  496. ERR(("Option array for ResolveUIConflicts is too small.\n"));
  497. return bReturnValue;
  498. }
  499. //
  500. // Determine if the caller is interested in doc- and/or printer-sticky options
  501. //
  502. bCheckConflictOnly = ((iMode & DONT_RESOLVE_CONFLICT) != 0);
  503. iMode &= ~DONT_RESOLVE_CONFLICT;
  504. switch (iMode)
  505. {
  506. case MODE_DOCUMENT_STICKY:
  507. dwStart = 0;
  508. dwOptions = pRawData->dwDocumentFeatures;
  509. break;
  510. case MODE_PRINTER_STICKY:
  511. dwStart = pRawData->dwDocumentFeatures;
  512. dwOptions = pRawData->dwPrinterFeatures;
  513. break;
  514. default:
  515. ASSERT(iMode == MODE_DOCANDPRINTER_STICKY);
  516. dwStart = 0;
  517. dwOptions = dwTotalFeatureCount;
  518. break;
  519. }
  520. if (dwOptions == 0)
  521. return TRUE;
  522. //
  523. // This problem is not completely solvable in the worst case.
  524. // But the approach below should work if the PPD is well-formed.
  525. //
  526. // for each feature starting from the highest priority one
  527. // and down to the lowest priority one do:
  528. // for each selected option of the feature do:
  529. // if the option is not constrained, continue
  530. // else do one of the following:
  531. // if the conflict feature has lower priority, continue
  532. // else resolve the current feature/option pair:
  533. // if UIType is PickMany, deselect the current option
  534. // else try to change the option to:
  535. // Default option
  536. // each option of the feature in sequence
  537. // OPTION_INDEX_ANY as the last resort
  538. //
  539. pPriorityInfo = MemAlloc(dwOptions * sizeof(struct _PRIORITY_INFO));
  540. pTempOptions = MemAlloc(iMaxOptions * sizeof(OPTSELECT));
  541. pdwFlags = MemAllocZ(dwOptions * sizeof(DWORD));
  542. if (pPriorityInfo && pTempOptions && pdwFlags)
  543. {
  544. //
  545. // Copy the options array into a temporary working buffer
  546. //
  547. CopyMemory(pTempOptions, pOptions, sizeof(OPTSELECT) * iMaxOptions);
  548. //
  549. // Sort the feature indices according to their priority
  550. //
  551. for (dwIndex = 0; dwIndex < dwOptions; dwIndex++)
  552. {
  553. pPriorityInfo[dwIndex].dwFeatureIndex = dwIndex + dwStart;
  554. pPriorityInfo[dwIndex].dwPriority = pFeatures[dwIndex + dwStart].dwPriority;
  555. }
  556. for (dwIndex = 0; dwIndex < dwOptions; dwIndex++)
  557. {
  558. struct _PRIORITY_INFO tempPriorityInfo;
  559. DWORD dwLoop, dwMax = dwIndex;
  560. for (dwLoop = dwIndex + 1; dwLoop < dwOptions; dwLoop++)
  561. {
  562. if (pPriorityInfo[dwLoop].dwPriority > pPriorityInfo[dwMax].dwPriority)
  563. dwMax = dwLoop;
  564. }
  565. if (dwMax != dwIndex)
  566. {
  567. tempPriorityInfo = pPriorityInfo[dwMax];
  568. pPriorityInfo[dwMax] = pPriorityInfo[dwIndex];
  569. pPriorityInfo[dwIndex] = tempPriorityInfo;
  570. }
  571. }
  572. //
  573. // Loop through every feature, starting from the highest
  574. // priority one down to the lowest priority one.
  575. //
  576. for (dwIndex = 0; dwIndex < dwOptions; )
  577. {
  578. DWORD dwCurFeature, dwCurOption, dwCurNext;
  579. BOOL bConflict = FALSE;
  580. //
  581. // Loop through every selected option of the current feature
  582. //
  583. dwCurNext = dwCurFeature = pPriorityInfo[dwIndex].dwFeatureIndex;
  584. do
  585. {
  586. DWORD dwFeature, dwOption, dwNext;
  587. dwCurOption = pTempOptions[dwCurNext].ubCurOptIndex;
  588. dwCurNext = pTempOptions[dwCurNext].ubNext;
  589. //
  590. // Check if the current feature/option pair is constrained
  591. //
  592. for (dwFeature = dwStart; dwFeature < dwStart + dwOptions; dwFeature++)
  593. {
  594. dwNext = dwFeature;
  595. do
  596. {
  597. dwOption = pTempOptions[dwNext].ubCurOptIndex;
  598. dwNext = pTempOptions[dwNext].ubNext;
  599. if (BCheckFeatureOptionConflict(pUIInfo,
  600. dwFeature,
  601. dwOption,
  602. dwCurFeature,
  603. dwCurOption))
  604. {
  605. bConflict = TRUE;
  606. break;
  607. }
  608. }
  609. while (dwNext != NULL_OPTSELECT);
  610. //
  611. // Check if a conflict was detected
  612. //
  613. if (bConflict)
  614. {
  615. VERBOSE(("Conflicting option selections: (%d, %d) - (%d, %d)\n",
  616. dwFeature, dwOption,
  617. dwCurFeature, dwCurOption));
  618. if (pdwFlags[dwFeature - dwStart] & 0x10000)
  619. {
  620. //
  621. // The conflicting feature has higher priority than
  622. // the current feature. Change the selected option
  623. // of the current feature.
  624. //
  625. pdwFlags[dwCurFeature - dwStart] =
  626. DwReplaceFeatureOption(pUIInfo,
  627. pTempOptions,
  628. dwCurFeature,
  629. dwCurOption,
  630. pdwFlags[dwCurFeature - dwStart]);
  631. }
  632. else
  633. {
  634. //
  635. // The conflicting feature has lower priority than
  636. // the current feature. Change the selected option
  637. // of the conflicting feature.
  638. //
  639. pdwFlags[dwFeature - dwStart] =
  640. DwReplaceFeatureOption(pUIInfo,
  641. pTempOptions,
  642. dwFeature,
  643. dwOption,
  644. pdwFlags[dwFeature - dwStart]);
  645. }
  646. break;
  647. }
  648. }
  649. }
  650. while ((dwCurNext != NULL_OPTSELECT) && !bConflict);
  651. //
  652. // If no conflict is found for the selected options of
  653. // the current feature, then move on to the next feature.
  654. // Otherwise, repeat the loop on the current feature.
  655. //
  656. if (! bConflict)
  657. {
  658. //
  659. // Make the current feature as visited
  660. //
  661. pdwFlags[dwCurFeature - dwStart] |= 0x10000;
  662. dwIndex++;
  663. }
  664. else
  665. {
  666. //
  667. // If a conflict is found, set the return value to false
  668. //
  669. bReturnValue = FALSE;
  670. }
  671. }
  672. //
  673. // Copy the resolved options array from the temporary working
  674. // buffer back to the input options array. This results in
  675. // all option selections being compacted at the beginning
  676. // of the array.
  677. //
  678. if (! bCheckConflictOnly)
  679. {
  680. INT iNext = (INT) dwTotalFeatureCount;
  681. for (dwIndex = 0; dwIndex < dwTotalFeatureCount; dwIndex ++)
  682. {
  683. VCopyOptionSelections(pOptions,
  684. dwIndex,
  685. pTempOptions,
  686. dwIndex,
  687. &iNext,
  688. iMaxOptions);
  689. }
  690. }
  691. }
  692. else
  693. {
  694. //
  695. // If we couldn't allocate temporary working buffer,
  696. // then return to the caller without doing anything.
  697. //
  698. ERR(("Memory allocation failed.\n"));
  699. }
  700. MemFree(pTempOptions);
  701. MemFree(pdwFlags);
  702. MemFree(pPriorityInfo);
  703. return bReturnValue;
  704. }
  705. BOOL
  706. EnumEnabledOptions(
  707. IN PRAWBINARYDATA pRawData,
  708. IN POPTSELECT pOptions,
  709. IN DWORD dwFeatureIndex,
  710. OUT PBOOL pbEnabledOptions,
  711. IN INT iMode
  712. )
  713. /*++
  714. Routine Description:
  715. Determine which options of the specified feature should be enabled
  716. based on the current option selections of printer features
  717. Arguments:
  718. pRawData - Points to raw binary printer description data
  719. pOptions - Points to the current feature option selections
  720. dwFeatureIndex - Specifies the index of the feature in question
  721. pbEnabledOptions - An array of BOOLs, each entry corresponds to an option
  722. of the specified feature. On exit, if the entry is TRUE, the corresponding
  723. option is enabled. Otherwise, the corresponding option should be disabled.
  724. iMode - Specifies what the caller is interested in:
  725. MODE_DOCUMENT_STICKY
  726. MODE_PRINTER_STICKY
  727. MODE_DOCANDPRINTER_STICKY
  728. Return Value:
  729. TRUE if any option for the specified feature is enabled,
  730. FALSE if all options of the specified feature are disabled
  731. (i.e. the feature itself is disabled)
  732. --*/
  733. {
  734. PINFOHEADER pInfoHdr;
  735. PUIINFO pUIInfo;
  736. PFEATURE pFeature;
  737. DWORD dwIndex, dwCount;
  738. BOOL bFeatureEnabled = FALSE;
  739. ASSERT(pOptions && pbEnabledOptions);
  740. //
  741. // Get pointers to various data structures
  742. //
  743. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  744. ASSERT(pUIInfo != NULL);
  745. if (! (pFeature = PGetIndexedFeature(pUIInfo, dwFeatureIndex)))
  746. {
  747. ASSERT(FALSE);
  748. return FALSE;
  749. }
  750. dwCount = pFeature->Options.dwCount;
  751. //
  752. // Go through each option of the specified feature and
  753. // determine whether it should be enabled or disabled.
  754. //
  755. for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
  756. {
  757. DWORD dwFeature, dwOption;
  758. BOOL bEnabled = TRUE;
  759. for (dwFeature = 0;
  760. dwFeature < pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures;
  761. dwFeature ++)
  762. {
  763. if (BCheckFeatureConflict(pUIInfo,
  764. pOptions,
  765. dwFeature,
  766. &dwOption,
  767. dwFeatureIndex,
  768. dwIndex))
  769. {
  770. bEnabled = FALSE;
  771. break;
  772. }
  773. }
  774. pbEnabledOptions[dwIndex] = bEnabled;
  775. bFeatureEnabled = bFeatureEnabled || bEnabled;
  776. }
  777. return bFeatureEnabled;
  778. }
  779. BOOL
  780. EnumNewUIConflict(
  781. IN PRAWBINARYDATA pRawData,
  782. IN POPTSELECT pOptions,
  783. IN DWORD dwFeatureIndex,
  784. IN PBOOL pbSelectedOptions,
  785. OUT PCONFLICTPAIR pConflictPair
  786. )
  787. /*++
  788. Routine Description:
  789. Check if there are any conflicts between the currently selected options
  790. for the specified feature an other feature/option selections.
  791. Arguments:
  792. pRawData - Points to raw binary printer description data
  793. pOptions - Points to the current feature/option selections
  794. dwFeatureIndex - Specifies the index of the interested printer feature
  795. pbSelectedOptions - Specifies which options for the specified feature are selected
  796. pConflictPair - Return the conflicting pair of feature/option selections
  797. Return Value:
  798. TRUE if there is a conflict between the selected options for the specified feature
  799. and other feature option selections.
  800. FALSE if the selected options for the specified feature is consistent with other
  801. feature option selections.
  802. --*/
  803. {
  804. PINFOHEADER pInfoHdr;
  805. PUIINFO pUIInfo;
  806. PFEATURE pSpecifiedFeature;
  807. DWORD dwIndex, dwCount, dwPriority;
  808. BOOL bConflict = FALSE;
  809. ASSERT(pOptions && pbSelectedOptions && pConflictPair);
  810. //
  811. // Get pointers to various data structures
  812. //
  813. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  814. ASSERT(pUIInfo != NULL);
  815. if (! (pSpecifiedFeature = PGetIndexedFeature(pUIInfo, dwFeatureIndex)))
  816. {
  817. ASSERT(FALSE);
  818. return FALSE;
  819. }
  820. dwCount = pSpecifiedFeature->Options.dwCount;
  821. //
  822. // Go through the selected options of the specified feature
  823. // and check if they are constrained.
  824. //
  825. for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
  826. {
  827. DWORD dwFeature, dwOption;
  828. PFEATURE pFeature;
  829. //
  830. // Skip options which are not selected
  831. //
  832. if (! pbSelectedOptions[dwIndex])
  833. continue;
  834. for (dwFeature = 0;
  835. dwFeature < pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures;
  836. dwFeature ++)
  837. {
  838. if (dwFeature == dwFeatureIndex)
  839. continue;
  840. if (BCheckFeatureConflict(pUIInfo,
  841. pOptions,
  842. dwFeature,
  843. &dwOption,
  844. dwFeatureIndex,
  845. dwIndex))
  846. {
  847. pFeature = PGetIndexedFeature(pUIInfo, dwFeature);
  848. ASSERT(pFeature != NULL);
  849. //
  850. // Remember the highest priority conflict-pair
  851. //
  852. if (!bConflict || pFeature->dwPriority > dwPriority)
  853. {
  854. dwPriority = pFeature->dwPriority;
  855. if (dwPriority >= pSpecifiedFeature->dwPriority)
  856. {
  857. pConflictPair->dwFeatureIndex1 = dwFeature;
  858. pConflictPair->dwOptionIndex1 = dwOption;
  859. pConflictPair->dwFeatureIndex2 = dwFeatureIndex;
  860. pConflictPair->dwOptionIndex2 = dwIndex;
  861. }
  862. else
  863. {
  864. pConflictPair->dwFeatureIndex1 = dwFeatureIndex;
  865. pConflictPair->dwOptionIndex1 = dwIndex;
  866. pConflictPair->dwFeatureIndex2 = dwFeature;
  867. pConflictPair->dwOptionIndex2 = dwOption;
  868. }
  869. }
  870. bConflict = TRUE;
  871. }
  872. }
  873. //
  874. // For PickMany UI types, the current selections for the specified
  875. // feature could potentially conflict with each other.
  876. //
  877. if (pSpecifiedFeature->dwUIType == UITYPE_PICKMANY)
  878. {
  879. for (dwOption = 0; dwOption < dwCount; dwOption++)
  880. {
  881. if (BCheckFeatureOptionConflict(pUIInfo,
  882. dwFeatureIndex,
  883. dwOption,
  884. dwFeatureIndex,
  885. dwIndex))
  886. {
  887. if (!bConflict || pSpecifiedFeature->dwPriority > dwPriority)
  888. {
  889. dwPriority = pSpecifiedFeature->dwPriority;
  890. pConflictPair->dwFeatureIndex1 = dwFeatureIndex;
  891. pConflictPair->dwOptionIndex1 = dwOption;
  892. pConflictPair->dwFeatureIndex2 = dwFeatureIndex;
  893. pConflictPair->dwOptionIndex2 = dwIndex;
  894. }
  895. bConflict = TRUE;
  896. }
  897. }
  898. }
  899. }
  900. return bConflict;
  901. }
  902. BOOL
  903. EnumNewPickOneUIConflict(
  904. IN PRAWBINARYDATA pRawData,
  905. IN POPTSELECT pOptions,
  906. IN DWORD dwFeatureIndex,
  907. IN DWORD dwOptionIndex,
  908. OUT PCONFLICTPAIR pConflictPair
  909. )
  910. /*++
  911. Routine Description:
  912. Check if there are any conflicts between the currently selected option
  913. for the specified feature an other feature/option selections.
  914. This is similar to EnumNewUIConflict above except that only one selected
  915. option is allowed for the specified feature.
  916. Arguments:
  917. pRawData - Points to raw binary printer description data
  918. pOptions - Points to the current feature/option selections
  919. dwFeatureIndex - Specifies the index of the interested printer feature
  920. dwOptionIndex - Specifies the selected option of the specified feature
  921. pConflictPair - Return the conflicting pair of feature/option selections
  922. Return Value:
  923. TRUE if there is a conflict between the selected option for the specified feature
  924. and other feature/option selections.
  925. FALSE if the selected option for the specified feature is consistent with other
  926. feature/option selections.
  927. --*/
  928. {
  929. PINFOHEADER pInfoHdr;
  930. PUIINFO pUIInfo;
  931. PFEATURE pSpecifiedFeature, pFeature;
  932. DWORD dwPriority, dwFeature, dwOption;
  933. BOOL bConflict = FALSE;
  934. ASSERT(pOptions && pConflictPair);
  935. //
  936. // Get pointers to various data structures
  937. //
  938. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  939. ASSERT(pUIInfo != NULL);
  940. if ((pSpecifiedFeature = PGetIndexedFeature(pUIInfo, dwFeatureIndex)) == NULL ||
  941. (dwOptionIndex >= pSpecifiedFeature->Options.dwCount))
  942. {
  943. ASSERT(FALSE);
  944. return FALSE;
  945. }
  946. //
  947. // Check if the specified feature/option is constrained
  948. //
  949. for (dwFeature = 0;
  950. dwFeature < pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures;
  951. dwFeature ++)
  952. {
  953. if (dwFeature == dwFeatureIndex)
  954. continue;
  955. if (BCheckFeatureConflict(pUIInfo,
  956. pOptions,
  957. dwFeature,
  958. &dwOption,
  959. dwFeatureIndex,
  960. dwOptionIndex))
  961. {
  962. pFeature = PGetIndexedFeature(pUIInfo, dwFeature);
  963. ASSERT(pFeature != NULL);
  964. //
  965. // Remember the highest priority conflict-pair
  966. //
  967. if (!bConflict || pFeature->dwPriority > dwPriority)
  968. {
  969. dwPriority = pFeature->dwPriority;
  970. if (dwPriority >= pSpecifiedFeature->dwPriority)
  971. {
  972. pConflictPair->dwFeatureIndex1 = dwFeature;
  973. pConflictPair->dwOptionIndex1 = dwOption;
  974. pConflictPair->dwFeatureIndex2 = dwFeatureIndex;
  975. pConflictPair->dwOptionIndex2 = dwOptionIndex;
  976. }
  977. else
  978. {
  979. pConflictPair->dwFeatureIndex1 = dwFeatureIndex;
  980. pConflictPair->dwOptionIndex1 = dwOptionIndex;
  981. pConflictPair->dwFeatureIndex2 = dwFeature;
  982. pConflictPair->dwOptionIndex2 = dwOption;
  983. }
  984. }
  985. bConflict = TRUE;
  986. }
  987. }
  988. return bConflict;
  989. }
  990. BOOL
  991. ChangeOptionsViaID(
  992. IN PINFOHEADER pInfoHdr,
  993. IN OUT POPTSELECT pOptions,
  994. IN DWORD dwFeatureID,
  995. IN PDEVMODE pDevmode
  996. )
  997. /*++
  998. Routine Description:
  999. Modifies an option array using the information in public devmode fields
  1000. Arguments:
  1001. pInfoHdr - Points to an instance of binary printer description data
  1002. pOptions - Points to the option array to be modified
  1003. dwFeatureID - Specifies which field(s) of the input devmode should be used
  1004. pDevmode - Specifies the input devmode
  1005. Return Value:
  1006. TRUE if successful, FALSE if the specified feature ID is not supported
  1007. or there is an error
  1008. Note:
  1009. We assume the input devmode fields have been validated by the caller.
  1010. --*/
  1011. {
  1012. PRAWBINARYDATA pRawData;
  1013. PUIINFO pUIInfo;
  1014. PFEATURE pFeature;
  1015. DWORD dwFeatureIndex;
  1016. LONG lParam1, lParam2;
  1017. BOOL abEnabledOptions[MAX_PRINTER_OPTIONS];
  1018. PDWORD pdwPaperIndex = (PDWORD)abEnabledOptions;
  1019. DWORD dwCount, dwOptionIndex, i;
  1020. ASSERT(pOptions && pDevmode);
  1021. //
  1022. // Get a pointer to the FEATURE structure corresponding to
  1023. // the specified feature ID.
  1024. //
  1025. pRawData = (PRAWBINARYDATA) pInfoHdr;
  1026. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  1027. ASSERT(pUIInfo != NULL);
  1028. if ((dwFeatureID >= MAX_GID) ||
  1029. (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, dwFeatureID)) == NULL)
  1030. {
  1031. VERBOSE(("ChangeOptionsViaID failed: feature ID = %d\n", dwFeatureID));
  1032. SetLastError(ERROR_NOT_SUPPORTED);
  1033. return FALSE;
  1034. }
  1035. dwFeatureIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pFeature);
  1036. //
  1037. // Handle it according to what dwFeatureID is specified
  1038. //
  1039. lParam1 = lParam2 = 0;
  1040. switch (dwFeatureID)
  1041. {
  1042. case GID_PAGESIZE:
  1043. //
  1044. // Don't select any PageRegion option by default
  1045. //
  1046. {
  1047. PFEATURE pPageRgnFeature;
  1048. DWORD dwPageRgnIndex;
  1049. if (pPageRgnFeature = GET_PREDEFINED_FEATURE(pUIInfo, GID_PAGEREGION))
  1050. {
  1051. dwPageRgnIndex = GET_INDEX_FROM_FEATURE(pUIInfo, pPageRgnFeature);
  1052. pOptions[dwPageRgnIndex].ubCurOptIndex =
  1053. (BYTE) pPageRgnFeature->dwNoneFalseOptIndex;
  1054. }
  1055. }
  1056. //
  1057. // If the devmode specifies PostScript custom page size,
  1058. // we assume the parameters have already been validated
  1059. // during devmode merge proces. So here we simply return
  1060. // the custom page size option index.
  1061. //
  1062. if ((pDevmode->dmFields & DM_PAPERSIZE) &&
  1063. (pDevmode->dmPaperSize == DMPAPER_CUSTOMSIZE))
  1064. {
  1065. ASSERT(SUPPORT_CUSTOMSIZE(pUIInfo));
  1066. pOptions[dwFeatureIndex].ubCurOptIndex = (BYTE) pUIInfo->dwCustomSizeOptIndex;
  1067. return TRUE;
  1068. }
  1069. lParam1 = pDevmode->dmPaperWidth * DEVMODE_PAPER_UNIT;
  1070. lParam2 = pDevmode->dmPaperLength * DEVMODE_PAPER_UNIT;
  1071. break;
  1072. case GID_INPUTSLOT:
  1073. lParam1 = pDevmode->dmDefaultSource;
  1074. break;
  1075. case GID_RESOLUTION:
  1076. //
  1077. // If none is set, this function is not called with par. GID_RESOLUTION
  1078. //
  1079. ASSERT(pDevmode->dmFields & (DM_PRINTQUALITY | DM_YRESOLUTION));
  1080. switch (pDevmode->dmFields & (DM_PRINTQUALITY | DM_YRESOLUTION))
  1081. {
  1082. case DM_PRINTQUALITY: // set both if only one is set
  1083. lParam1 = lParam2 = pDevmode->dmPrintQuality;
  1084. break;
  1085. case DM_YRESOLUTION: // set both if only one is set
  1086. lParam1 = lParam2 = pDevmode->dmYResolution;
  1087. break;
  1088. default:
  1089. lParam1 = pDevmode->dmPrintQuality;
  1090. lParam2 = pDevmode->dmYResolution;
  1091. break;
  1092. }
  1093. break;
  1094. case GID_DUPLEX:
  1095. lParam1 = pDevmode->dmDuplex;
  1096. break;
  1097. case GID_MEDIATYPE:
  1098. lParam1 = pDevmode->dmMediaType;
  1099. break;
  1100. case GID_COLLATE:
  1101. lParam1 = pDevmode->dmCollate;
  1102. break;
  1103. default:
  1104. VERBOSE(("ChangeOptionsViaID failed: feature ID = %d\n", dwFeatureID));
  1105. SetLastError(ERROR_NOT_SUPPORTED);
  1106. return FALSE;
  1107. }
  1108. ASSERT(pFeature->dwUIType != UITYPE_PICKMANY);
  1109. if (dwFeatureID == GID_PAGESIZE)
  1110. {
  1111. dwCount = DwInternalMapToOptIndex(pUIInfo, pFeature, lParam1, lParam2, pdwPaperIndex);
  1112. if (dwCount == 0 )
  1113. return TRUE;
  1114. if (dwCount > 1 )
  1115. {
  1116. POPTION pOption;
  1117. LPCTSTR pDisplayName;
  1118. for (i = 0; i < dwCount; i++)
  1119. {
  1120. if (pOption = PGetIndexedOption(pUIInfo, pFeature, pdwPaperIndex[i]))
  1121. {
  1122. if ((pDisplayName = OFFSET_TO_POINTER(pRawData, pOption->loDisplayName)) &&
  1123. (_tcsicmp(pDevmode->dmFormName, pDisplayName) == EQUAL_STRING) )
  1124. {
  1125. dwOptionIndex = pdwPaperIndex[i];
  1126. break;
  1127. }
  1128. }
  1129. }
  1130. if (i >= dwCount)
  1131. dwOptionIndex = pdwPaperIndex[0];
  1132. }
  1133. else
  1134. dwOptionIndex = pdwPaperIndex[0];
  1135. pOptions[dwFeatureIndex].ubCurOptIndex = (BYTE)dwOptionIndex;
  1136. }
  1137. else
  1138. {
  1139. pOptions[dwFeatureIndex].ubCurOptIndex =
  1140. (BYTE) DwInternalMapToOptIndex(pUIInfo, pFeature, lParam1, lParam2, NULL);
  1141. }
  1142. return TRUE;
  1143. }
  1144. DWORD
  1145. MapToDeviceOptIndex(
  1146. IN PINFOHEADER pInfoHdr,
  1147. IN DWORD dwFeatureID,
  1148. IN LONG lParam1,
  1149. IN LONG lParam2,
  1150. OUT PDWORD pdwOptionIndexes
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. Map logical values to device feature option index
  1155. Arguments:
  1156. pInfoHdr - Points to an instance of binary printer description data
  1157. dwFeatureID - Indicate which feature the logical values are related to
  1158. lParam1, lParam2 - Parameters depending on dwFeatureID
  1159. pdwOptionIndexes - if Not NULL, means fill this array with all indicies
  1160. which match the search criteria. In this case the return value
  1161. is the number of elements in the array initialized. Currently
  1162. we assume the array is large enough (256 elements).
  1163. (It should be non-NULL only for GID_PAGESIZE.)
  1164. dwFeatureID = GID_PAGESIZE:
  1165. map logical paper specification to physical page size option
  1166. lParam1 = paper width in microns
  1167. lParam2 = paper height in microns
  1168. dwFeatureID = GID_RESOLUTION:
  1169. map logical resolution to physical resolution option
  1170. lParam1 = x-resolution in dpi
  1171. lParam2 = y-resolution in dpi
  1172. Return Value:
  1173. If pdwOptionIndexes is NULL, returns index of the feature option corresponding
  1174. to the specified logical values; OPTION_INDEX_ANY if the specified logical
  1175. values cannot be mapped to any feature option.
  1176. If pdwOptionIndexes is not NULL (for GID_PAGESIZE), returns the number of elements
  1177. filled in the output buffer. Zero means the specified logical values cannot be mapped
  1178. to any feature option.
  1179. --*/
  1180. {
  1181. PRAWBINARYDATA pRawData;
  1182. PUIINFO pUIInfo;
  1183. PFEATURE pFeature;
  1184. //
  1185. // Get a pointer to the FEATURE structure corresponding to
  1186. // the specified feature ID.
  1187. //
  1188. pRawData = (PRAWBINARYDATA) pInfoHdr;
  1189. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  1190. ASSERT(pUIInfo != NULL);
  1191. if ((dwFeatureID >= MAX_GID) ||
  1192. (pFeature = GET_PREDEFINED_FEATURE(pUIInfo, dwFeatureID)) == NULL)
  1193. {
  1194. VERBOSE(("MapToDeviceOptIndex failed: feature ID = %d\n", dwFeatureID));
  1195. if (!pdwOptionIndexes)
  1196. return OPTION_INDEX_ANY;
  1197. else
  1198. return 0;
  1199. }
  1200. //
  1201. // pdwOptionIndexes can be non-NULL only if dwFeatureID is GID_PAGESIZE.
  1202. //
  1203. ASSERT(dwFeatureID == GID_PAGESIZE || pdwOptionIndexes == NULL);
  1204. return DwInternalMapToOptIndex(pUIInfo, pFeature, lParam1, lParam2, pdwOptionIndexes);
  1205. }
  1206. BOOL
  1207. CombineOptionArray(
  1208. IN PRAWBINARYDATA pRawData,
  1209. OUT POPTSELECT pCombinedOptions,
  1210. IN INT iMaxOptions,
  1211. IN POPTSELECT pDocOptions,
  1212. IN POPTSELECT pPrinterOptions
  1213. )
  1214. /*++
  1215. Routine Description:
  1216. Combine doc-sticky with printer-sticky option selections to form a single option array
  1217. Arguments:
  1218. pRawData - Points to raw binary printer description data
  1219. pCombinedOptions - Points to an array of OPTSELECTs for holding the combined options
  1220. iMaxOptions - Max number of entries in pCombinedOptions array
  1221. pDocOptions - Specifies the array of doc-sticky options
  1222. pPrinterOptions - Specifies the array of printer-sticky options
  1223. Return Value:
  1224. FALSE if the combined option array is not large enough to store
  1225. all the option values, TRUE otherwise.
  1226. Note:
  1227. Either pDocOptions or pPrinterOptions could be NULL but not both. If pDocOptions
  1228. is NULL, then in the combined option array, the options for document-sticky
  1229. features will be OPTION_INDEX_ANY. Same is true when pPrinterOptions is NULL.
  1230. --*/
  1231. {
  1232. PINFOHEADER pInfoHdr;
  1233. PUIINFO pUIInfo;
  1234. PFEATURE pFeatures;
  1235. INT iCount, iDocOptions, iPrinterOptions, iNext;
  1236. //
  1237. // Calculate the number of features: both doc-sticky and printer-sticky
  1238. //
  1239. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  1240. ASSERT(pUIInfo != NULL);
  1241. pFeatures = OFFSET_TO_POINTER(pInfoHdr, pUIInfo->loFeatureList);
  1242. iDocOptions = (INT) pRawData->dwDocumentFeatures;
  1243. iPrinterOptions = (INT) pRawData->dwPrinterFeatures;
  1244. iNext = iDocOptions + iPrinterOptions;
  1245. ASSERT(iNext <= iMaxOptions);
  1246. //
  1247. // Copy doc-sticky options into the combined array.
  1248. // Take care of the special case where pDocOptions is NULL.
  1249. //
  1250. if (pDocOptions == NULL)
  1251. {
  1252. for (iCount = 0; iCount < iDocOptions; iCount++)
  1253. {
  1254. pCombinedOptions[iCount].ubCurOptIndex = OPTION_INDEX_ANY;
  1255. pCombinedOptions[iCount].ubNext = NULL_OPTSELECT;
  1256. }
  1257. }
  1258. else
  1259. {
  1260. for (iCount = 0; iCount < iDocOptions; iCount++)
  1261. {
  1262. VCopyOptionSelections(pCombinedOptions,
  1263. iCount,
  1264. pDocOptions,
  1265. iCount,
  1266. &iNext,
  1267. iMaxOptions);
  1268. }
  1269. }
  1270. //
  1271. // Copy printer-sticky options into the combined option array.
  1272. //
  1273. if (pPrinterOptions == NULL)
  1274. {
  1275. for (iCount = 0; iCount < iPrinterOptions; iCount++)
  1276. {
  1277. pCombinedOptions[iCount + iDocOptions].ubCurOptIndex = OPTION_INDEX_ANY;
  1278. pCombinedOptions[iCount + iDocOptions].ubNext = NULL_OPTSELECT;
  1279. }
  1280. }
  1281. else
  1282. {
  1283. for (iCount = 0; iCount < iPrinterOptions; iCount++)
  1284. {
  1285. VCopyOptionSelections(pCombinedOptions,
  1286. iCount + iDocOptions,
  1287. pPrinterOptions,
  1288. iCount,
  1289. &iNext,
  1290. iMaxOptions);
  1291. }
  1292. }
  1293. if (iNext > iMaxOptions)
  1294. WARNING(("Option array too small: size = %d, needed = %d\n", iMaxOptions, iNext));
  1295. return (iNext <= iMaxOptions);
  1296. }
  1297. BOOL
  1298. SeparateOptionArray(
  1299. IN PRAWBINARYDATA pRawData,
  1300. IN POPTSELECT pCombinedOptions,
  1301. OUT POPTSELECT pOptions,
  1302. IN INT iMaxOptions,
  1303. IN INT iMode
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. Separate an option array into doc-sticky and for printer-sticky options
  1308. Arguments:
  1309. pRawData - Points to raw binary printer description data
  1310. pCombinedOptions - Points to the combined option array to be separated
  1311. pOptions - Points to an array of OPTSELECT structures
  1312. for storing the separated option array
  1313. iMaxOptions - Max number of entries in pOptions array
  1314. iMode - Whether the caller is interested in doc- or printer-sticky options:
  1315. MODE_DOCUMENT_STICKY
  1316. MODE_PRINTER_STICKY
  1317. Return Value:
  1318. FALSE if the destination option array is not large enough to hold
  1319. the separated option values, TRUE otherwise.
  1320. --*/
  1321. {
  1322. INT iStart, iCount, iOptions, iNext;
  1323. //
  1324. // Determine if the caller is interested in doc-sticky or printer-sticky options
  1325. //
  1326. if (iMode == MODE_DOCUMENT_STICKY)
  1327. {
  1328. iStart = 0;
  1329. iOptions = (INT) pRawData->dwDocumentFeatures;
  1330. }
  1331. else
  1332. {
  1333. ASSERT (iMode == MODE_PRINTER_STICKY);
  1334. iStart = (INT) pRawData->dwDocumentFeatures;
  1335. iOptions = (INT) pRawData->dwPrinterFeatures;
  1336. }
  1337. iNext = iOptions;
  1338. ASSERT(iNext <= iMaxOptions);
  1339. //
  1340. // Separate the requested options out of the combined option array
  1341. //
  1342. for (iCount = 0; iCount < iOptions; iCount++)
  1343. {
  1344. VCopyOptionSelections(pOptions,
  1345. iCount,
  1346. pCombinedOptions,
  1347. iStart + iCount,
  1348. &iNext,
  1349. iMaxOptions);
  1350. }
  1351. if (iNext > iMaxOptions)
  1352. WARNING(("Option array too small: size = %d, needed = %d\n", iMaxOptions, iNext));
  1353. return (iNext <= iMaxOptions);
  1354. }
  1355. BOOL
  1356. ReconstructOptionArray(
  1357. IN PRAWBINARYDATA pRawData,
  1358. IN OUT POPTSELECT pOptions,
  1359. IN INT iMaxOptions,
  1360. IN DWORD dwFeatureIndex,
  1361. IN PBOOL pbSelectedOptions
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. Modify an option array to change the selected options for the specified feature
  1366. Arguments:
  1367. pRawData - Points to raw binary printer description data
  1368. pOptions - Points to an array of OPTSELECT structures to be modified
  1369. iMaxOptions - Max number of entries in pOptions array
  1370. dwFeatureIndex - Specifies the index of printer feature in question
  1371. pbSelectedOptions - Which options of the specified feature is selected
  1372. Return Value:
  1373. FALSE if the input option array is not large enough to hold
  1374. all modified option values. TRUE otherwise.
  1375. Note:
  1376. Number of BOOLs in pSelectedOptions must match the number of options
  1377. for the specified feature.
  1378. This function always leaves the option array in a compact format (i.e.
  1379. all unused entries are left at the end of the array).
  1380. --*/
  1381. {
  1382. INT iNext, iCount, iDest;
  1383. DWORD dwIndex;
  1384. PINFOHEADER pInfoHdr;
  1385. PUIINFO pUIInfo;
  1386. PFEATURE pFeature;
  1387. POPTSELECT pTempOptions;
  1388. ASSERT(pOptions && pbSelectedOptions);
  1389. //
  1390. // Get pointers to various data structures
  1391. //
  1392. PPD_GET_UIINFO_FROM_RAWDATA(pRawData, pInfoHdr, pUIInfo);
  1393. ASSERT(pUIInfo != NULL);
  1394. if (! (pFeature = PGetIndexedFeature(pUIInfo, dwFeatureIndex)))
  1395. {
  1396. ASSERT(FALSE);
  1397. return FALSE;
  1398. }
  1399. //
  1400. // Assume the entire input option array is used by default. This is
  1401. // not exactly true but it shouldn't have any adverse effects either.
  1402. //
  1403. iNext = iMaxOptions;
  1404. //
  1405. // Special case (faster) for non-PickMany UI types
  1406. //
  1407. if (pFeature->dwUIType != UITYPE_PICKMANY)
  1408. {
  1409. for (dwIndex = 0, iCount = 0;
  1410. dwIndex < pFeature->Options.dwCount;
  1411. dwIndex ++)
  1412. {
  1413. if (pbSelectedOptions[dwIndex])
  1414. {
  1415. pOptions[dwFeatureIndex].ubCurOptIndex = (BYTE) dwIndex;
  1416. ASSERT(pOptions[dwFeatureIndex].ubNext == NULL_OPTSELECT);
  1417. iCount++;
  1418. }
  1419. }
  1420. //
  1421. // Exactly one option is allowed to be selected
  1422. //
  1423. ASSERT(iCount == 1);
  1424. }
  1425. else
  1426. {
  1427. //
  1428. // Handle PickMany UI type:
  1429. // allocate a temporary option array and copy the input option values
  1430. // except the option values for the specified feature.
  1431. //
  1432. if (pTempOptions = MemAllocZ(iMaxOptions * sizeof(OPTSELECT)))
  1433. {
  1434. DWORD dwOptions;
  1435. dwOptions = pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures;
  1436. iNext = dwOptions;
  1437. if (iNext > iMaxOptions)
  1438. {
  1439. ASSERT(FALSE);
  1440. return FALSE;
  1441. }
  1442. for (dwIndex = 0; dwIndex < dwOptions; dwIndex++)
  1443. {
  1444. if (dwIndex != dwFeatureIndex)
  1445. {
  1446. VCopyOptionSelections(pTempOptions,
  1447. dwIndex,
  1448. pOptions,
  1449. dwIndex,
  1450. &iNext,
  1451. iMaxOptions);
  1452. }
  1453. }
  1454. //
  1455. // Reconstruct the option values for the specified feature
  1456. //
  1457. pTempOptions[dwFeatureIndex].ubCurOptIndex = OPTION_INDEX_ANY;
  1458. pTempOptions[dwFeatureIndex].ubNext = NULL_OPTSELECT;
  1459. iDest = dwFeatureIndex;
  1460. iCount = 0;
  1461. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex ++)
  1462. {
  1463. if (pbSelectedOptions[dwIndex])
  1464. {
  1465. if (iCount++ == 0)
  1466. {
  1467. //
  1468. // The first selected option
  1469. //
  1470. pTempOptions[iDest].ubCurOptIndex = (BYTE) dwIndex;
  1471. }
  1472. else
  1473. {
  1474. //
  1475. // Subsequent selected options
  1476. //
  1477. if (iNext < iMaxOptions)
  1478. {
  1479. pTempOptions[iDest].ubNext = (BYTE) iNext;
  1480. pTempOptions[iNext].ubCurOptIndex = (BYTE) dwIndex;
  1481. iDest = iNext;
  1482. }
  1483. iNext++;
  1484. }
  1485. }
  1486. }
  1487. pTempOptions[iDest].ubNext = NULL_OPTSELECT;
  1488. //
  1489. // Copy the reconstructed option array from the temporary buffer
  1490. // back to the input option array provided by the caller.
  1491. //
  1492. CopyMemory(pOptions, pTempOptions, iMaxOptions * sizeof(OPTSELECT));
  1493. MemFree(pTempOptions);
  1494. }
  1495. else
  1496. {
  1497. ERR(("Cannot allocate memory for temporary option array\n"));
  1498. }
  1499. }
  1500. return (iNext <= iMaxOptions);
  1501. }
  1502. PTSTR
  1503. GenerateBpdFilename(
  1504. PTSTR ptstrPpdFilename
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. Generate a filename for the cached binary PPD data given a PPD filename
  1509. Arguments:
  1510. ptstrPpdFilename - Specifies the PPD filename
  1511. Return Value:
  1512. Pointer to BPD filename string, NULL if there is an error
  1513. --*/
  1514. {
  1515. PTSTR ptstrBpdFilename, ptstrExtension;
  1516. INT iLength;
  1517. //
  1518. // If the PPD filename has .PPD extension, replace it with .BPD extension.
  1519. // Otherwise, append .BPD extension at the end.
  1520. //
  1521. iLength = _tcslen(ptstrPpdFilename);
  1522. if ((ptstrExtension = _tcsrchr(ptstrPpdFilename, TEXT('.'))) == NULL ||
  1523. _tcsicmp(ptstrExtension, PPD_FILENAME_EXT) != EQUAL_STRING)
  1524. {
  1525. WARNING(("Bad PPD filename extension: %ws\n", ptstrPpdFilename));
  1526. ptstrExtension = ptstrPpdFilename + iLength;
  1527. iLength += _tcslen(BPD_FILENAME_EXT);
  1528. }
  1529. //
  1530. // Allocate memory and compose the BPD filename
  1531. //
  1532. if (ptstrBpdFilename = MemAlloc((iLength + 1) * sizeof(TCHAR)))
  1533. {
  1534. StringCchCopyW(ptstrBpdFilename, iLength + 1, ptstrPpdFilename);
  1535. //
  1536. // The first if-block ensures that (ptstrExtension - ptstrPpdFileName) is
  1537. // non-negative, and (iLength + 1) is greater than (ptstrExtension - ptstrPpdFileName).
  1538. //
  1539. StringCchCopyW(ptstrBpdFilename + (ptstrExtension - ptstrPpdFilename),
  1540. (iLength + 1) - (ptstrExtension - ptstrPpdFilename),
  1541. BPD_FILENAME_EXT);
  1542. VERBOSE(("BPD filename: %ws\n", ptstrBpdFilename));
  1543. }
  1544. else
  1545. {
  1546. ERR(("Memory allocation failed: %d\n", GetLastError()));
  1547. }
  1548. return ptstrBpdFilename;
  1549. }
  1550. PRAWBINARYDATA
  1551. PpdLoadCachedBinaryData(
  1552. PTSTR ptstrPpdFilename
  1553. )
  1554. /*++
  1555. Routine Description:
  1556. Load cached binary PPD data file into memory
  1557. Arguments:
  1558. ptstrPpdFilename - Specifies the PPD filename
  1559. Return Value:
  1560. Pointer to PPD data if successful, NULL if there is an error
  1561. --*/
  1562. {
  1563. HFILEMAP hFileMap;
  1564. DWORD dwSize;
  1565. PVOID pvData;
  1566. PTSTR ptstrBpdFilename;
  1567. PRAWBINARYDATA pRawData, pCopiedData;
  1568. BOOL bValidCache = FALSE;
  1569. //
  1570. // Generate BPD filename from the specified PPD filename
  1571. //
  1572. if (! (ptstrBpdFilename = GenerateBpdFilename(ptstrPpdFilename)))
  1573. return NULL;
  1574. //
  1575. // First map the data file into memory
  1576. //
  1577. if (! (hFileMap = MapFileIntoMemory(ptstrBpdFilename, &pvData, &dwSize)))
  1578. {
  1579. TERSE(("Couldn't map file '%ws' into memory: %d\n", ptstrBpdFilename, GetLastError()));
  1580. MemFree(ptstrBpdFilename);
  1581. return NULL;
  1582. }
  1583. //
  1584. // Verify size, parser version number, and signature.
  1585. // Allocate a memory buffer and copy data into it.
  1586. //
  1587. pRawData = pvData;
  1588. pCopiedData = NULL;
  1589. if ((dwSize > sizeof(INFOHEADER) + sizeof(UIINFO) + sizeof(PPDDATA)) &&
  1590. (dwSize >= pRawData->dwFileSize) &&
  1591. (pRawData->dwParserVersion == PPD_PARSER_VERSION) &&
  1592. (pRawData->dwParserSignature == PPD_PARSER_SIGNATURE) &&
  1593. (BIsRawBinaryDataUpToDate(pRawData)))
  1594. {
  1595. #ifndef WINNT_40
  1596. PPPDDATA pPpdData;
  1597. //
  1598. // For Win2K+ systems, we support MUI where user can switch UI language
  1599. // and MUI knows to redirect resource loading calls to the correct resource
  1600. // DLL (built by MUI). However, PPD parser caches some display names into
  1601. // the .bpd file, where the display names are obtained based on the UI
  1602. // language when the parsing occurs. To support MUI, we store the UI language
  1603. // ID into the .bpd file and now if we see the current user's UI language ID
  1604. // doesn't match to the one stored in the .bpd file, we need to throw away
  1605. // the old .bpd file and reparse the .ppd, so we can get correct display names
  1606. // under current UI language.
  1607. //
  1608. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER)pRawData);
  1609. if (pPpdData && pPpdData->dwUserDefUILangID == (DWORD)GetUserDefaultUILanguage())
  1610. {
  1611. bValidCache = TRUE;
  1612. }
  1613. #else
  1614. bValidCache = TRUE;
  1615. #endif // !WINNT_40
  1616. }
  1617. if (bValidCache &&
  1618. (pCopiedData = MemAlloc(dwSize)))
  1619. {
  1620. CopyMemory(pCopiedData, pRawData, dwSize);
  1621. }
  1622. else
  1623. {
  1624. ERR(("Invalid binary PPD data\n"));
  1625. SetLastError(ERROR_INVALID_DATA);
  1626. }
  1627. MemFree(ptstrBpdFilename);
  1628. UnmapFileFromMemory(hFileMap);
  1629. return pCopiedData;
  1630. }
  1631. BOOL
  1632. BSearchConstraintList(
  1633. PUIINFO pUIInfo,
  1634. DWORD dwConstraintIndex,
  1635. DWORD dwFeature,
  1636. DWORD dwOption
  1637. )
  1638. /*++
  1639. Routine Description:
  1640. Check if the specified feature/option appears in a constraint list
  1641. Arguments:
  1642. pUIInfo - Points to a UIINFO structure
  1643. dwConstraintIndex - Specifies the constraint list to be searched
  1644. dwFeature, dwOption - Specifies the feature/option we're interested in
  1645. Return Value:
  1646. TRUE if dwFeature/dwOption appears on the specified constraint list
  1647. FALSE otherwise
  1648. --*/
  1649. {
  1650. PUICONSTRAINT pConstraint;
  1651. BOOL bMatch = FALSE;
  1652. pConstraint = OFFSET_TO_POINTER(pUIInfo->pInfoHeader, pUIInfo->UIConstraints.loOffset);
  1653. //
  1654. // Go through each item on the constraint list
  1655. //
  1656. while (!bMatch && (dwConstraintIndex != NULL_CONSTRAINT))
  1657. {
  1658. ASSERT(dwConstraintIndex < pUIInfo->UIConstraints.dwCount);
  1659. if (pConstraint[dwConstraintIndex].dwFeatureIndex == dwFeature)
  1660. {
  1661. //
  1662. // If the option index is OPTION_INDEX_ANY, it matches
  1663. // any option other than None/False.
  1664. //
  1665. if (pConstraint[dwConstraintIndex].dwOptionIndex == OPTION_INDEX_ANY)
  1666. {
  1667. PFEATURE pFeature;
  1668. pFeature = PGetIndexedFeature(pUIInfo, dwFeature);
  1669. ASSERT(pFeature != NULL);
  1670. bMatch = (pFeature->dwNoneFalseOptIndex != dwOption);
  1671. }
  1672. else
  1673. {
  1674. bMatch = (pConstraint[dwConstraintIndex].dwOptionIndex == dwOption);
  1675. }
  1676. }
  1677. dwConstraintIndex = pConstraint[dwConstraintIndex].dwNextConstraint;
  1678. }
  1679. return bMatch;
  1680. }
  1681. BOOL
  1682. BCheckFeatureOptionConflict(
  1683. PUIINFO pUIInfo,
  1684. DWORD dwFeature1,
  1685. DWORD dwOption1,
  1686. DWORD dwFeature2,
  1687. DWORD dwOption2
  1688. )
  1689. /*++
  1690. Routine Description:
  1691. Check if there is a conflict between a pair of feature/options
  1692. Arguments:
  1693. pUIInfo - Points to a UIINFO structure
  1694. dwFeature1, dwOption1 - Specifies the first feature/option
  1695. dwFeature2, dwOption2 - Specifies the second feature/option
  1696. Return Value:
  1697. TRUE if dwFeature1/dwOption1 constrains dwFeature2/dwOption2,
  1698. FALSE otherwise
  1699. --*/
  1700. {
  1701. PFEATURE pFeature;
  1702. POPTION pOption;
  1703. //
  1704. // Check for special case:
  1705. // either dwOption1 or dwOption2 is OPTION_INDEX_ANY
  1706. //
  1707. if ((dwOption1 == OPTION_INDEX_ANY) ||
  1708. (dwOption2 == OPTION_INDEX_ANY) ||
  1709. (dwFeature1 == dwFeature2 && dwOption1 == dwOption2))
  1710. {
  1711. return FALSE;
  1712. }
  1713. //
  1714. // Go through the constraint list associated with dwFeature1
  1715. //
  1716. if (! (pFeature = PGetIndexedFeature(pUIInfo, dwFeature1)))
  1717. return FALSE;
  1718. if ((dwOption1 != pFeature->dwNoneFalseOptIndex) &&
  1719. BSearchConstraintList(pUIInfo,
  1720. pFeature->dwUIConstraintList,
  1721. dwFeature2,
  1722. dwOption2))
  1723. {
  1724. return TRUE;
  1725. }
  1726. //
  1727. // Go through the constraint list associated with dwFeature1/dwOption1
  1728. //
  1729. if ((pOption = PGetIndexedOption(pUIInfo, pFeature, dwOption1)) &&
  1730. BSearchConstraintList(pUIInfo,
  1731. pOption->dwUIConstraintList,
  1732. dwFeature2,
  1733. dwOption2))
  1734. {
  1735. return TRUE;
  1736. }
  1737. //
  1738. // Automatically check the reciprocal constraint for:
  1739. // (dwFeature2, dwOption2) => (dwFeature1, dwOption1)
  1740. //
  1741. if (! (pFeature = PGetIndexedFeature(pUIInfo, dwFeature2)))
  1742. return FALSE;
  1743. if ((dwOption2 != pFeature->dwNoneFalseOptIndex) &&
  1744. BSearchConstraintList(pUIInfo,
  1745. pFeature->dwUIConstraintList,
  1746. dwFeature1,
  1747. dwOption1))
  1748. {
  1749. return TRUE;
  1750. }
  1751. if ((pOption = PGetIndexedOption(pUIInfo, pFeature, dwOption2)) &&
  1752. BSearchConstraintList(pUIInfo,
  1753. pOption->dwUIConstraintList,
  1754. dwFeature1,
  1755. dwOption1))
  1756. {
  1757. return TRUE;
  1758. }
  1759. return FALSE;
  1760. }
  1761. BOOL
  1762. BCheckFeatureConflict(
  1763. PUIINFO pUIInfo,
  1764. POPTSELECT pOptions,
  1765. DWORD dwFeature1,
  1766. PDWORD pdwOption1,
  1767. DWORD dwFeature2,
  1768. DWORD dwOption2
  1769. )
  1770. /*++
  1771. Routine Description:
  1772. Check if there is a conflict between the current option selections
  1773. of a feature and the specified feature/option
  1774. Arguments:
  1775. pUIInfo - Points to a UIINFO structure
  1776. pOptions - Points to the current feature option selections
  1777. dwFeature1 - Specifies the feature whose current option selections we're interested in
  1778. pdwOption1 - In case of a conflict, returns the option of dwFeature1
  1779. which caused the conflict
  1780. dwFeature2, dwOption2 - Specifies the feature/option to be checked
  1781. Return Value:
  1782. TRUE if there is a conflict between the current selections of dwFeature1
  1783. and dwFeature2/dwOption2, FALSE otherwise.
  1784. --*/
  1785. {
  1786. DWORD dwIndex = dwFeature1;
  1787. do
  1788. {
  1789. if (BCheckFeatureOptionConflict(pUIInfo,
  1790. dwFeature1,
  1791. pOptions[dwIndex].ubCurOptIndex,
  1792. dwFeature2,
  1793. dwOption2))
  1794. {
  1795. *pdwOption1 = pOptions[dwIndex].ubCurOptIndex;
  1796. return TRUE;
  1797. }
  1798. dwIndex = pOptions[dwIndex].ubNext;
  1799. } while (dwIndex != NULL_OPTSELECT);
  1800. return FALSE;
  1801. }
  1802. DWORD
  1803. DwReplaceFeatureOption(
  1804. PUIINFO pUIInfo,
  1805. POPTSELECT pOptions,
  1806. DWORD dwFeatureIndex,
  1807. DWORD dwOptionIndex,
  1808. DWORD dwHint
  1809. )
  1810. /*++
  1811. Routine Description:
  1812. description-of-function
  1813. Arguments:
  1814. pUIInfo - Points to UIINFO structure
  1815. pOptions - Points to the options array to be modified
  1816. dwFeatureIndex, dwOptionIndex - Specifies the feature/option to be replaced
  1817. dwHint - Hint on how to replace the specified feature option.
  1818. Return Value:
  1819. New hint value to be used next time this function is called on the same feature.
  1820. Note:
  1821. HIWORD of dwHint should be returned untouched. LOWORD of dwHint is
  1822. used by this function to determine how to replace the specified feature/option.
  1823. --*/
  1824. {
  1825. PFEATURE pFeature;
  1826. DWORD dwNext;
  1827. pFeature = PGetIndexedFeature(pUIInfo, dwFeatureIndex);
  1828. ASSERT(pFeature != NULL);
  1829. if (pFeature->dwUIType == UITYPE_PICKMANY)
  1830. {
  1831. //
  1832. // For PickMany feature, simply unselect the specified feature option.
  1833. //
  1834. dwNext = dwFeatureIndex;
  1835. while ((pOptions[dwNext].ubCurOptIndex != dwOptionIndex) &&
  1836. (dwNext = pOptions[dwNext].ubNext) != NULL_OPTSELECT)
  1837. {
  1838. }
  1839. if (dwNext != NULL_OPTSELECT)
  1840. {
  1841. DWORD dwLast;
  1842. pOptions[dwNext].ubCurOptIndex = OPTION_INDEX_ANY;
  1843. //
  1844. // Compact the list of selected options for the specified
  1845. // feature to filter out any redundant OPTION_INDEX_ANY entries.
  1846. //
  1847. dwLast = dwNext = dwFeatureIndex;
  1848. do
  1849. {
  1850. if (pOptions[dwNext].ubCurOptIndex != OPTION_INDEX_ANY)
  1851. {
  1852. pOptions[dwLast].ubCurOptIndex = pOptions[dwNext].ubCurOptIndex;
  1853. dwLast = pOptions[dwLast].ubNext;
  1854. }
  1855. dwNext = pOptions[dwNext].ubNext;
  1856. }
  1857. while (dwNext != NULL_OPTSELECT);
  1858. pOptions[dwLast].ubNext = NULL_OPTSELECT;
  1859. }
  1860. else
  1861. {
  1862. ERR(("Trying to replace non-existent feature/option.\n"));
  1863. }
  1864. return dwHint;
  1865. }
  1866. else
  1867. {
  1868. //
  1869. // For non-PickMany feature, use the hint paramater to determine
  1870. // how to replace the specified feature option:
  1871. //
  1872. // If this is the first time we're trying to replace the
  1873. // selected option of the specified feature, then we'll
  1874. // replace it with the default option for that feature.
  1875. //
  1876. // Otherwise, we'll try each option of the specified feature in turn.
  1877. //
  1878. // If we've exhausted all of the options for the specified
  1879. // (which should happen if the PPD file is well-formed),
  1880. // then we'll use OPTION_INDEX_ANY as the last resort.
  1881. //
  1882. dwNext = dwHint & 0xffff;
  1883. if (dwNext == 0)
  1884. dwOptionIndex = pFeature->dwDefaultOptIndex;
  1885. else if (dwNext > pFeature->Options.dwCount)
  1886. dwOptionIndex = OPTION_INDEX_ANY;
  1887. else
  1888. dwOptionIndex = dwNext - 1;
  1889. pOptions[dwFeatureIndex].ubCurOptIndex = (BYTE) dwOptionIndex;
  1890. return (dwHint & 0xffff0000) | (dwNext + 1);
  1891. }
  1892. }
  1893. DWORD
  1894. DwInternalMapToOptIndex(
  1895. PUIINFO pUIInfo,
  1896. PFEATURE pFeature,
  1897. LONG lParam1,
  1898. LONG lParam2,
  1899. OUT PDWORD pdwOptionIndexes
  1900. )
  1901. /*++
  1902. Routine Description:
  1903. Map logical values to device feature option index
  1904. Arguments:
  1905. pUIInfo - Points to UIINFO structure
  1906. pFeature - Specifies the interested feature
  1907. lParam1, lParam2 - Parameters depending on pFeature->dwFeatureID
  1908. pdwOptionIndexes - if Not NULL, means fill this array with all indicies
  1909. which match the search criteria. In this case the return value
  1910. is the number of elements in the array initialized. Currently
  1911. we assume the array is large enough (256 elements).
  1912. (It should be non-NULL only for GID_PAGESIZE.)
  1913. GID_PAGESIZE:
  1914. map logical paper specification to physical PageSize option
  1915. lParam1 = paper width in microns
  1916. lParam2 = paper height in microns
  1917. GID_RESOLUTION:
  1918. map logical resolution to physical Resolution option
  1919. lParam1 = x-resolution in dpi
  1920. lParam2 = y-resolution in dpi
  1921. GID_INPUTSLOT:
  1922. map logical paper source to physical InputSlot option
  1923. lParam1 = DEVMODE.dmDefaultSource
  1924. GID_DUPLEX:
  1925. map logical duplex selection to physical Duplex option
  1926. lParam1 = DEVMODE.dmDuplex
  1927. GID_COLLATE:
  1928. map logical collate selection to physical Collate option
  1929. lParam1 = DEVMODE.dmCollate
  1930. GID_MEDIATYPE:
  1931. map logical media type to physical MediaType option
  1932. lParam1 = DEVMODE.dmMediaType
  1933. Return Value:
  1934. If pdwOptionIndexes is NULL, returns index of the feature option corresponding
  1935. to the specified logical values; OPTION_INDEX_ANY if the specified logical
  1936. values cannot be mapped to any feature option.
  1937. If pdwOptionIndexes is not NULL (for GID_PAGESIZE), returns the number of elements
  1938. filled in the output buffer. Zero means the specified logical values cannot be mapped
  1939. to any feature option.
  1940. --*/
  1941. {
  1942. DWORD dwIndex, dwOptionIndex;
  1943. //
  1944. // Handle it according to what dwFeatureID is specified
  1945. //
  1946. dwOptionIndex = pFeature->dwNoneFalseOptIndex;
  1947. switch (pFeature->dwFeatureID)
  1948. {
  1949. case GID_PAGESIZE:
  1950. {
  1951. PPAGESIZE pPaper;
  1952. LONG lXDelta, lYDelta;
  1953. DWORD dwExactMatch;
  1954. //
  1955. // lParam1 = paper width
  1956. // lParam1 = paper height
  1957. //
  1958. //
  1959. // Go through the list of paper sizes supported by the printer
  1960. // and see if we can find an exact match to the requested size.
  1961. // (The tolerance is 1mm). If not, remember the closest match found.
  1962. //
  1963. dwExactMatch = 0;
  1964. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++)
  1965. {
  1966. pPaper = PGetIndexedOption(pUIInfo, pFeature, dwIndex);
  1967. ASSERT(pPaper != NULL);
  1968. //
  1969. // Custom page size is handled differently - skip it here.
  1970. //
  1971. if (pPaper->dwPaperSizeID == DMPAPER_CUSTOMSIZE)
  1972. continue;
  1973. lXDelta = abs(pPaper->szPaperSize.cx - lParam1);
  1974. lYDelta = abs(pPaper->szPaperSize.cy - lParam2);
  1975. if (lXDelta <= 1000 && lYDelta <= 1000)
  1976. {
  1977. //
  1978. // Exact match is found
  1979. //
  1980. if (pdwOptionIndexes)
  1981. {
  1982. pdwOptionIndexes[dwExactMatch++] = dwIndex;
  1983. }
  1984. else
  1985. {
  1986. dwOptionIndex = dwIndex;
  1987. break;
  1988. }
  1989. }
  1990. }
  1991. if (dwExactMatch > 0)
  1992. {
  1993. //
  1994. // Exact match(es) found
  1995. //
  1996. dwOptionIndex = dwExactMatch;
  1997. }
  1998. else if (dwIndex >= pFeature->Options.dwCount)
  1999. {
  2000. //
  2001. // No exact match found
  2002. //
  2003. if (SUPPORT_CUSTOMSIZE(pUIInfo) &&
  2004. BFormSupportedThruCustomSize((PRAWBINARYDATA) pUIInfo->pInfoHeader, lParam1, lParam2, NULL))
  2005. {
  2006. dwOptionIndex = pUIInfo->dwCustomSizeOptIndex;
  2007. }
  2008. else
  2009. {
  2010. //
  2011. // We used to use dwClosestIndex as dwOptionIndex here, but see bug #124203, we now
  2012. // choose to behave the same as Unidrv that if there is no exact match, we return no
  2013. // match instead of the cloest match.
  2014. //
  2015. dwOptionIndex = OPTION_INDEX_ANY;
  2016. }
  2017. if (pdwOptionIndexes)
  2018. {
  2019. if (dwOptionIndex == OPTION_INDEX_ANY)
  2020. dwOptionIndex = 0;
  2021. else
  2022. {
  2023. pdwOptionIndexes[0] = dwOptionIndex;
  2024. dwOptionIndex = 1;
  2025. }
  2026. }
  2027. }
  2028. }
  2029. break;
  2030. case GID_INPUTSLOT:
  2031. //
  2032. // lParam1 = DEVMODE.dmDefaultSource
  2033. //
  2034. dwOptionIndex = OPTION_INDEX_ANY;
  2035. if (lParam1 >= DMBIN_USER)
  2036. {
  2037. //
  2038. // An input slot is specifically requested.
  2039. //
  2040. dwIndex = lParam1 - DMBIN_USER;
  2041. if (dwIndex < pFeature->Options.dwCount)
  2042. dwOptionIndex = dwIndex;
  2043. }
  2044. else if (lParam1 == DMBIN_MANUAL || lParam1 == DMBIN_ENVMANUAL)
  2045. {
  2046. //
  2047. // Manual feed is requested
  2048. //
  2049. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex ++)
  2050. {
  2051. PINPUTSLOT pInputSlot;
  2052. if ((pInputSlot = PGetIndexedOption(pUIInfo, pFeature, dwIndex)) &&
  2053. (pInputSlot->dwPaperSourceID == DMBIN_MANUAL))
  2054. {
  2055. dwOptionIndex = dwIndex;
  2056. break;
  2057. }
  2058. }
  2059. }
  2060. if (dwOptionIndex == OPTION_INDEX_ANY)
  2061. {
  2062. //
  2063. // Treat all other cases as if no input slot is explicitly requested.
  2064. // At print time, the driver will choose an input slot based on
  2065. // the form-to-tray assignment table.
  2066. //
  2067. dwOptionIndex = 0;
  2068. }
  2069. break;
  2070. case GID_RESOLUTION:
  2071. //
  2072. // lParam1 = x-resolution
  2073. // lParam2 = y-resolution
  2074. //
  2075. {
  2076. PRESOLUTION pRes;
  2077. //
  2078. // check whether it's one of the predefined DMRES_-values
  2079. //
  2080. if ((lParam1 < 0) && (lParam2 < 0))
  2081. {
  2082. DWORD dwHiResId=0, dwLoResId, dwMedResId, dwDraftResId=0;
  2083. DWORD dwHiResProd=0, dwMedResProd=0, dwLoResProd= 0xffffffff, dwDraftResProd= 0xffffffff;
  2084. BOOL bValid = FALSE; // if there is at least one valid entry
  2085. DWORD dwResProd;
  2086. // no need to sort all the available options, just pick out the interesting ones
  2087. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++)
  2088. {
  2089. if ((pRes = PGetIndexedOption(pUIInfo, pFeature, dwIndex)) != NULL)
  2090. {
  2091. bValid = TRUE;
  2092. dwResProd = pRes->iXdpi * pRes->iYdpi; // use product as sort criteria
  2093. if (dwResProd > dwHiResProd) // take highest as high resolution
  2094. {
  2095. // previous max. is now second highest
  2096. dwMedResProd= dwHiResProd;
  2097. dwMedResId = dwHiResId;
  2098. dwHiResProd = dwResProd;
  2099. dwHiResId = dwIndex;
  2100. }
  2101. else if (dwResProd == dwHiResProd)
  2102. {
  2103. // duplicates possible, if e.g. 300x600 as well as 600x300 supported
  2104. // skip that
  2105. }
  2106. else if (dwResProd > dwMedResProd) // take second highest as medium,
  2107. { // can only be hit if not max.
  2108. dwMedResProd= dwResProd;
  2109. dwMedResId = dwIndex;
  2110. }
  2111. if (dwResProd < dwDraftResProd) // take lowest as draft
  2112. {
  2113. // previous min. is now second lowest
  2114. dwLoResProd = dwDraftResProd;
  2115. dwLoResId = dwDraftResId;
  2116. dwDraftResProd = dwResProd;
  2117. dwDraftResId = dwIndex;
  2118. }
  2119. else if (dwResProd == dwDraftResProd)
  2120. {
  2121. // duplicates possible, if e.g. 300x600 as well as 600x300 supported
  2122. // skip that
  2123. }
  2124. else if (dwResProd < dwLoResProd) // take second lowest as low
  2125. {// can only be hit if not min.
  2126. dwLoResProd = dwResProd;
  2127. dwLoResId = dwIndex;
  2128. }
  2129. }
  2130. }
  2131. if (!bValid) // no valid entry ?
  2132. {
  2133. return OPTION_INDEX_ANY;
  2134. }
  2135. //
  2136. // Correct medium, might not be touched if less than 3 resolution options
  2137. //
  2138. if (dwMedResProd == 0)
  2139. {
  2140. dwMedResProd = dwHiResProd;
  2141. dwMedResId = dwHiResId;
  2142. }
  2143. //
  2144. // Correct low, might not be touched if less than 3 resolution options
  2145. //
  2146. if (dwLoResProd == 0xffffffff)
  2147. {
  2148. dwLoResProd = dwDraftResProd;
  2149. dwLoResId = dwDraftResId;
  2150. }
  2151. //
  2152. // if different, take the higher of the requested resolutions
  2153. //
  2154. switch(min(lParam1, lParam2))
  2155. {
  2156. case DMRES_DRAFT:
  2157. return dwDraftResId;
  2158. case DMRES_LOW:
  2159. return dwLoResId;
  2160. case DMRES_MEDIUM:
  2161. return dwMedResId;
  2162. case DMRES_HIGH:
  2163. return dwHiResId;
  2164. }
  2165. //
  2166. // requested is not one of the known predefined values
  2167. //
  2168. return OPTION_INDEX_ANY;
  2169. }
  2170. //
  2171. // First try to match both x- and y-resolution exactly
  2172. //
  2173. dwOptionIndex = OPTION_INDEX_ANY;
  2174. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++)
  2175. {
  2176. if ((pRes = PGetIndexedOption(pUIInfo, pFeature, dwIndex)) &&
  2177. (pRes->iXdpi == lParam1) &&
  2178. (pRes->iYdpi == lParam2))
  2179. {
  2180. dwOptionIndex = dwIndex;
  2181. break;
  2182. }
  2183. }
  2184. if (dwOptionIndex != OPTION_INDEX_ANY)
  2185. break;
  2186. //
  2187. // If no exact match is found, then relax the criteria a bit and
  2188. // compare the max of x- and y-resolution.
  2189. //
  2190. lParam1 = max(lParam1, lParam2);
  2191. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++)
  2192. {
  2193. if ((pRes = PGetIndexedOption(pUIInfo, pFeature, dwIndex)) &&
  2194. (max(pRes->iXdpi, pRes->iYdpi) == lParam1))
  2195. {
  2196. dwOptionIndex = dwIndex;
  2197. break;
  2198. }
  2199. }
  2200. }
  2201. break;
  2202. case GID_DUPLEX:
  2203. //
  2204. // lParam1 = DEVMODE.dmDuplex
  2205. //
  2206. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++)
  2207. {
  2208. PDUPLEX pDuplex;
  2209. if ((pDuplex = PGetIndexedOption(pUIInfo, pFeature, dwIndex)) &&
  2210. ((LONG) pDuplex->dwDuplexID == lParam1))
  2211. {
  2212. dwOptionIndex = dwIndex;
  2213. break;
  2214. }
  2215. }
  2216. break;
  2217. case GID_COLLATE:
  2218. //
  2219. // lParam1 = DEVMODE.dmCollate
  2220. //
  2221. for (dwIndex = 0; dwIndex < pFeature->Options.dwCount; dwIndex++)
  2222. {
  2223. PCOLLATE pCollate;
  2224. if ((pCollate = PGetIndexedOption(pUIInfo, pFeature, dwIndex)) &&
  2225. ((LONG) pCollate->dwCollateID == lParam1))
  2226. {
  2227. dwOptionIndex = dwIndex;
  2228. break;
  2229. }
  2230. }
  2231. break;
  2232. case GID_MEDIATYPE:
  2233. //
  2234. // lParam1 = DEVMODE.dmMediaType
  2235. //
  2236. if (lParam1 >= DMMEDIA_USER)
  2237. {
  2238. dwIndex = lParam1 - DMMEDIA_USER;
  2239. if (dwIndex < pFeature->Options.dwCount)
  2240. dwOptionIndex = dwIndex;
  2241. }
  2242. break;
  2243. default:
  2244. VERBOSE(("DwInternalMapToOptIndex failed: feature ID = %d\n", pFeature->dwFeatureID));
  2245. break;
  2246. }
  2247. return dwOptionIndex;
  2248. }
  2249. PTSTR
  2250. PtstrGetDefaultTTSubstTable(
  2251. PUIINFO pUIInfo
  2252. )
  2253. /*++
  2254. Routine Description:
  2255. Return a copy of the default font substitution table
  2256. Arguments:
  2257. pUIInfo - Pointer to UIINFO structure
  2258. Return Value:
  2259. Pointer to a copy of the default font substitution table
  2260. NULL if there is an error
  2261. --*/
  2262. {
  2263. PTSTR ptstrDefault, ptstrTable = NULL;
  2264. DWORD dwSize;
  2265. //
  2266. // Make a copy of the default font substitution table
  2267. //
  2268. if ((ptstrDefault = OFFSET_TO_POINTER(pUIInfo->pubResourceData, pUIInfo->loFontSubstTable)) &&
  2269. (dwSize = pUIInfo->dwFontSubCount) &&
  2270. (ptstrTable = MemAlloc(dwSize)))
  2271. {
  2272. ASSERT(BVerifyMultiSZPair(ptstrDefault, dwSize));
  2273. CopyMemory(ptstrTable, ptstrDefault, dwSize);
  2274. }
  2275. return ptstrTable;
  2276. }
  2277. VOID
  2278. VConvertOptSelectArray(
  2279. PRAWBINARYDATA pRawData,
  2280. POPTSELECT pNt5Options,
  2281. DWORD dwNt5MaxCount,
  2282. PBYTE pubNt4Options,
  2283. DWORD dwNt4MaxCount,
  2284. INT iMode
  2285. )
  2286. /*++
  2287. Routine Description:
  2288. Convert NT4 feature/option selections to NT5 format
  2289. Arguments:
  2290. pRawData - Points to raw binary printer description data
  2291. pNt5Options - Points to NT5 feature/option selection array
  2292. pNt4Options - Points to NT4 feature/option selection array
  2293. iMode - Convert doc- or printer-sticky options?
  2294. Return Value:
  2295. NONE
  2296. --*/
  2297. {
  2298. PPPDDATA pPpdData;
  2299. PBYTE pubNt4Mapping;
  2300. DWORD dwNt5Index, dwNt5Offset, dwCount;
  2301. DWORD dwNt4Index, dwNt4Offset;
  2302. pPpdData = GET_DRIVER_INFO_FROM_INFOHEADER((PINFOHEADER) pRawData);
  2303. ASSERT(pPpdData != NULL);
  2304. //
  2305. // Determine whether we're converting doc-sticky or
  2306. // printer-sticky feature selections.
  2307. //
  2308. if (iMode == MODE_DOCUMENT_STICKY)
  2309. {
  2310. dwCount = pRawData->dwDocumentFeatures;
  2311. dwNt5Offset = dwNt4Offset = 0;
  2312. }
  2313. else
  2314. {
  2315. dwCount = pRawData->dwPrinterFeatures;
  2316. dwNt5Offset = pRawData->dwDocumentFeatures;
  2317. dwNt4Offset = pPpdData->dwNt4DocFeatures;
  2318. }
  2319. //
  2320. // Get a pointer to the NT4-NT5 feature index mapping table
  2321. //
  2322. pubNt4Mapping = OFFSET_TO_POINTER(pRawData, pPpdData->Nt4Mapping.loOffset);
  2323. ASSERT(pubNt4Mapping != NULL);
  2324. ASSERT(pPpdData->Nt4Mapping.dwCount ==
  2325. pRawData->dwDocumentFeatures + pRawData->dwPrinterFeatures);
  2326. //
  2327. // Convert the feature option selection array
  2328. //
  2329. for (dwNt5Index=0; dwNt5Index < dwCount; dwNt5Index++)
  2330. {
  2331. dwNt4Index = pubNt4Mapping[dwNt5Index + dwNt5Offset] - dwNt4Offset;
  2332. if (dwNt4Index < dwNt4MaxCount && pubNt4Options[dwNt4Index] != OPTION_INDEX_ANY)
  2333. pNt5Options[dwNt5Index].ubCurOptIndex = pubNt4Options[dwNt4Index];
  2334. }
  2335. }