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.

3834 lines
88 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. ppdkwd.c
  5. Abstract:
  6. Functions for interpreting the semantics elements of a PPD file
  7. Environment:
  8. PostScript driver, PPD parser
  9. Revision History:
  10. 09/30/96 -davidx-
  11. Cleaner handling of ManualFeed and AutoSelect feature.
  12. 08/20/96 -davidx-
  13. Common coding style for NT 5.0 drivers.
  14. 03/26/96 -davidx-
  15. Created it.
  16. --*/
  17. #include "lib.h"
  18. #include "ppd.h"
  19. #include "ppdparse.h"
  20. #include <math.h>
  21. //
  22. // Data structure for representing entries in a keyword table
  23. //
  24. typedef PPDERROR (*KWDPROC)(PPARSERDATA);
  25. typedef struct _KWDENTRY {
  26. PCSTR pstrKeyword; // keyword name
  27. KWDPROC pfnProc; // keyword handler function
  28. DWORD dwFlags; // misc. flag bits
  29. } KWDENTRY, *PKWDENTRY;
  30. //
  31. // Constants for KWDENTRY.flags field. The low order byte is used to indicate value types.
  32. //
  33. #define REQ_OPTION 0x0100
  34. #define ALLOW_MULTI 0x0200
  35. #define ALLOW_HEX 0x0400
  36. #define DEFAULT_PROC 0x0800
  37. #define INVOCA_VALUE (VALUETYPE_QUOTED | VALUETYPE_SYMBOL)
  38. #define QUOTED_VALUE (VALUETYPE_QUOTED | ALLOW_HEX)
  39. #define QUOTED_NOHEX VALUETYPE_QUOTED
  40. #define STRING_VALUE VALUETYPE_STRING
  41. #define GENERIC_ENTRY(featureId) ((featureId) << 16)
  42. //
  43. // Give a warning when there are duplicate entries for the same option
  44. //
  45. #define WARN_DUPLICATE() \
  46. TERSE(("%ws: Duplicate entries of '*%s %s' on line %d\n", \
  47. pParserData->pFile->ptstrFileName, \
  48. pParserData->achKeyword, \
  49. pParserData->achOption, \
  50. pParserData->pFile->iLineNumber))
  51. //
  52. // Default keyword prefix string
  53. //
  54. #define HAS_DEFAULT_PREFIX(pstr) \
  55. (strncmp((pstr), gstrDefault, strlen(gstrDefault)) == EQUAL_STRING)
  56. //
  57. // Determine whether a string starts with JCL prefix
  58. //
  59. #define HAS_JCL_PREFIX(pstr) (strncmp((pstr), "JCL", 3) == EQUAL_STRING)
  60. //
  61. // Forward declaration of local functions
  62. //
  63. PPDERROR IVerifyValueType(PPARSERDATA, DWORD);
  64. PPDERROR IGenericOptionProc(PPARSERDATA, PFEATUREOBJ);
  65. PPDERROR IGenericDefaultProc(PPARSERDATA, PFEATUREOBJ);
  66. PPDERROR IGenericQueryProc(PPARSERDATA, PFEATUREOBJ);
  67. PFEATUREOBJ PCreateFeatureItem(PPARSERDATA, DWORD);
  68. PKWDENTRY PSearchKeywordTable(PPARSERDATA, PSTR, PINT);
  69. PPDERROR
  70. IInterpretEntry(
  71. PPARSERDATA pParserData
  72. )
  73. /*++
  74. Routine Description:
  75. Interpret an entry parsed from a printer description file
  76. Arguments:
  77. pParserData - Points to parser data structure
  78. Return Value:
  79. Status code
  80. --*/
  81. {
  82. PSTR pstrKeyword, pstrRealKeyword;
  83. PPDERROR iStatus;
  84. PKWDENTRY pKwdEntry;
  85. INT iIndex;
  86. BOOL bQuery, bDefault;
  87. //
  88. // Get a pointer to the keyword string and look for
  89. // *? and *Default prefix in front of the keyword.
  90. //
  91. pstrRealKeyword = pstrKeyword = pParserData->achKeyword;
  92. bQuery = bDefault = FALSE;
  93. // NOTE: We don't have any use for query entries so don't parse them here.
  94. // This helps us somewhat to preserve the feature index from NT4.
  95. if (FALSE && *pstrKeyword == QUERY_CHAR)
  96. {
  97. bQuery = TRUE;
  98. pstrRealKeyword++;
  99. }
  100. else if (HAS_DEFAULT_PREFIX(pstrKeyword))
  101. {
  102. bDefault = TRUE;
  103. pstrRealKeyword += strlen(gstrDefault);
  104. }
  105. //
  106. // Set up a convenient pointer to the entry value
  107. //
  108. pParserData->pstrValue = (PSTR) pParserData->Value.pbuf;
  109. //
  110. // If we're within an OpenUI/CloseUI pair and the keyword
  111. // in the current entry matches what's in OpenUI, then we
  112. // will handle the current entry using a generic procedure.
  113. //
  114. if (pParserData->pOpenFeature &&
  115. pParserData->pOpenFeature->dwFeatureID == GID_UNKNOWN &&
  116. strcmp(pstrRealKeyword, pParserData->pOpenFeature->pstrName) == EQUAL_STRING)
  117. {
  118. pKwdEntry = NULL;
  119. }
  120. else
  121. {
  122. //
  123. // Find out if the keyword has built-in support
  124. //
  125. pKwdEntry = PSearchKeywordTable(pParserData, pstrRealKeyword, &iIndex);
  126. //
  127. // For *Default keywords, if we failed to find the keyword without
  128. // the prefix, try it again with the prefix.
  129. //
  130. if (bDefault &&
  131. (pKwdEntry == NULL || pKwdEntry->pfnProc != NULL) &&
  132. (pKwdEntry = PSearchKeywordTable(pParserData, pstrKeyword, &iIndex)))
  133. {
  134. bDefault = FALSE;
  135. }
  136. //
  137. // Ignore unsupported keywords
  138. //
  139. if ((pKwdEntry == NULL) ||
  140. ((bQuery || bDefault) && (pKwdEntry->pfnProc != NULL)))
  141. {
  142. VERBOSE(("Keyword not supported: *%s\n", pstrKeyword));
  143. return PPDERR_NONE;
  144. }
  145. }
  146. //
  147. // Determine if the entry should be handle by the generic procedure
  148. //
  149. if (pKwdEntry == NULL || pKwdEntry->pfnProc == NULL)
  150. {
  151. PFEATUREOBJ pFeature;
  152. DWORD dwValueType;
  153. PPDERROR (*pfnGenericProc)(PPARSERDATA, PFEATUREOBJ);
  154. //
  155. // Make sure the value type matches what's expected
  156. //
  157. if (bQuery)
  158. {
  159. pfnGenericProc = IGenericQueryProc;
  160. dwValueType = INVOCA_VALUE;
  161. }
  162. else if (bDefault)
  163. {
  164. pfnGenericProc = IGenericDefaultProc;
  165. dwValueType = STRING_VALUE;
  166. }
  167. else
  168. {
  169. pfnGenericProc = IGenericOptionProc;
  170. dwValueType = INVOCA_VALUE | REQ_OPTION;
  171. }
  172. if ((iStatus = IVerifyValueType(pParserData, dwValueType)) != PPDERR_NONE)
  173. return iStatus;
  174. //
  175. // Call the appropriate generic procedure
  176. //
  177. pFeature = (pKwdEntry == NULL) ?
  178. pParserData->pOpenFeature :
  179. PCreateFeatureItem(pParserData, HIWORD(pKwdEntry->dwFlags));
  180. return pfnGenericProc(pParserData, pFeature);
  181. }
  182. else
  183. {
  184. //
  185. // Screen out duplicate keyword entries
  186. //
  187. if (! (pKwdEntry->dwFlags & (ALLOW_MULTI|REQ_OPTION)))
  188. {
  189. if (pParserData->pubKeywordCounts[iIndex])
  190. {
  191. WARN_DUPLICATE();
  192. return PPDERR_NONE;
  193. }
  194. pParserData->pubKeywordCounts[iIndex]++;
  195. }
  196. //
  197. // Make sure the value type matches what's expected
  198. // Take care of embedded hexdecimal strings if necessary
  199. //
  200. if ((iStatus = IVerifyValueType(pParserData, pKwdEntry->dwFlags)) != PPDERR_NONE)
  201. return iStatus;
  202. //
  203. // Invoke the specific procedure to handle built-in keywords
  204. //
  205. return (pKwdEntry->pfnProc)(pParserData);
  206. }
  207. }
  208. PPDERROR
  209. IVerifyValueType(
  210. PPARSERDATA pParserData,
  211. DWORD dwExpectedType
  212. )
  213. /*++
  214. Routine Description:
  215. Verify the value type of the current entry matches what's expected
  216. Arguments:
  217. pParserData - Points to parser data structure
  218. dwExpectedType - Expected value type
  219. Return Value:
  220. Status code
  221. --*/
  222. {
  223. DWORD dwValueType;
  224. //
  225. // Check for following syntax error conditions:
  226. // 1. The entry requires an option keyword but no option keyword is present
  227. // 2. The entry doesn't require an option keyword but an option keyword is present
  228. //
  229. if ((dwExpectedType & REQ_OPTION) &&
  230. IS_BUFFER_EMPTY(&pParserData->Option))
  231. {
  232. return ISyntaxError(pParserData->pFile, "Missing option keyword");
  233. }
  234. if (! (dwExpectedType & REQ_OPTION) &&
  235. ! IS_BUFFER_EMPTY(&pParserData->Option))
  236. {
  237. return ISyntaxError(pParserData->pFile, "Extra option keyword");
  238. }
  239. //
  240. // Tolerate the following syntax error conditions:
  241. // 1. The entry requires a quoted value but a string value is provided.
  242. // 2. The entry requires a string value but a quoted value is provided.
  243. //
  244. switch (dwValueType = pParserData->dwValueType)
  245. {
  246. case VALUETYPE_STRING:
  247. if (dwExpectedType & VALUETYPE_QUOTED)
  248. {
  249. TERSE(("%ws: Expect QuotedValue instead of StringValue on line %d\n",
  250. pParserData->pFile->ptstrFileName,
  251. pParserData->pFile->iLineNumber));
  252. dwValueType = VALUETYPE_QUOTED;
  253. }
  254. break;
  255. case VALUETYPE_QUOTED:
  256. if (dwExpectedType & VALUETYPE_STRING)
  257. {
  258. TERSE(("%ws: Expect StringValue instead of QuotedValue on line %d\n",
  259. pParserData->pFile->ptstrFileName,
  260. pParserData->pFile->iLineNumber));
  261. if (IS_BUFFER_EMPTY(&pParserData->Value))
  262. return ISyntaxError(pParserData->pFile, "Empty string value");
  263. dwValueType = VALUETYPE_STRING;
  264. }
  265. break;
  266. }
  267. //
  268. // Return syntax error if the provided value type doesn't match what's expected
  269. //
  270. if ((dwExpectedType & dwValueType) == 0)
  271. return ISyntaxError(pParserData->pFile, "Value type mismatch");
  272. //
  273. // If the value field is a quoted string and one of the following conditions
  274. // is true, then we need to process any embedded hexdecimal strings within
  275. // the quoted string:
  276. // 1. The entry expects a QuotedValue.
  277. // 2. The entry expects an InvocationValue and appears inside JCLOpenUI/JCLCloseUI
  278. //
  279. if (dwValueType == VALUETYPE_QUOTED)
  280. {
  281. if ((dwExpectedType & ALLOW_HEX) ||
  282. ((dwExpectedType & VALUETYPE_MASK) == INVOCA_VALUE && pParserData->bJclFeature))
  283. {
  284. if (! BConvertHexString(&pParserData->Value))
  285. return ISyntaxError(pParserData->pFile, "Invalid embedded hexdecimal string");
  286. }
  287. else if (! BIs7BitAscii(pParserData->pstrValue))
  288. {
  289. //
  290. // Only allow 7-bit ASCII characters inside invocation string
  291. //
  292. return ISyntaxError(pParserData->pFile, "Non-printable ASCII character");
  293. }
  294. }
  295. return PPDERR_NONE;
  296. }
  297. BOOL
  298. BGetIntegerFromString(
  299. PSTR *ppstr,
  300. LONG *plValue
  301. )
  302. /*++
  303. Routine Description:
  304. Parse an unsigned decimal integer value from a character string
  305. Arguments:
  306. ppstr - Points to a string pointer. On entry, it contains a pointer
  307. to the beginning of the number string. On exit, it points to
  308. the first non-space character after the number string.
  309. plValue - Points to a variable for storing parsed number
  310. Return Value:
  311. TRUE if a number is successfully parsed, FALSE if there is an error
  312. --*/
  313. {
  314. LONG lValue;
  315. PSTR pstr = *ppstr;
  316. BOOL bNegative = FALSE;
  317. //
  318. // Skip any leading space characters and
  319. // look for the sign character (if any)
  320. //
  321. while (IS_SPACE(*pstr))
  322. pstr++;
  323. if (*pstr == '-')
  324. {
  325. bNegative = TRUE;
  326. pstr++;
  327. }
  328. if (! IS_DIGIT(*pstr))
  329. {
  330. TERSE(("Invalid integer number: %s\n", pstr));
  331. return FALSE;
  332. }
  333. //
  334. // NOTE: Overflow conditions are ignored.
  335. //
  336. lValue = 0;
  337. while (IS_DIGIT(*pstr))
  338. lValue = lValue * 10 + (*pstr++ - '0');
  339. //
  340. // Skip any trailing space characters
  341. //
  342. while (IS_SPACE(*pstr))
  343. pstr++;
  344. *ppstr = pstr;
  345. *plValue = bNegative ? -lValue : lValue;
  346. return TRUE;
  347. }
  348. BOOL
  349. BGetFloatFromString(
  350. PSTR *ppstr,
  351. PLONG plValue,
  352. INT iType
  353. )
  354. /*++
  355. Routine Description:
  356. Parse an unsigned floating-point number from a character string
  357. Arguments:
  358. ppstr - Points to a string pointer. On entry, it contains a pointer
  359. to the beginning of the number string. On exit, it points to
  360. the first non-space character after the number string.
  361. plValue - Points to a variable for storing the parsed number
  362. iType - How to convert the floating-point number before returning
  363. FLTYPE_FIX - convert it to 24.8 format fixed-point number
  364. FLTYPE_INT - convert it to integer
  365. FLTYPE_POINT - convert it from point to micron
  366. FLTYPE_POINT_ROUNDUP - round it up and convert it from point to micron
  367. FLTYPE_POINT_ROUNDDOWN - round it down and convert it from point to micron
  368. Return Value:
  369. TRUE if successful, FALSE if there is an error
  370. --*/
  371. {
  372. double value, scale;
  373. PSTR pstr = *ppstr;
  374. BOOL bNegative = FALSE, bFraction = FALSE;
  375. //
  376. // Skip any leading space characters and
  377. // look for the sign character (if any)
  378. //
  379. while (IS_SPACE(*pstr))
  380. pstr++;
  381. if (*pstr == '-')
  382. {
  383. bNegative = TRUE;
  384. pstr++;
  385. }
  386. if (!IS_DIGIT(*pstr) && *pstr != '.')
  387. {
  388. TERSE(("Invalid floating-point number\n"));
  389. return FALSE;
  390. }
  391. //
  392. // Integer portion
  393. //
  394. value = 0.0;
  395. while (IS_DIGIT(*pstr))
  396. value = value * 10.0 + (*pstr++ - '0');
  397. //
  398. // Fractional portion
  399. //
  400. if (*pstr == '.')
  401. {
  402. bFraction = TRUE;
  403. pstr++;
  404. if (! IS_DIGIT(*pstr))
  405. {
  406. TERSE(("Invalid floating-point number\n"));
  407. return FALSE;
  408. }
  409. scale = 0.1;
  410. while (IS_DIGIT(*pstr))
  411. {
  412. value += scale * (*pstr++ - '0');
  413. scale *= 0.1;
  414. }
  415. }
  416. //
  417. // Skip any trailing space characters
  418. //
  419. while (IS_SPACE(*pstr))
  420. pstr++;
  421. //
  422. // Perform requested round up or round down only if
  423. // fractional portion is present.
  424. //
  425. if (bFraction)
  426. {
  427. if (iType == FLTYPE_POINT_ROUNDUP)
  428. value = ceil(value);
  429. else if (iType == FLTYPE_POINT_ROUNDDOWN)
  430. value = (LONG)value;
  431. }
  432. //
  433. // Convert the return value to the specified format
  434. //
  435. switch (iType)
  436. {
  437. case FLTYPE_POINT:
  438. case FLTYPE_POINT_ROUNDUP:
  439. case FLTYPE_POINT_ROUNDDOWN:
  440. value = (value * 25400.0) / 72.0;
  441. break;
  442. case FLTYPE_FIX:
  443. value *= FIX_24_8_SCALE;
  444. break;
  445. default:
  446. ASSERT(iType == FLTYPE_INT);
  447. break;
  448. }
  449. //
  450. // Guard against overflow conditions
  451. //
  452. if (value >= MAX_LONG)
  453. {
  454. TERSE(("Floating-point number overflow\n"));
  455. return FALSE;
  456. }
  457. *ppstr = pstr;
  458. *plValue = (LONG) (value + 0.5);
  459. if (bNegative)
  460. {
  461. TERSE(("Negative number treated as 0\n"));
  462. *plValue = 0;
  463. }
  464. return TRUE;
  465. }
  466. BOOL
  467. BSearchStrTable(
  468. PCSTRTABLE pTable,
  469. PSTR pstrKeyword,
  470. DWORD *pdwValue
  471. )
  472. /*++
  473. Routine Description:
  474. Search for a keyword from a string table
  475. Arguments:
  476. pTable - Specifies the string table to be search
  477. pstrKeyword - Specifies the keyword we're interested in
  478. pdwValue - Points to a variable for storing value corresponding to the given keyword
  479. Return Value:
  480. TRUE if the given keyword is found in the table, FALSE otherwise
  481. --*/
  482. {
  483. ASSERT(pstrKeyword != NULL);
  484. while (pTable->pstrKeyword != NULL &&
  485. strcmp(pTable->pstrKeyword, pstrKeyword) != EQUAL_STRING)
  486. {
  487. pTable++;
  488. }
  489. *pdwValue = pTable->dwValue;
  490. return (pTable->pstrKeyword != NULL);
  491. }
  492. PSTR
  493. PstrParseString(
  494. PPARSERDATA pParserData,
  495. PBUFOBJ pBufObj
  496. )
  497. /*++
  498. Routine Description:
  499. Duplicate a character string from a buffer object
  500. Arguments:
  501. pParserData - Points to parser data structure
  502. pBufObj - Specifies the buffer object containing the character string to be duplicated
  503. Return Value:
  504. Pointer to a copy of the specified string
  505. NULL if there is an error
  506. --*/
  507. {
  508. PSTR pstr;
  509. ASSERT(! IS_BUFFER_EMPTY(pBufObj));
  510. if (pstr = ALLOC_PARSER_MEM(pParserData, pBufObj->dwSize + 1))
  511. CopyMemory(pstr, pBufObj->pbuf, pBufObj->dwSize + 1);
  512. else
  513. ERR(("Memory allocation failed: %d\n", GetLastError()));
  514. return pstr;
  515. }
  516. PPDERROR
  517. IParseInvocation(
  518. PPARSERDATA pParserData,
  519. PINVOCOBJ pInvocation
  520. )
  521. /*++
  522. Routine Description:
  523. Parse the content of value buffer to an invocation string
  524. Arguments:
  525. pParserData - Points to parser data structure
  526. pInvocation - Specifies a buffer for storing the parsed invocation string
  527. Return Value:
  528. Status code
  529. --*/
  530. {
  531. ASSERT(pInvocation->pvData == NULL);
  532. //
  533. // Determine if the invocation is a quoted string or a symbol reference.
  534. // In case of symbol reference, we save the name of the symbol in pvData
  535. // field (including the leading ^ character).
  536. //
  537. if (pParserData->dwValueType == VALUETYPE_SYMBOL)
  538. {
  539. PSTR pstrSymbolName;
  540. if (! (pstrSymbolName = PstrParseString(pParserData, &pParserData->Value)))
  541. return PPDERR_MEMORY;
  542. pInvocation->pvData = pstrSymbolName;
  543. MARK_SYMBOL_INVOC(pInvocation);
  544. }
  545. else
  546. {
  547. PVOID pvData;
  548. if (! (pvData = ALLOC_PARSER_MEM(pParserData, pParserData->Value.dwSize + 1)))
  549. {
  550. ERR(("Memory allocation failed\n"));
  551. return PPDERR_MEMORY;
  552. }
  553. pInvocation->pvData = pvData;
  554. pInvocation->dwLength = pParserData->Value.dwSize;
  555. ASSERT(! IS_SYMBOL_INVOC(pInvocation));
  556. CopyMemory(pvData, pParserData->Value.pbuf, pInvocation->dwLength + 1);
  557. }
  558. return PPDERR_NONE;
  559. }
  560. PPDERROR
  561. IParseInteger(
  562. PPARSERDATA pParserData,
  563. PDWORD pdwValue
  564. )
  565. /*++
  566. Routine Description:
  567. Intrepret the value field of an entry as unsigned integer
  568. Arguments:
  569. pParserData - Points to parser data structure
  570. pdwValue - Points to a variable for storing parsed integer value
  571. Return Value:
  572. Status code
  573. --*/
  574. {
  575. PSTR pstr = pParserData->pstrValue;
  576. LONG lValue;
  577. if (BGetIntegerFromString(&pstr, &lValue))
  578. {
  579. if (lValue >= 0)
  580. {
  581. *pdwValue = lValue;
  582. return PPDERR_NONE;
  583. } else
  584. TERSE(("Negative integer value not allowed: %s.\n", pParserData->pstrValue));
  585. }
  586. *pdwValue = 0;
  587. return PPDERR_SYNTAX;
  588. }
  589. PPDERROR
  590. IParseBoolean(
  591. PPARSERDATA pParserData,
  592. DWORD *pdwValue
  593. )
  594. /*++
  595. Routine Description:
  596. Interpret the value of an entry as a boolen, i.e. True or False
  597. Arguments:
  598. pParserData - Points to parser data structure
  599. pdwValue - Points to a variable for storing the parsed boolean value
  600. Return Value:
  601. Status code
  602. --*/
  603. {
  604. static const STRTABLE BooleanStrs[] =
  605. {
  606. gstrTrueKwd, TRUE,
  607. gstrFalseKwd, FALSE,
  608. NULL, FALSE
  609. };
  610. if (! BSearchStrTable(BooleanStrs, pParserData->pstrValue, pdwValue))
  611. return ISyntaxError(pParserData->pFile, "Invalid boolean constant");
  612. return PPDERR_NONE;
  613. }
  614. BOOL
  615. BFindNextWord(
  616. PSTR *ppstr,
  617. PSTR pstrWord
  618. )
  619. /*++
  620. Routine Description:
  621. Find the next word in a character string. Words are separated by spaces.
  622. Arguments:
  623. ppstr - Points to a string pointer. On entry, it contains a pointer
  624. to the beginning of the word string. On exit, it points to
  625. the first non-space character after the word string.
  626. pstrWord - Points to a buffer for storing characters from the next word
  627. The size of this buffer must be at least MAX_WORD_LEN characters
  628. Return Value:
  629. TRUE if next word is found, FALSE otherwise
  630. --*/
  631. {
  632. PSTR pstr = *ppstr;
  633. pstrWord[0] = NUL;
  634. //
  635. // Skip any leading spaces
  636. //
  637. while (IS_SPACE(*pstr))
  638. pstr++;
  639. if (*pstr != NUL)
  640. {
  641. PSTR pstrStart;
  642. INT iWordLen;
  643. //
  644. // Go to the end of the word
  645. //
  646. pstrStart = pstr;
  647. while (*pstr && !IS_SPACE(*pstr))
  648. pstr++;
  649. //
  650. // Copy the word into the specified buffer
  651. //
  652. if ((iWordLen = (INT)(pstr - pstrStart)) < MAX_WORD_LEN)
  653. {
  654. CopyMemory(pstrWord, pstrStart, iWordLen);
  655. pstrWord[iWordLen] = NUL;
  656. }
  657. //
  658. // Skip to the next non-space character
  659. //
  660. while (IS_SPACE(*pstr))
  661. pstr++;
  662. }
  663. *ppstr = pstr;
  664. return (*pstrWord != NUL);
  665. }
  666. PPDERROR
  667. IParseVersionNumber(
  668. PPARSERDATA pParserData,
  669. PDWORD pdwVersion
  670. )
  671. /*++
  672. Routine Description:
  673. Parse a version number. The format of a version number is Version[.Revision]
  674. where both Version and Revision are integers.
  675. Arguments:
  676. pParserData - Points to parser data structure
  677. pdwVersion - Points to a variable for storing the parsed version number
  678. Return Value:
  679. Status code
  680. --*/
  681. {
  682. PSTR pstr;
  683. LONG lVersion, lRevision = 0;
  684. //
  685. // Parse the major version number followed by minor revision number
  686. //
  687. pstr = pParserData->pstrValue;
  688. if (! BGetIntegerFromString(&pstr, &lVersion))
  689. return ISyntaxError(pParserData->pFile, "Invalid version number");
  690. if (*pstr == '.')
  691. {
  692. pstr++;
  693. if (! BGetIntegerFromString(&pstr, &lRevision))
  694. return ISyntaxError(pParserData->pFile, "Invalid revision number");
  695. }
  696. //
  697. // High-order word contains version number and
  698. // low-order word contains revision number
  699. //
  700. if (lVersion < 0 || lVersion > MAX_WORD ||
  701. lRevision < 0 || lRevision > MAX_WORD)
  702. {
  703. return ISyntaxError(pParserData->pFile, "Version number out-of-range");
  704. }
  705. *pdwVersion = (lVersion << 16) | lRevision;
  706. return PPDERR_NONE;
  707. }
  708. PPDERROR
  709. IParseXlation(
  710. PPARSERDATA pParserData,
  711. PINVOCOBJ pXlation
  712. )
  713. /*++
  714. Routine Description:
  715. Parse the information in the translation string field to an INVOCOBJ
  716. Arguments:
  717. pParserData - Points to parser data structure
  718. pXlation - Returns information about parsed translation string
  719. Return Value:
  720. Status code
  721. --*/
  722. {
  723. PBUFOBJ pBufObj = &pParserData->Xlation;
  724. //
  725. // Allocate memory to hold the translation string (plus a null terminator)
  726. //
  727. pXlation->pvData = ALLOC_PARSER_MEM(pParserData, pBufObj->dwSize + 1);
  728. if (pXlation->pvData == NULL)
  729. {
  730. ERR(("Memory allocation failed\n"));
  731. return PPDERR_MEMORY;
  732. }
  733. pXlation->dwLength = pBufObj->dwSize;
  734. ASSERT(! IS_SYMBOL_INVOC(pXlation));
  735. CopyMemory(pXlation->pvData, pBufObj->pbuf, pBufObj->dwSize);
  736. return PPDERR_NONE;
  737. }
  738. PCSTR
  739. PstrStripKeywordChar(
  740. PCSTR pstrKeyword
  741. )
  742. /*++
  743. Routine Description:
  744. Strip off the keyword prefix character from the input string
  745. Arguments:
  746. pstrKeyword - Points to a string prefixed by the keyword character
  747. Return Value:
  748. Pointer to the keyword string after the keyword character is stripped
  749. NULL if the keyword string is empty
  750. --*/
  751. {
  752. if (IS_KEYWORD_CHAR(*pstrKeyword))
  753. pstrKeyword++;
  754. return *pstrKeyword ? pstrKeyword : NULL;
  755. }
  756. PVOID
  757. PvCreateListItem(
  758. PPARSERDATA pParserData,
  759. PLISTOBJ *ppList,
  760. DWORD dwItemSize,
  761. PSTR pstrListTag
  762. )
  763. /*++
  764. Routine Description:
  765. Create a new item in the specified linked-list
  766. Make sure no existing item has the same name
  767. Arguments:
  768. pParserData - Points to parser data structure
  769. ppList - Specifies the linked-list
  770. dwItemSize - Linked-list item size
  771. pListTag - Specifies the name of the linked-list (for debugging purpose)
  772. Return Value:
  773. Pointer to newly created linked-list item
  774. NULL if there is an error
  775. --*/
  776. {
  777. PLISTOBJ pItem;
  778. PSTR pstrItemName;
  779. //
  780. // Check if the item appeared in the list already
  781. // Create a new item data structure if not
  782. //
  783. pItem = PvFindListItem(*ppList, pParserData->Option.pbuf, NULL);
  784. if (pItem != NULL)
  785. {
  786. if (pstrListTag)
  787. TERSE(("%s %s redefined\n", pstrListTag, pItem->pstrName));
  788. }
  789. else
  790. {
  791. if (! (pItem = ALLOC_PARSER_MEM(pParserData, dwItemSize)) ||
  792. ! (pstrItemName = PstrParseString(pParserData, &pParserData->Option)))
  793. {
  794. ERR(("Memory allocation failed: %d\n", GetLastError()));
  795. return NULL;
  796. }
  797. pItem->pstrName = pstrItemName;
  798. pItem->pNext = NULL;
  799. //
  800. // Put the newly created item at the end of the linked-list
  801. //
  802. while (*ppList != NULL)
  803. ppList = (PLISTOBJ *) &((*ppList)->pNext);
  804. *ppList = pItem;
  805. }
  806. return pItem;
  807. }
  808. PFEATUREOBJ
  809. PCreateFeatureItem(
  810. PPARSERDATA pParserData,
  811. DWORD dwFeatureID
  812. )
  813. /*++
  814. Routine Description:
  815. Create a new printer feature structure or find an existing one
  816. Arguments:
  817. pParserData - Points to parser data structure
  818. dwFeatureID - Printer feature identifier
  819. Return Value:
  820. Pointer to a newly created or an existing printer feature structure
  821. NULL if there is an error
  822. --*/
  823. {
  824. static struct {
  825. PCSTR pstrKeyword;
  826. DWORD dwFeatureID;
  827. DWORD dwOptionSize;
  828. } FeatureInfo[] = {
  829. gstrPageSizeKwd, GID_PAGESIZE, sizeof(PAPEROBJ),
  830. "PageRegion", GID_PAGEREGION, sizeof(OPTIONOBJ),
  831. "Duplex", GID_DUPLEX, sizeof(OPTIONOBJ),
  832. gstrInputSlotKwd, GID_INPUTSLOT, sizeof(TRAYOBJ),
  833. "Resolution", GID_RESOLUTION, sizeof(RESOBJ),
  834. "JCLResolution", GID_RESOLUTION, sizeof(RESOBJ),
  835. "OutputBin", GID_OUTPUTBIN, sizeof(BINOBJ),
  836. "MediaType", GID_MEDIATYPE, sizeof(OPTIONOBJ),
  837. "Collate", GID_COLLATE, sizeof(OPTIONOBJ),
  838. "InstalledMemory",GID_MEMOPTION, sizeof(MEMOBJ),
  839. "LeadingEdge", GID_LEADINGEDGE, sizeof(OPTIONOBJ),
  840. "UseHWMargins", GID_USEHWMARGINS, sizeof(OPTIONOBJ),
  841. NULL, GID_UNKNOWN, sizeof(OPTIONOBJ)
  842. };
  843. PFEATUREOBJ pFeature;
  844. PCSTR pstrKeyword;
  845. BUFOBJ SavedBuffer;
  846. INT iIndex = 0;
  847. if (dwFeatureID == GID_UNKNOWN)
  848. {
  849. //
  850. // Given a feature name, first find out if it refers to
  851. // one of the predefined features
  852. //
  853. pstrKeyword = PstrStripKeywordChar(pParserData->achOption);
  854. ASSERT(pstrKeyword != NULL);
  855. while (FeatureInfo[iIndex].pstrKeyword &&
  856. strcmp(FeatureInfo[iIndex].pstrKeyword, pstrKeyword) != EQUAL_STRING)
  857. {
  858. iIndex++;
  859. }
  860. if (FeatureInfo[iIndex].pstrKeyword)
  861. pParserData->aubOpenUIFeature[FeatureInfo[iIndex].dwFeatureID] = 1;
  862. }
  863. else
  864. {
  865. //
  866. // We're given a predefined feature identifier.
  867. // Map to its corresponding feature name.
  868. //
  869. while (FeatureInfo[iIndex].pstrKeyword &&
  870. dwFeatureID != FeatureInfo[iIndex].dwFeatureID)
  871. {
  872. iIndex++;
  873. }
  874. pstrKeyword = FeatureInfo[iIndex].pstrKeyword;
  875. ASSERT(pstrKeyword != NULL);
  876. }
  877. //
  878. // If we're dealing with a predefined feature, the first search the current
  879. // list of printer features based on the predefined feature identifier.
  880. //
  881. pFeature = NULL;
  882. if (FeatureInfo[iIndex].dwFeatureID != GID_UNKNOWN)
  883. {
  884. for (pFeature = pParserData->pFeatures;
  885. pFeature && pFeature->dwFeatureID != FeatureInfo[iIndex].dwFeatureID;
  886. pFeature = pFeature->pNext)
  887. {
  888. }
  889. }
  890. //
  891. // Create a new printer feature item or find an existing printer feature item
  892. // based on the feature name.
  893. //
  894. if (pFeature == NULL)
  895. {
  896. SavedBuffer = pParserData->Option;
  897. pParserData->Option.pbuf = (PBYTE) pstrKeyword;
  898. pParserData->Option.dwSize = strlen(pstrKeyword);
  899. pFeature = PvCreateListItem(pParserData,
  900. (PLISTOBJ *) &pParserData->pFeatures,
  901. sizeof(FEATUREOBJ),
  902. NULL);
  903. pParserData->Option = SavedBuffer;
  904. }
  905. if (pFeature)
  906. {
  907. //
  908. // Parse the translation string for the feature name
  909. //
  910. if (dwFeatureID == GID_UNKNOWN &&
  911. ! IS_BUFFER_EMPTY(&pParserData->Xlation) &&
  912. ! pFeature->Translation.pvData &&
  913. IParseXlation(pParserData, &pFeature->Translation) != PPDERR_NONE)
  914. {
  915. ERR(("Failed to parse feature name translation string\n"));
  916. return NULL;
  917. }
  918. if (pFeature->dwOptionSize == 0)
  919. {
  920. //
  921. // Store information about newly created feature item
  922. //
  923. pFeature->dwOptionSize = FeatureInfo[iIndex].dwOptionSize;
  924. pFeature->dwFeatureID = FeatureInfo[iIndex].dwFeatureID;
  925. //
  926. // All predefined features are doc-sticky except for InstalledMemory/VMOption
  927. //
  928. if (pFeature->dwFeatureID == GID_MEMOPTION ||
  929. pFeature->dwFeatureID == GID_UNKNOWN && pParserData->bInstallableGroup)
  930. {
  931. pFeature->bInstallable = TRUE;
  932. }
  933. }
  934. }
  935. else
  936. {
  937. ERR(("Couldn't create printer feature item for: %s\n", pstrKeyword));
  938. }
  939. return pFeature;
  940. }
  941. PVOID
  942. PvCreateXlatedItem(
  943. PPARSERDATA pParserData,
  944. PVOID ppList,
  945. DWORD dwItemSize
  946. )
  947. /*++
  948. Routine Description:
  949. Create a feature option item and parse the associated translation string
  950. Arguments:
  951. pParserData - Points to parser data structure
  952. ppList - Points to the list of feature option items
  953. dwItemSize - Size of a feature option item
  954. Return Value:
  955. Pointer to newly created feature option item
  956. NULL if there is an error
  957. --*/
  958. {
  959. POPTIONOBJ pOption;
  960. if (! (pOption = PvCreateListItem(pParserData, ppList, dwItemSize, NULL)) ||
  961. (! IS_BUFFER_EMPTY(&pParserData->Xlation) &&
  962. ! pOption->Translation.pvData &&
  963. IParseXlation(pParserData, &pOption->Translation) != PPDERR_NONE))
  964. {
  965. ERR(("Couldn't process entry: *%s %s\n",
  966. pParserData->achKeyword,
  967. pParserData->achOption));
  968. return NULL;
  969. }
  970. return pOption;
  971. }
  972. PVOID
  973. PvCreateOptionItem(
  974. PPARSERDATA pParserData,
  975. DWORD dwFeatureID
  976. )
  977. /*++
  978. Routine Description:
  979. Create a feature option item for a predefined printer feature
  980. Arguments:
  981. pParserData - Points to parser data structure
  982. dwFeatureID - Specifies a predefined feature identifier
  983. Return Value:
  984. Pointer to an existing feature option item or a newly created one if none exists
  985. NULL if there is an error
  986. --*/
  987. {
  988. PFEATUREOBJ pFeature;
  989. ASSERT(dwFeatureID != GID_UNKNOWN);
  990. if (! (pFeature = PCreateFeatureItem(pParserData, dwFeatureID)))
  991. return NULL;
  992. return PvCreateXlatedItem(pParserData, &pFeature->pOptions, pFeature->dwOptionSize);
  993. }
  994. INT
  995. ICountFeatureList(
  996. PFEATUREOBJ pFeature,
  997. BOOL bInstallable
  998. )
  999. {
  1000. INT i = 0;
  1001. //
  1002. // Count the number of features of the specified type
  1003. //
  1004. while (pFeature != NULL)
  1005. {
  1006. if (pFeature->bInstallable == bInstallable)
  1007. i++;
  1008. pFeature = pFeature->pNext;
  1009. }
  1010. return i;
  1011. }
  1012. PPDERROR
  1013. IGenericOptionProc(
  1014. PPARSERDATA pParserData,
  1015. PFEATUREOBJ pFeature
  1016. )
  1017. /*++
  1018. Routine Description:
  1019. Function for handling a generic feature option entry
  1020. Arguments:
  1021. pParserData - Points to parser data structure
  1022. pFeature - Points to feature data structure
  1023. Return Value:
  1024. Status code
  1025. --*/
  1026. {
  1027. POPTIONOBJ pOption;
  1028. //
  1029. // Handle special case
  1030. //
  1031. if (pFeature == NULL)
  1032. return PPDERR_MEMORY;
  1033. //
  1034. // Create a feature option item and parse the option name and translation string
  1035. //
  1036. if (! (pOption = PvCreateXlatedItem(pParserData, &pFeature->pOptions, pFeature->dwOptionSize)))
  1037. return PPDERR_MEMORY;
  1038. if (pOption->Invocation.pvData)
  1039. {
  1040. WARN_DUPLICATE();
  1041. return PPDERR_NONE;
  1042. }
  1043. //
  1044. // Parse the invocation string
  1045. //
  1046. return IParseInvocation(pParserData, &pOption->Invocation);
  1047. }
  1048. PPDERROR
  1049. IGenericDefaultProc(
  1050. PPARSERDATA pParserData,
  1051. PFEATUREOBJ pFeature
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. Function for handling a generic default option entry
  1056. Arguments:
  1057. pParserData - Points to parser data structure
  1058. pFeature - Points to feature data structure
  1059. Return Value:
  1060. Status code
  1061. --*/
  1062. {
  1063. //
  1064. // Check if there is a memory error before this function is called
  1065. //
  1066. if (pFeature == NULL)
  1067. return PPDERR_MEMORY;
  1068. //
  1069. // Watch out for duplicate *Default entries for the same feature
  1070. //
  1071. if (pFeature->pstrDefault)
  1072. {
  1073. WARN_DUPLICATE();
  1074. return PPDERR_NONE;
  1075. }
  1076. //
  1077. // NOTE: Hack to take in account of a bug in NT4 driver.
  1078. // This is used to build up NT4-NT5 feature index mapping.
  1079. //
  1080. if (pFeature->dwFeatureID == GID_MEMOPTION &&
  1081. pParserData->iDefInstallMemIndex < 0)
  1082. {
  1083. pParserData->iDefInstallMemIndex = ICountFeatureList(pParserData->pFeatures, TRUE);
  1084. }
  1085. //
  1086. // Remember the default option keyword
  1087. //
  1088. if (pFeature->pstrDefault = PstrParseString(pParserData, &pParserData->Value))
  1089. return PPDERR_NONE;
  1090. else
  1091. return PPDERR_MEMORY;
  1092. }
  1093. PPDERROR
  1094. IGenericQueryProc(
  1095. PPARSERDATA pParserData,
  1096. PFEATUREOBJ pFeature
  1097. )
  1098. /*++
  1099. Routine Description:
  1100. Function for handling a generic query invocation entry
  1101. Arguments:
  1102. pParserData - Points to parser data structure
  1103. pFeature - Points to feature data structure
  1104. Return Value:
  1105. Status code
  1106. --*/
  1107. {
  1108. //
  1109. // Check if there is a memory error before this function is called
  1110. //
  1111. if (pFeature == NULL)
  1112. return PPDERR_MEMORY;
  1113. //
  1114. // Watch out for duplicate *Default entries for the same feature
  1115. //
  1116. if (pFeature->QueryInvoc.pvData)
  1117. {
  1118. WARN_DUPLICATE();
  1119. return PPDERR_NONE;
  1120. }
  1121. //
  1122. // Parse the query invocation string
  1123. //
  1124. return IParseInvocation(pParserData, &pFeature->QueryInvoc);
  1125. }
  1126. //
  1127. // Functions for handling predefined PPD keywords
  1128. //
  1129. //
  1130. // Specifies the imageable area of a media option
  1131. //
  1132. PPDERROR
  1133. IImageAreaProc(
  1134. PPARSERDATA pParserData
  1135. )
  1136. {
  1137. PPAPEROBJ pOption;
  1138. PSTR pstr;
  1139. RECT *pRect;
  1140. if (! (pOption = PvCreateOptionItem(pParserData, GID_PAGESIZE)))
  1141. return PPDERR_MEMORY;
  1142. pRect = &pOption->rcImageArea;
  1143. if (pRect->top > 0 || pRect->right > 0)
  1144. {
  1145. WARN_DUPLICATE();
  1146. return PPDERR_NONE;
  1147. }
  1148. //
  1149. // Parse imageable area: left, bottom, right, top
  1150. //
  1151. pstr = pParserData->pstrValue;
  1152. if (! BGetFloatFromString(&pstr, &pRect->left, FLTYPE_POINT_ROUNDUP) ||
  1153. ! BGetFloatFromString(&pstr, &pRect->bottom, FLTYPE_POINT_ROUNDUP) ||
  1154. ! BGetFloatFromString(&pstr, &pRect->right, FLTYPE_POINT_ROUNDDOWN) ||
  1155. ! BGetFloatFromString(&pstr, &pRect->top, FLTYPE_POINT_ROUNDDOWN) ||
  1156. pRect->left >= pRect->right || pRect->bottom >= pRect->top)
  1157. {
  1158. return ISyntaxError(pParserData->pFile, "Invalid imageable area");
  1159. }
  1160. return PPDERR_NONE;
  1161. }
  1162. //
  1163. // Specifies the paper dimension of a media option
  1164. //
  1165. PPDERROR
  1166. IPaperDimProc(
  1167. PPARSERDATA pParserData
  1168. )
  1169. {
  1170. PPAPEROBJ pOption;
  1171. PSTR pstr;
  1172. if (! (pOption = PvCreateOptionItem(pParserData, GID_PAGESIZE)))
  1173. return PPDERR_MEMORY;
  1174. if (pOption->szDimension.cx > 0 || pOption->szDimension.cy > 0)
  1175. {
  1176. WARN_DUPLICATE();
  1177. return PPDERR_NONE;
  1178. }
  1179. //
  1180. // Parse paper width and height
  1181. //
  1182. pstr = pParserData->pstrValue;
  1183. if (! BGetFloatFromString(&pstr, &pOption->szDimension.cx, FLTYPE_POINT) ||
  1184. ! BGetFloatFromString(&pstr, &pOption->szDimension.cy, FLTYPE_POINT))
  1185. {
  1186. return ISyntaxError(pParserData->pFile, "Invalid paper dimension");
  1187. }
  1188. return PPDERR_NONE;
  1189. }
  1190. //
  1191. // Interpret PageStackOrder and OutputOrder options
  1192. //
  1193. BOOL
  1194. BParseOutputOrder(
  1195. PSTR pstr,
  1196. PBOOL pbValue
  1197. )
  1198. {
  1199. static const STRTABLE OutputOrderStrs[] =
  1200. {
  1201. "Normal", FALSE,
  1202. "Reverse", TRUE,
  1203. NULL, FALSE
  1204. };
  1205. DWORD dwValue;
  1206. BOOL bResult;
  1207. bResult = BSearchStrTable(OutputOrderStrs, pstr, &dwValue);
  1208. *pbValue = dwValue;
  1209. return bResult;
  1210. }
  1211. //
  1212. // Specifies the page stack order for an output bin
  1213. //
  1214. PPDERROR
  1215. IPageStackOrderProc(
  1216. PPARSERDATA pParserData
  1217. )
  1218. {
  1219. PFEATUREOBJ pFeature;
  1220. PBINOBJ pOutputBin;
  1221. //
  1222. // Have we seen the OutputBin feature yet?
  1223. //
  1224. for (pFeature = pParserData->pFeatures;
  1225. pFeature && pFeature->dwFeatureID != GID_OUTPUTBIN;
  1226. pFeature = pFeature->pNext)
  1227. {
  1228. }
  1229. //
  1230. // If PageStackOrder entry appears before OutputBin feature, ignore it
  1231. //
  1232. if (pFeature == NULL)
  1233. {
  1234. BOOL bReverse;
  1235. if (!BParseOutputOrder(pParserData->pstrValue, &bReverse))
  1236. return ISyntaxError(pParserData->pFile, "Invalid PageStackOrder option");
  1237. if (bReverse)
  1238. TERSE(("%ws: Ignored *PageStackOrder: Reverse on line %d because OutputBin not yet defined\n",
  1239. pParserData->pFile->ptstrFileName,
  1240. pParserData->pFile->iLineNumber));
  1241. return PPDERR_NONE;
  1242. }
  1243. //
  1244. // Add an option for OutputBin feature
  1245. //
  1246. pOutputBin = PvCreateXlatedItem(pParserData, &pFeature->pOptions, pFeature->dwOptionSize);
  1247. if (pOutputBin == NULL)
  1248. return PPDERR_MEMORY;
  1249. return BParseOutputOrder(pParserData->pstrValue, &pOutputBin->bReversePrint) ?
  1250. PPDERR_NONE :
  1251. ISyntaxError(pParserData->pFile, "Invalid PageStackOrder option");
  1252. }
  1253. //
  1254. // Specifies the default page output order
  1255. // NOTE: This function gets called only if *DefaultOutputOrder
  1256. // entry appears outside of OpenUI/CloseUI.
  1257. //
  1258. PPDERROR
  1259. IDefOutputOrderProc(
  1260. PPARSERDATA pParserData
  1261. )
  1262. {
  1263. pParserData->bDefOutputOrderSet = BParseOutputOrder(pParserData->pstrValue, &pParserData->bDefReversePrint);
  1264. return pParserData->bDefOutputOrderSet ?
  1265. PPDERR_NONE :
  1266. ISyntaxError(pParserData->pFile, "Invalid DefaultOutputOrder option");
  1267. }
  1268. //
  1269. // Specifies whether an input slot requires page region specification
  1270. //
  1271. PPDERROR
  1272. IReqPageRgnProc(
  1273. PPARSERDATA pParserData
  1274. )
  1275. {
  1276. PTRAYOBJ pOption;
  1277. DWORD dwValue;
  1278. //
  1279. // NOTE: Hack for doing NT4-NT5 feature index conversion
  1280. //
  1281. if (pParserData->iReqPageRgnIndex < 0)
  1282. {
  1283. PFEATUREOBJ pFeature = pParserData->pFeatures;
  1284. while (pFeature && pFeature->dwFeatureID != GID_INPUTSLOT)
  1285. pFeature = pFeature->pNext;
  1286. if (pFeature == NULL)
  1287. pParserData->iReqPageRgnIndex = ICountFeatureList(pParserData->pFeatures, FALSE);
  1288. }
  1289. //
  1290. // The value should be either True or False
  1291. //
  1292. if (IParseBoolean(pParserData, &dwValue) != PPDERR_NONE)
  1293. return PPDERR_SYNTAX;
  1294. dwValue = dwValue ? REQRGN_TRUE : REQRGN_FALSE;
  1295. //
  1296. // *RequiresPageRegion All: entry has special meaning
  1297. //
  1298. if (strcmp(pParserData->achOption, "All") == EQUAL_STRING)
  1299. {
  1300. if (pParserData->dwReqPageRgn == REQRGN_UNKNOWN)
  1301. pParserData->dwReqPageRgn = dwValue;
  1302. else
  1303. WARN_DUPLICATE();
  1304. }
  1305. else
  1306. {
  1307. if (! (pOption = PvCreateOptionItem(pParserData, GID_INPUTSLOT)))
  1308. return PPDERR_MEMORY;
  1309. if (pOption->dwReqPageRgn == REQRGN_UNKNOWN)
  1310. pOption->dwReqPageRgn = dwValue;
  1311. else
  1312. WARN_DUPLICATE();
  1313. }
  1314. return PPDERR_NONE;
  1315. }
  1316. //
  1317. // Specifies Duplex feature options
  1318. //
  1319. PPDERROR
  1320. IDefaultDuplexProc(
  1321. PPARSERDATA pParserData
  1322. )
  1323. {
  1324. return IGenericDefaultProc(pParserData,
  1325. PCreateFeatureItem(pParserData, GID_DUPLEX));
  1326. }
  1327. PPDERROR
  1328. IDuplexProc(
  1329. PPARSERDATA pParserData
  1330. )
  1331. {
  1332. if (strcmp(pParserData->achOption, gstrNoneKwd) != EQUAL_STRING &&
  1333. strcmp(pParserData->achOption, gstrDuplexTumble) != EQUAL_STRING &&
  1334. strcmp(pParserData->achOption, gstrDuplexNoTumble) != EQUAL_STRING)
  1335. {
  1336. return ISyntaxError(pParserData->pFile, "Invalid Duplex option");
  1337. }
  1338. return IGenericOptionProc(pParserData,
  1339. PCreateFeatureItem(pParserData, GID_DUPLEX));
  1340. }
  1341. //
  1342. // Specifies ManualFeed True/False invocation strings
  1343. //
  1344. PPDERROR
  1345. IDefManualFeedProc(
  1346. PPARSERDATA pParserData
  1347. )
  1348. {
  1349. //
  1350. // NOTE: Hack for doing NT4-NT5 feature index conversion
  1351. //
  1352. if (pParserData->iManualFeedIndex < 0)
  1353. pParserData->iManualFeedIndex = ICountFeatureList(pParserData->pFeatures, FALSE);
  1354. return PPDERR_NONE;
  1355. }
  1356. PPDERROR
  1357. IManualFeedProc(
  1358. PPARSERDATA pParserData
  1359. )
  1360. {
  1361. POPTIONOBJ pOption;
  1362. INT iResult = PPDERR_NONE;
  1363. //
  1364. // NOTE: Hack for doing NT4-NT5 feature index conversion
  1365. //
  1366. if (pParserData->iManualFeedIndex < 0)
  1367. pParserData->iManualFeedIndex = ICountFeatureList(pParserData->pFeatures, FALSE);
  1368. if (strcmp(pParserData->achOption, gstrTrueKwd) == EQUAL_STRING ||
  1369. strcmp(pParserData->achOption, gstrOnKwd) == EQUAL_STRING)
  1370. {
  1371. //
  1372. // The way manual feed is handled in PPD spec is incredibly klugy.
  1373. // Hack here to treat *ManualFeed True as one of the input slot
  1374. // selections so that downstream component can handle it uniformly.
  1375. //
  1376. StringCchCopyA(pParserData->achOption, CCHOF(pParserData->achOption), gstrManualFeedKwd);
  1377. pParserData->Option.dwSize = strlen(gstrManualFeedKwd);
  1378. StringCchCopyA(pParserData->achXlation, CCHOF(pParserData->achXlation), "");
  1379. pParserData->Xlation.dwSize = 0;
  1380. if (! (pOption = PvCreateOptionItem(pParserData, GID_INPUTSLOT)))
  1381. {
  1382. iResult = PPDERR_MEMORY;
  1383. }
  1384. else if (pOption->Invocation.pvData)
  1385. {
  1386. TERSE(("%ws: Duplicate entries of '*ManualFeed True' on line %d\n",
  1387. pParserData->pFile->ptstrFileName,
  1388. pParserData->pFile->iLineNumber));
  1389. }
  1390. else
  1391. {
  1392. ((PTRAYOBJ) pOption)->dwTrayIndex = DMBIN_MANUAL;
  1393. iResult = IParseInvocation(pParserData, &pOption->Invocation);
  1394. }
  1395. }
  1396. else if (strcmp(pParserData->achOption, gstrFalseKwd) == EQUAL_STRING ||
  1397. strcmp(pParserData->achOption, gstrNoneKwd) == EQUAL_STRING ||
  1398. strcmp(pParserData->achOption, gstrOffKwd) == EQUAL_STRING)
  1399. {
  1400. //
  1401. // Save *ManualFeed False invocation string separately.
  1402. // It's always emitted before any tray invocation string.
  1403. //
  1404. if (pParserData->ManualFeedFalse.pvData)
  1405. {
  1406. WARN_DUPLICATE();
  1407. }
  1408. else
  1409. {
  1410. iResult = IParseInvocation(pParserData, &pParserData->ManualFeedFalse);
  1411. }
  1412. }
  1413. else
  1414. {
  1415. iResult = ISyntaxError(pParserData->pFile, "Unrecognized ManualFeed option");
  1416. }
  1417. return iResult;
  1418. }
  1419. //
  1420. // Specifies JCLResolution invocation string
  1421. //
  1422. PPDERROR
  1423. IJCLResProc(
  1424. PPARSERDATA pParserData
  1425. )
  1426. {
  1427. POPTIONOBJ pOption;
  1428. if (! (pOption = PvCreateOptionItem(pParserData, GID_RESOLUTION)))
  1429. return PPDERR_MEMORY;
  1430. if (pOption->Invocation.pvData)
  1431. {
  1432. WARN_DUPLICATE();
  1433. return PPDERR_NONE;
  1434. }
  1435. pParserData->dwSetResType = RESTYPE_JCL;
  1436. return IParseInvocation(pParserData, &pOption->Invocation);
  1437. }
  1438. //
  1439. // Specifies the default JCLResolution option
  1440. //
  1441. PPDERROR
  1442. IDefaultJCLResProc(
  1443. PPARSERDATA pParserData
  1444. )
  1445. {
  1446. return IGenericDefaultProc(pParserData,
  1447. PCreateFeatureItem(pParserData, GID_RESOLUTION));
  1448. }
  1449. //
  1450. // Specifies SetResolution invocation string
  1451. //
  1452. PPDERROR
  1453. ISetResProc(
  1454. PPARSERDATA pParserData
  1455. )
  1456. {
  1457. POPTIONOBJ pOption;
  1458. if (! (pOption = PvCreateOptionItem(pParserData, GID_RESOLUTION)))
  1459. return PPDERR_MEMORY;
  1460. if (pOption->Invocation.pvData)
  1461. {
  1462. WARN_DUPLICATE();
  1463. return PPDERR_NONE;
  1464. }
  1465. pParserData->dwSetResType = RESTYPE_EXITSERVER;
  1466. return IParseInvocation(pParserData, &pOption->Invocation);
  1467. }
  1468. //
  1469. // Specifies default halftone screen angle
  1470. //
  1471. PPDERROR
  1472. IScreenAngleProc(
  1473. PPARSERDATA pParserData
  1474. )
  1475. {
  1476. PSTR pstr = pParserData->pstrValue;
  1477. if (! BGetFloatFromString(&pstr, &pParserData->fxScreenAngle, FLTYPE_FIX))
  1478. return ISyntaxError(pParserData->pFile, "Invalid screen angle");
  1479. return PPDERR_NONE;
  1480. }
  1481. //
  1482. // Specifies default halftone screen frequency
  1483. //
  1484. PPDERROR
  1485. IScreenFreqProc(
  1486. PPARSERDATA pParserData
  1487. )
  1488. {
  1489. PSTR pstr = pParserData->pstrValue;
  1490. if (! BGetFloatFromString(&pstr, &pParserData->fxScreenFreq, FLTYPE_FIX) ||
  1491. pParserData->fxScreenFreq <= 0)
  1492. {
  1493. return ISyntaxError(pParserData->pFile, "Invalid screen frequency");
  1494. }
  1495. else
  1496. return PPDERR_NONE;
  1497. }
  1498. //
  1499. // Specifies default halftone screen angle for a resolution option
  1500. //
  1501. PPDERROR
  1502. IResScreenAngleProc(
  1503. PPARSERDATA pParserData
  1504. )
  1505. {
  1506. PRESOBJ pOption;
  1507. PSTR pstr = pParserData->pstrValue;
  1508. if (! (pOption = PvCreateOptionItem(pParserData, GID_RESOLUTION)))
  1509. return PPDERR_MEMORY;
  1510. if (! BGetFloatFromString(&pstr, &pOption->fxScreenAngle, FLTYPE_FIX))
  1511. return ISyntaxError(pParserData->pFile, "Invalid screen angle");
  1512. return PPDERR_NONE;
  1513. }
  1514. //
  1515. // Specifies default halftone screen frequency for a resolution option
  1516. //
  1517. PPDERROR
  1518. IResScreenFreqProc(
  1519. PPARSERDATA pParserData
  1520. )
  1521. {
  1522. PRESOBJ pOption;
  1523. PSTR pstr = pParserData->pstrValue;
  1524. if (! (pOption = PvCreateOptionItem(pParserData, GID_RESOLUTION)))
  1525. return PPDERR_MEMORY;
  1526. if (! BGetFloatFromString(&pstr, &pOption->fxScreenFreq, FLTYPE_FIX) ||
  1527. pOption->fxScreenFreq <= 0)
  1528. {
  1529. return ISyntaxError(pParserData->pFile, "Invalid screen frequency");
  1530. }
  1531. else
  1532. return PPDERR_NONE;
  1533. }
  1534. //
  1535. // Specifies device font information
  1536. //
  1537. PPDERROR
  1538. IFontProc(
  1539. PPARSERDATA pParserData
  1540. )
  1541. {
  1542. static const STRTABLE FontStatusStrs[] =
  1543. {
  1544. "ROM", FONTSTATUS_ROM,
  1545. "Disk", FONTSTATUS_DISK,
  1546. NULL, FONTSTATUS_UNKNOWN
  1547. };
  1548. PFONTREC pFont;
  1549. PSTR pstr;
  1550. CHAR achWord[MAX_WORD_LEN];
  1551. DWORD cbSize;
  1552. //
  1553. // Create a new device font item
  1554. //
  1555. if (! (pFont = PvCreateXlatedItem(pParserData, &pParserData->pFonts, sizeof(FONTREC))))
  1556. return PPDERR_MEMORY;
  1557. if (pFont->pstrEncoding != NULL)
  1558. {
  1559. WARN_DUPLICATE();
  1560. return PPDERR_NONE;
  1561. }
  1562. //
  1563. // encoding
  1564. //
  1565. pstr = pParserData->pstrValue;
  1566. if (! BFindNextWord(&pstr, achWord))
  1567. return ISyntaxError(pParserData->pFile, "Invalid *Font entry");
  1568. cbSize = strlen(achWord) + 1;
  1569. if (! (pFont->pstrEncoding = ALLOC_PARSER_MEM(pParserData, cbSize)))
  1570. return PPDERR_MEMORY;
  1571. StringCchCopyA(pFont->pstrEncoding, cbSize / sizeof(char), achWord);
  1572. //
  1573. // version
  1574. //
  1575. (VOID) BFindNextWord(&pstr, achWord);
  1576. {
  1577. PSTR pstrStart, pstrEnd;
  1578. if (pstrStart = strchr(achWord, '('))
  1579. pstrStart++;
  1580. else
  1581. pstrStart = achWord;
  1582. if (pstrEnd = strrchr(pstrStart, ')'))
  1583. *pstrEnd = NUL;
  1584. cbSize = strlen(pstrStart) + 1;
  1585. if (! (pFont->pstrVersion = ALLOC_PARSER_MEM(pParserData, cbSize)))
  1586. return PPDERR_MEMORY;
  1587. StringCchCopyA(pFont->pstrVersion, cbSize / sizeof(char), pstrStart);
  1588. }
  1589. //
  1590. // charset
  1591. //
  1592. (VOID) BFindNextWord(&pstr, achWord);
  1593. cbSize = strlen(achWord) + 1;
  1594. if (! (pFont->pstrCharset = ALLOC_PARSER_MEM(pParserData, cbSize)))
  1595. return PPDERR_MEMORY;
  1596. StringCchCopyA(pFont->pstrCharset, cbSize / sizeof(char), achWord);
  1597. //
  1598. // status
  1599. //
  1600. (VOID) BFindNextWord(&pstr, achWord);
  1601. (VOID) BSearchStrTable(FontStatusStrs, achWord, &pFont->dwStatus);
  1602. return PPDERR_NONE;
  1603. }
  1604. //
  1605. // Specifies the default device font
  1606. //
  1607. PPDERROR
  1608. IDefaultFontProc(
  1609. PPARSERDATA pParserData
  1610. )
  1611. {
  1612. if (strcmp(pParserData->pstrValue, "Error") == EQUAL_STRING)
  1613. pParserData->pstrDefaultFont = NULL;
  1614. else if (! (pParserData->pstrDefaultFont = PstrParseString(pParserData, &pParserData->Value)))
  1615. return PPDERR_MEMORY;
  1616. return PPDERR_NONE;
  1617. }
  1618. //
  1619. // Mark the beginning of a new printer feature section
  1620. //
  1621. PPDERROR
  1622. IOpenUIProc(
  1623. PPARSERDATA pParserData
  1624. )
  1625. {
  1626. static const STRTABLE UITypeStrs[] =
  1627. {
  1628. "PickOne", UITYPE_PICKONE,
  1629. "PickMany", UITYPE_PICKMANY,
  1630. "Boolean", UITYPE_BOOLEAN,
  1631. NULL, UITYPE_PICKONE
  1632. };
  1633. PCSTR pstrKeyword;
  1634. //
  1635. // Guard against nested or unbalanced OpenUI
  1636. //
  1637. if (pParserData->pOpenFeature != NULL)
  1638. {
  1639. TERSE(("Missing CloseUI for *%s\n", pParserData->pOpenFeature->pstrName));
  1640. pParserData->pOpenFeature = NULL;
  1641. }
  1642. //
  1643. // Make sure the keyword is well-formed
  1644. //
  1645. if (! (pstrKeyword = PstrStripKeywordChar(pParserData->achOption)))
  1646. return ISyntaxError(pParserData->pFile, "Empty keyword");
  1647. //
  1648. // HACK: special-case handling of "*OpenUI: *ManualFeed" entry
  1649. //
  1650. if (strcmp(pstrKeyword, gstrManualFeedKwd) == EQUAL_STRING)
  1651. return PPDERR_NONE;
  1652. if (! (pParserData->pOpenFeature = PCreateFeatureItem(pParserData, GID_UNKNOWN)))
  1653. return PPDERR_MEMORY;
  1654. //
  1655. // Determine the type of feature option list
  1656. //
  1657. if (! BSearchStrTable(UITypeStrs,
  1658. pParserData->pstrValue,
  1659. &pParserData->pOpenFeature->dwUIType))
  1660. {
  1661. ISyntaxError(pParserData->pFile, "Unrecognized UI type");
  1662. }
  1663. //
  1664. // Are we dealing with JCLOpenUI?
  1665. //
  1666. pParserData->bJclFeature = HAS_JCL_PREFIX(pstrKeyword);
  1667. return PPDERR_NONE;
  1668. }
  1669. //
  1670. // Mark the end of a new printer feature section
  1671. //
  1672. PPDERROR
  1673. ICloseUIProc(
  1674. PPARSERDATA pParserData
  1675. )
  1676. {
  1677. PCSTR pstrKeyword;
  1678. PFEATUREOBJ pOpenFeature;
  1679. //
  1680. // Make sure the CloseUI entry is balanced with a previous OpenUI entry
  1681. //
  1682. pOpenFeature = pParserData->pOpenFeature;
  1683. pParserData->pOpenFeature = NULL;
  1684. pstrKeyword = PstrStripKeywordChar(pParserData->pstrValue);
  1685. //
  1686. // HACK: special-case handling of "*CloseUI: *ManualFeed" entry
  1687. //
  1688. if (pstrKeyword && strcmp(pstrKeyword, gstrManualFeedKwd) == EQUAL_STRING)
  1689. return PPDERR_NONE;
  1690. if (pOpenFeature == NULL ||
  1691. pstrKeyword == NULL ||
  1692. strcmp(pstrKeyword, pOpenFeature->pstrName) != EQUAL_STRING ||
  1693. pParserData->bJclFeature != HAS_JCL_PREFIX(pstrKeyword))
  1694. {
  1695. return ISyntaxError(pParserData->pFile, "Invalid CloseUI entry");
  1696. }
  1697. return PPDERR_NONE;
  1698. }
  1699. //
  1700. // Process OpenGroup and CloseGroup entries
  1701. //
  1702. // !!! OpenGroup, CloseGroup, OpenSubGroup, and CloseSubGroup
  1703. // keywords are not completely supported. Currently, we
  1704. // only pay specific attention to the InstallableOptions group.
  1705. //
  1706. // If the group information is needed in the future by the
  1707. // user interface, the following functions should be beefed up.
  1708. //
  1709. PPDERROR
  1710. IOpenCloseGroupProc(
  1711. PPARSERDATA pParserData,
  1712. BOOL bOpenGroup
  1713. )
  1714. {
  1715. PSTR pstrGroupName = pParserData->pstrValue;
  1716. //
  1717. // We're only interested in the InstallableOptions group
  1718. //
  1719. if (strcmp(pstrGroupName, "InstallableOptions") == EQUAL_STRING)
  1720. {
  1721. if (pParserData->bInstallableGroup == bOpenGroup)
  1722. return ISyntaxError(pParserData->pFile, "Unbalanced OpenGroup/CloseGroup");
  1723. pParserData->bInstallableGroup = bOpenGroup;
  1724. }
  1725. else
  1726. {
  1727. VERBOSE(("Group %s ignored\n", pstrGroupName));
  1728. }
  1729. return PPDERR_NONE;
  1730. }
  1731. //
  1732. // Process OpenGroup entries
  1733. //
  1734. PPDERROR
  1735. IOpenGroupProc(
  1736. PPARSERDATA pParserData
  1737. )
  1738. {
  1739. return IOpenCloseGroupProc(pParserData, TRUE);
  1740. }
  1741. //
  1742. // Process CloseGroup entries
  1743. //
  1744. PPDERROR
  1745. ICloseGroupProc(
  1746. PPARSERDATA pParserData
  1747. )
  1748. {
  1749. return IOpenCloseGroupProc(pParserData, FALSE);
  1750. }
  1751. //
  1752. // Handle OpenSubGroup entries
  1753. //
  1754. PPDERROR
  1755. IOpenSubGroupProc(
  1756. PPARSERDATA pParserData
  1757. )
  1758. {
  1759. return PPDERR_NONE;
  1760. }
  1761. //
  1762. // Handle CloseSubGroup entries
  1763. //
  1764. PPDERROR
  1765. ICloseSubGroupProc(
  1766. PPARSERDATA pParserData
  1767. )
  1768. {
  1769. return PPDERR_NONE;
  1770. }
  1771. //
  1772. // Parse a UIConstraints entry
  1773. //
  1774. PPDERROR
  1775. IUIConstraintsProc(
  1776. PPARSERDATA pParserData
  1777. )
  1778. {
  1779. PLISTOBJ pItem;
  1780. if (! (pItem = ALLOC_PARSER_MEM(pParserData, sizeof(LISTOBJ))) ||
  1781. ! (pItem->pstrName = PstrParseString(pParserData, &pParserData->Value)))
  1782. {
  1783. ERR(("Memory allocation failed\n"));
  1784. return PPDERR_MEMORY;
  1785. }
  1786. pItem->pNext = pParserData->pUIConstraints;
  1787. pParserData->pUIConstraints = pItem;
  1788. return PPDERR_NONE;
  1789. }
  1790. //
  1791. // Parse an OrderDependency entry
  1792. //
  1793. PPDERROR
  1794. IOrderDepProc(
  1795. PPARSERDATA pParserData
  1796. )
  1797. {
  1798. PLISTOBJ pItem;
  1799. if (! (pItem = ALLOC_PARSER_MEM(pParserData, sizeof(LISTOBJ))) ||
  1800. ! (pItem->pstrName = PstrParseString(pParserData, &pParserData->Value)))
  1801. {
  1802. ERR(("Memory allocation failed\n"));
  1803. return PPDERR_MEMORY;
  1804. }
  1805. pItem->pNext = pParserData->pOrderDep;
  1806. pParserData->pOrderDep = pItem;
  1807. return PPDERR_NONE;
  1808. }
  1809. //
  1810. // Parse QueryOrderDependency entries
  1811. //
  1812. PPDERROR
  1813. IQueryOrderDepProc(
  1814. PPARSERDATA pParserData
  1815. )
  1816. {
  1817. PLISTOBJ pItem;
  1818. if (! (pItem = ALLOC_PARSER_MEM(pParserData, sizeof(LISTOBJ))) ||
  1819. ! (pItem->pstrName = PstrParseString(pParserData, &pParserData->Value)))
  1820. {
  1821. ERR(("Memory allocation failed\n"));
  1822. return PPDERR_MEMORY;
  1823. }
  1824. pItem->pNext = pParserData->pQueryOrderDep;
  1825. pParserData->pQueryOrderDep = pItem;
  1826. return PPDERR_NONE;
  1827. }
  1828. //
  1829. // Specifies memory configuration information
  1830. //
  1831. PPDERROR
  1832. IVMOptionProc(
  1833. PPARSERDATA pParserData
  1834. )
  1835. {
  1836. PMEMOBJ pOption;
  1837. if (! (pOption = PvCreateOptionItem(pParserData, GID_MEMOPTION)))
  1838. return PPDERR_MEMORY;
  1839. if (pOption->dwFreeVM)
  1840. {
  1841. WARN_DUPLICATE();
  1842. return PPDERR_NONE;
  1843. }
  1844. return IParseInteger(pParserData, &pOption->dwFreeVM);
  1845. }
  1846. //
  1847. // Specifies font cache size information
  1848. //
  1849. PPDERROR
  1850. IFCacheSizeProc(
  1851. PPARSERDATA pParserData
  1852. )
  1853. {
  1854. PMEMOBJ pOption;
  1855. if (! (pOption = PvCreateOptionItem(pParserData, GID_MEMOPTION)))
  1856. return PPDERR_MEMORY;
  1857. if (pOption->dwFontMem)
  1858. {
  1859. WARN_DUPLICATE();
  1860. return PPDERR_NONE;
  1861. }
  1862. return IParseInteger(pParserData, &pOption->dwFontMem);
  1863. }
  1864. //
  1865. // Specifies the minimum amount of free VM
  1866. //
  1867. PPDERROR
  1868. IFreeVMProc(
  1869. PPARSERDATA pParserData
  1870. )
  1871. {
  1872. return IParseInteger(pParserData, &pParserData->dwFreeMem);
  1873. }
  1874. //
  1875. // Include another file
  1876. //
  1877. PPDERROR
  1878. IIncludeProc(
  1879. PPARSERDATA pParserData
  1880. )
  1881. #define MAX_INCLUDE_LEVEL 10
  1882. {
  1883. WCHAR awchFilename[MAX_PATH];
  1884. PFILEOBJ pPreviousFile;
  1885. PPDERROR iStatus;
  1886. if (pParserData->iIncludeLevel >= MAX_INCLUDE_LEVEL)
  1887. {
  1888. ERR(("There appears to be recursive *Include.\n"));
  1889. return PPDERR_FILE;
  1890. }
  1891. if (! MultiByteToWideChar(CP_ACP, 0, pParserData->pstrValue, -1, awchFilename, MAX_PATH))
  1892. return ISyntaxError(pParserData->pFile, "Invalid include filename");
  1893. VERBOSE(("Including file %ws ...\n", awchFilename));
  1894. pPreviousFile = pParserData->pFile;
  1895. pParserData->iIncludeLevel++;
  1896. iStatus = IParseFile(pParserData, awchFilename);
  1897. pParserData->iIncludeLevel--;
  1898. pParserData->pFile = pPreviousFile;
  1899. return iStatus;
  1900. }
  1901. //
  1902. // Specifies the printer description file format version number
  1903. //
  1904. PPDERROR
  1905. IPPDAdobeProc(
  1906. PPARSERDATA pParserData
  1907. )
  1908. {
  1909. return IParseVersionNumber(pParserData, &pParserData->dwSpecVersion);
  1910. }
  1911. //
  1912. // Specifies the printer description file format version number
  1913. //
  1914. PPDERROR
  1915. IFormatVersionProc(
  1916. PPARSERDATA pParserData
  1917. )
  1918. {
  1919. if (pParserData->dwSpecVersion != 0)
  1920. return PPDERR_NONE;
  1921. return IParseVersionNumber(pParserData, &pParserData->dwSpecVersion);
  1922. }
  1923. //
  1924. // Specifies the PPD file version number
  1925. //
  1926. PPDERROR
  1927. IFileVersionProc(
  1928. PPARSERDATA pParserData
  1929. )
  1930. {
  1931. return IParseVersionNumber(pParserData, &pParserData->dwPpdFilever);
  1932. }
  1933. //
  1934. // Specifies the protocols supported by the device
  1935. //
  1936. PPDERROR
  1937. IProtocolsProc(
  1938. PPARSERDATA pParserData
  1939. )
  1940. {
  1941. static const STRTABLE ProtocolStrs[] =
  1942. {
  1943. "PJL", PROTOCOL_PJL,
  1944. "BCP", PROTOCOL_BCP,
  1945. "TBCP", PROTOCOL_TBCP,
  1946. "SIC", PROTOCOL_SIC,
  1947. NULL, 0
  1948. };
  1949. CHAR achWord[MAX_WORD_LEN];
  1950. DWORD dwProtocol;
  1951. PSTR pstr = pParserData->pstrValue;
  1952. while (BFindNextWord(&pstr, achWord))
  1953. {
  1954. if (BSearchStrTable(ProtocolStrs, achWord, &dwProtocol))
  1955. pParserData->dwProtocols |= dwProtocol;
  1956. else
  1957. TERSE(("Unknown protocol: %s\n", achWord));
  1958. }
  1959. return PPDERR_NONE;
  1960. }
  1961. //
  1962. // Specifies whether the device supports color output
  1963. //
  1964. PPDERROR
  1965. IColorDeviceProc(
  1966. PPARSERDATA pParserData
  1967. )
  1968. {
  1969. return IParseBoolean(pParserData, &pParserData->dwColorDevice);
  1970. }
  1971. //
  1972. // Specifies whether the device fonts already have the Euro
  1973. //
  1974. PPDERROR
  1975. IHasEuroProc(
  1976. PPARSERDATA pParserData
  1977. )
  1978. {
  1979. PPDERROR rc;
  1980. if (rc = IParseBoolean(pParserData, &pParserData->bHasEuro) != PPDERR_NONE)
  1981. return rc;
  1982. pParserData->bEuroInformationSet = TRUE;
  1983. return PPDERR_NONE;
  1984. }
  1985. //
  1986. // Specifies whether the device fonts already have the Euro
  1987. //
  1988. PPDERROR
  1989. ITrueGrayProc(
  1990. PPARSERDATA pParserData
  1991. )
  1992. {
  1993. return IParseBoolean(pParserData, &pParserData->bTrueGray);
  1994. }
  1995. //
  1996. // Specifies the language extensions supported by the device
  1997. //
  1998. PPDERROR
  1999. IExtensionsProc(
  2000. PPARSERDATA pParserData
  2001. )
  2002. {
  2003. static const STRTABLE ExtensionStrs[] =
  2004. {
  2005. "DPS", LANGEXT_DPS,
  2006. "CMYK", LANGEXT_CMYK,
  2007. "Composite", LANGEXT_COMPOSITE,
  2008. "FileSystem", LANGEXT_FILESYSTEM,
  2009. NULL, 0
  2010. };
  2011. CHAR achWord[MAX_WORD_LEN];
  2012. INT dwExtension;
  2013. PSTR pstr = pParserData->pstrValue;
  2014. while (BFindNextWord(&pstr, achWord))
  2015. {
  2016. if (BSearchStrTable(ExtensionStrs, achWord, &dwExtension))
  2017. pParserData->dwExtensions |= dwExtension;
  2018. else
  2019. TERSE(("Unknown extension: %s\n", achWord));
  2020. }
  2021. return PPDERR_NONE;
  2022. }
  2023. //
  2024. // Specifies whether the device has a file system on disk
  2025. //
  2026. PPDERROR
  2027. IFileSystemProc(
  2028. PPARSERDATA pParserData
  2029. )
  2030. {
  2031. DWORD dwFileSystem;
  2032. PPDERROR iStatus;
  2033. if ((iStatus = IParseBoolean(pParserData, &dwFileSystem)) == PPDERR_NONE)
  2034. {
  2035. if (dwFileSystem)
  2036. pParserData->dwExtensions |= LANGEXT_FILESYSTEM;
  2037. else
  2038. pParserData->dwExtensions &= ~LANGEXT_FILESYSTEM;
  2039. }
  2040. return iStatus;
  2041. }
  2042. //
  2043. // Specifies the device name
  2044. //
  2045. PPDERROR
  2046. INickNameProc(
  2047. PPARSERDATA pParserData
  2048. )
  2049. {
  2050. //
  2051. // Use NickName only if ShortNickName entry is not present
  2052. //
  2053. if (pParserData->NickName.pvData == NULL)
  2054. return IParseInvocation(pParserData, &pParserData->NickName);
  2055. else
  2056. return PPDERR_NONE;
  2057. }
  2058. //
  2059. // Specifies the short device name
  2060. //
  2061. PPDERROR
  2062. IShortNameProc(
  2063. PPARSERDATA pParserData
  2064. )
  2065. {
  2066. pParserData->NickName.dwLength = 0;
  2067. pParserData->NickName.pvData = NULL;
  2068. return IParseInvocation(pParserData, &pParserData->NickName);
  2069. }
  2070. //
  2071. // Specifies the PostScript language level
  2072. //
  2073. PPDERROR
  2074. ILangLevelProc(
  2075. PPARSERDATA pParserData
  2076. )
  2077. {
  2078. return IParseInteger(pParserData, &pParserData->dwLangLevel);
  2079. }
  2080. //
  2081. // Specifies PPD language encoding options
  2082. //
  2083. PPDERROR
  2084. ILangEncProc(
  2085. PPARSERDATA pParserData
  2086. )
  2087. {
  2088. //
  2089. // NOTE: Only the following two language encodings are supported because
  2090. // the rest of them are not used (according to our discussions with Adobe).
  2091. // In any case, we don't have any direct way of translating ANSI strings
  2092. // in other encodings to Unicode.
  2093. //
  2094. // A possible future PPD extension is to allow Unicode encoding directly
  2095. // in translation strings.
  2096. //
  2097. static const STRTABLE LangEncStrs[] =
  2098. {
  2099. "ISOLatin1", LANGENC_ISOLATIN1,
  2100. "WindowsANSI", LANGENC_ISOLATIN1, // WindowsANSI means CharSet=0, which is now page 1252->ISO Latin1
  2101. "None", LANGENC_NONE,
  2102. "Unicode", LANGENC_UNICODE,
  2103. "JIS83-RKSJ", LANGENC_JIS83_RKSJ,
  2104. NULL, LANGENC_NONE
  2105. };
  2106. if (! BSearchStrTable(LangEncStrs, pParserData->pstrValue, &pParserData->dwLangEncoding))
  2107. return ISyntaxError(pParserData->pFile, "Unsupported LanguageEncoding keyword");
  2108. else
  2109. return PPDERR_NONE;
  2110. }
  2111. //
  2112. // Identifies the natural language used in the PPD file
  2113. //
  2114. PPDERROR
  2115. ILangVersProc(
  2116. PPARSERDATA pParserData
  2117. )
  2118. {
  2119. static const STRTABLE LangVersionStrs[] = {
  2120. "English", LANGENC_ISOLATIN1,
  2121. "Danish", LANGENC_ISOLATIN1,
  2122. "Dutch", LANGENC_ISOLATIN1,
  2123. "Finnish", LANGENC_ISOLATIN1,
  2124. "French", LANGENC_ISOLATIN1,
  2125. "German", LANGENC_ISOLATIN1,
  2126. "Italian", LANGENC_ISOLATIN1,
  2127. "Norwegian", LANGENC_ISOLATIN1,
  2128. "Portuguese", LANGENC_ISOLATIN1,
  2129. "Spanish", LANGENC_ISOLATIN1,
  2130. "Swedish", LANGENC_ISOLATIN1,
  2131. "Japanese", LANGENC_JIS83_RKSJ,
  2132. "Chinese", LANGENC_NONE,
  2133. "Russian", LANGENC_NONE,
  2134. NULL, LANGENC_NONE
  2135. };
  2136. if (pParserData->dwLangEncoding == LANGENC_NONE &&
  2137. ! BSearchStrTable(LangVersionStrs, pParserData->pstrValue, &pParserData->dwLangEncoding))
  2138. {
  2139. return ISyntaxError(pParserData->pFile, "Unsupported LanguageVersion keyword");
  2140. }
  2141. return PPDERR_NONE;
  2142. }
  2143. //
  2144. // Specifies the available TrueType rasterizer options
  2145. //
  2146. PPDERROR
  2147. ITTRasterizerProc(
  2148. PPARSERDATA pParserData
  2149. )
  2150. {
  2151. static const STRTABLE RasterizerStrs[] =
  2152. {
  2153. "None", TTRAS_NONE,
  2154. "Accept68K", TTRAS_ACCEPT68K,
  2155. "Type42", TTRAS_TYPE42,
  2156. "TrueImage", TTRAS_TRUEIMAGE,
  2157. NULL, TTRAS_NONE
  2158. };
  2159. if (! BSearchStrTable(RasterizerStrs, pParserData->pstrValue, &pParserData->dwTTRasterizer))
  2160. return ISyntaxError(pParserData->pFile, "Unknown TTRasterizer option");
  2161. else
  2162. return PPDERR_NONE;
  2163. }
  2164. //
  2165. // Specifies the exitserver invocation string
  2166. //
  2167. PPDERROR
  2168. IExitServerProc(
  2169. PPARSERDATA pParserData
  2170. )
  2171. {
  2172. return IParseInvocation(pParserData, &pParserData->ExitServer);
  2173. }
  2174. //
  2175. // Specifies the password string
  2176. //
  2177. PPDERROR
  2178. IPasswordProc(
  2179. PPARSERDATA pParserData
  2180. )
  2181. {
  2182. return IParseInvocation(pParserData, &pParserData->Password);
  2183. }
  2184. //
  2185. // Specifies the PatchFile invocation string
  2186. //
  2187. PPDERROR
  2188. IPatchFileProc(
  2189. PPARSERDATA pParserData
  2190. )
  2191. {
  2192. return IParseInvocation(pParserData, &pParserData->PatchFile);
  2193. }
  2194. //
  2195. // Specifies JobPatchFile invocation strings
  2196. //
  2197. PPDERROR
  2198. IJobPatchFileProc(
  2199. PPARSERDATA pParserData
  2200. )
  2201. {
  2202. PJOBPATCHFILEOBJ pItem;
  2203. PSTR pTmp;
  2204. //
  2205. // Create a new job patch file item
  2206. //
  2207. if (! (pItem = PvCreateListItem(pParserData,
  2208. (PLISTOBJ *) &pParserData->pJobPatchFiles,
  2209. sizeof(JOBPATCHFILEOBJ),
  2210. "JobPatchFile")))
  2211. {
  2212. return PPDERR_MEMORY;
  2213. }
  2214. //
  2215. // Parse the job patch file invocation string
  2216. //
  2217. if (pItem->Invocation.pvData)
  2218. {
  2219. WARN_DUPLICATE();
  2220. return PPDERR_NONE;
  2221. }
  2222. //
  2223. // warn if number of patch file is invalid
  2224. //
  2225. pTmp = pItem->pstrName;
  2226. if (!BGetIntegerFromString(&pTmp, &pItem->lPatchNo))
  2227. {
  2228. TERSE(("Warning: invalid JobPatchFile number '%s' on line %d\n",
  2229. pParserData->achOption, pParserData->pFile->iLineNumber));
  2230. pItem->lPatchNo = 0;
  2231. }
  2232. return IParseInvocation(pParserData, &pItem->Invocation);
  2233. }
  2234. //
  2235. // Specifies PostScript interpreter version and revision number
  2236. //
  2237. PPDERROR
  2238. IPSVersionProc(
  2239. PPARSERDATA pParserData
  2240. )
  2241. {
  2242. PSTR pstr = pParserData->Value.pbuf;
  2243. DWORD dwVersion;
  2244. PPDERROR status;
  2245. //
  2246. // Save the first PSVersion string
  2247. //
  2248. if ((pParserData->PSVersion.pvData == NULL) &&
  2249. ((status = IParseInvocation(pParserData, &pParserData->PSVersion)) != PPDERR_NONE))
  2250. {
  2251. return status;
  2252. }
  2253. //
  2254. // Skip non-digit characters
  2255. //
  2256. while (*pstr && !IS_DIGIT(*pstr))
  2257. pstr++;
  2258. //
  2259. // Extract the PS interpreter version number
  2260. //
  2261. dwVersion = 0;
  2262. while (*pstr && IS_DIGIT(*pstr))
  2263. dwVersion = dwVersion * 10 + (*pstr++ - '0');
  2264. if (dwVersion > 0)
  2265. {
  2266. //
  2267. // Remember the lowest PSVersion number
  2268. //
  2269. if (pParserData->dwPSVersion == 0 || pParserData->dwPSVersion > dwVersion)
  2270. pParserData->dwPSVersion = dwVersion;
  2271. return PPDERR_NONE;
  2272. }
  2273. else
  2274. return ISyntaxError(pParserData->pFile, "Invalid PSVersion entry");
  2275. }
  2276. //
  2277. // Specifies the Product string
  2278. //
  2279. PPDERROR
  2280. IProductProc(
  2281. PPARSERDATA pParserData
  2282. )
  2283. {
  2284. //
  2285. // only store the first *Product entry, though there may be multiple
  2286. //
  2287. if (pParserData->Product.dwLength != 0)
  2288. return PPDERR_NONE;
  2289. return IParseInvocation(pParserData, &pParserData->Product);
  2290. }
  2291. //
  2292. // Specifies the default job timeout value
  2293. //
  2294. PPDERROR
  2295. IJobTimeoutProc(
  2296. PPARSERDATA pParserData
  2297. )
  2298. {
  2299. return IParseInteger(pParserData, &pParserData->dwJobTimeout);
  2300. }
  2301. //
  2302. // Specifies the default wait timeout value
  2303. //
  2304. PPDERROR
  2305. IWaitTimeoutProc(
  2306. PPARSERDATA pParserData
  2307. )
  2308. {
  2309. return IParseInteger(pParserData, &pParserData->dwWaitTimeout);
  2310. }
  2311. //
  2312. // Specifies whether error handler should be enabled by default
  2313. //
  2314. PPDERROR
  2315. IPrintPSErrProc(
  2316. PPARSERDATA pParserData
  2317. )
  2318. {
  2319. DWORD dwValue;
  2320. if (IParseBoolean(pParserData, &dwValue) != PPDERR_NONE)
  2321. return PPDERR_SYNTAX;
  2322. if (dwValue)
  2323. pParserData->dwPpdFlags |= PPDFLAG_PRINTPSERROR;
  2324. else
  2325. pParserData->dwPpdFlags &= ~PPDFLAG_PRINTPSERROR;
  2326. return PPDERR_NONE;
  2327. }
  2328. //
  2329. // Specifies PJL commands to start a job
  2330. //
  2331. PPDERROR
  2332. IJCLBeginProc(
  2333. PPARSERDATA pParserData
  2334. )
  2335. {
  2336. pParserData->dwPpdFlags |= PPDFLAG_HAS_JCLBEGIN;
  2337. return IParseInvocation(pParserData, &pParserData->JclBegin);
  2338. }
  2339. //
  2340. // Specifies PJL commands to switch into PostScript language
  2341. //
  2342. PPDERROR
  2343. IJCLToPSProc(
  2344. PPARSERDATA pParserData
  2345. )
  2346. {
  2347. pParserData->dwPpdFlags |= PPDFLAG_HAS_JCLENTERPS;
  2348. return IParseInvocation(pParserData, &pParserData->JclEnterPS);
  2349. }
  2350. //
  2351. // Specifies PJL commands to end a job
  2352. //
  2353. PPDERROR
  2354. IJCLEndProc(
  2355. PPARSERDATA pParserData
  2356. )
  2357. {
  2358. pParserData->dwPpdFlags |= PPDFLAG_HAS_JCLEND;
  2359. return IParseInvocation(pParserData, &pParserData->JclEnd);
  2360. }
  2361. //
  2362. // Specifies the default landscape orientation mode
  2363. //
  2364. PPDERROR
  2365. ILSOrientProc(
  2366. PPARSERDATA pParserData
  2367. )
  2368. {
  2369. static const STRTABLE LsoStrs[] =
  2370. {
  2371. "Any", LSO_ANY,
  2372. "Plus90", LSO_PLUS90,
  2373. "Minus90", LSO_MINUS90,
  2374. NULL, LSO_ANY
  2375. };
  2376. if (! BSearchStrTable(LsoStrs, pParserData->pstrValue, &pParserData->dwLSOrientation))
  2377. return ISyntaxError(pParserData->pFile, "Unrecognized landscape orientation");
  2378. else
  2379. return PPDERR_NONE;
  2380. }
  2381. PPAPEROBJ
  2382. PCreateCustomSizeOption(
  2383. PPARSERDATA pParserData
  2384. )
  2385. /*++
  2386. Routine Description:
  2387. Create a CustomPageSize option for PageSize feature (if necessary)
  2388. Arguments:
  2389. pParserData - Points to parser data structure
  2390. Return Value:
  2391. Pointer to newly created CustomPageSize option item or
  2392. the existing CustomPageSize option item if it already exists.
  2393. NULL if there is an error.
  2394. --*/
  2395. {
  2396. PPAPEROBJ pCustomSize;
  2397. BUFOBJ SavedBuffer;
  2398. //
  2399. // Create an item corresponding to *PageSize feature if needed
  2400. //
  2401. SavedBuffer = pParserData->Option;
  2402. pParserData->Option.pbuf = (PBYTE) gstrCustomSizeKwd;
  2403. pParserData->Option.dwSize = strlen(gstrCustomSizeKwd);
  2404. pCustomSize = PvCreateOptionItem(pParserData, GID_PAGESIZE);
  2405. pParserData->Option = SavedBuffer;
  2406. return pCustomSize;;
  2407. }
  2408. //
  2409. // Specifies custom paper size invocation string
  2410. //
  2411. PPDERROR
  2412. ICustomSizeProc(
  2413. PPARSERDATA pParserData
  2414. )
  2415. {
  2416. PPAPEROBJ pCustomSize;
  2417. if (strcmp(pParserData->achOption, gstrTrueKwd) != EQUAL_STRING)
  2418. {
  2419. ISyntaxError(pParserData->pFile, "Invalid *CustomPageSize option");
  2420. return PPDERR_NONE;
  2421. }
  2422. if (! (pCustomSize = PCreateCustomSizeOption(pParserData)))
  2423. return PPDERR_MEMORY;
  2424. if (pCustomSize->Option.Invocation.pvData)
  2425. {
  2426. WARN_DUPLICATE();
  2427. return PPDERR_NONE;
  2428. }
  2429. return IParseInvocation(pParserData, &pCustomSize->Option.Invocation);
  2430. }
  2431. //
  2432. // Specifies custom paper size parameters
  2433. //
  2434. PPDERROR
  2435. IParamCustomProc(
  2436. PPARSERDATA pParserData
  2437. )
  2438. {
  2439. static const STRTABLE CustomParamStrs[] =
  2440. {
  2441. "Width", CUSTOMPARAM_WIDTH,
  2442. "Height", CUSTOMPARAM_HEIGHT,
  2443. "WidthOffset", CUSTOMPARAM_WIDTHOFFSET,
  2444. "HeightOffset", CUSTOMPARAM_HEIGHTOFFSET,
  2445. "Orientation", CUSTOMPARAM_ORIENTATION,
  2446. NULL, 0
  2447. };
  2448. CHAR achWord[MAX_WORD_LEN];
  2449. LONG lMinVal, lMaxVal;
  2450. INT iType;
  2451. DWORD dwParam;
  2452. LONG lOrder;
  2453. PSTR pstr = pParserData->pstrValue;
  2454. //
  2455. // The format for a ParamCustomPageSize entry:
  2456. // ParameterName Order Type MinVal MaxVal
  2457. //
  2458. if (! BSearchStrTable(CustomParamStrs, pParserData->achOption, &dwParam) ||
  2459. ! BGetIntegerFromString(&pstr, &lOrder) ||
  2460. ! BFindNextWord(&pstr, achWord) ||
  2461. lOrder <= 0 || lOrder > CUSTOMPARAM_MAX)
  2462. {
  2463. return ISyntaxError(pParserData->pFile, "Bad *ParamCustomPageSize entry");
  2464. }
  2465. //
  2466. // Expected type is "int" for Orientation parameter and "points" for other parameters
  2467. //
  2468. iType = (dwParam == CUSTOMPARAM_ORIENTATION) ?
  2469. ((strcmp(achWord, "int") == EQUAL_STRING) ? FLTYPE_INT : FLTYPE_ERROR) :
  2470. ((strcmp(achWord, "points") == EQUAL_STRING) ? FLTYPE_POINT : FLTYPE_ERROR);
  2471. if (iType == FLTYPE_ERROR ||
  2472. ! BGetFloatFromString(&pstr, &lMinVal, iType) ||
  2473. ! BGetFloatFromString(&pstr, &lMaxVal, iType) ||
  2474. lMinVal > lMaxVal)
  2475. {
  2476. return ISyntaxError(pParserData->pFile, "Bad *ParamCustomPageSize entry");
  2477. }
  2478. pParserData->CustomSizeParams[dwParam].dwOrder = lOrder;
  2479. pParserData->CustomSizeParams[dwParam].lMinVal = lMinVal;
  2480. pParserData->CustomSizeParams[dwParam].lMaxVal = lMaxVal;
  2481. return PPDERR_NONE;
  2482. }
  2483. //
  2484. // Specifies the maximum height of custom paper size
  2485. //
  2486. PPDERROR
  2487. IMaxWidthProc(
  2488. PPARSERDATA pParserData
  2489. )
  2490. {
  2491. PPAPEROBJ pCustomSize;
  2492. LONG lValue;
  2493. PSTR pstr = pParserData->pstrValue;
  2494. if (! BGetFloatFromString(&pstr, &lValue, FLTYPE_POINT) || lValue <= 0)
  2495. return ISyntaxError(pParserData->pFile, "Invalid media width");
  2496. if (! (pCustomSize = PCreateCustomSizeOption(pParserData)))
  2497. return PPDERR_MEMORY;
  2498. pCustomSize->szDimension.cx = lValue;
  2499. return PPDERR_NONE;
  2500. }
  2501. //
  2502. // Specifies the maximum height of custom paper size
  2503. //
  2504. PPDERROR
  2505. IMaxHeightProc(
  2506. PPARSERDATA pParserData
  2507. )
  2508. {
  2509. PPAPEROBJ pCustomSize;
  2510. LONG lValue;
  2511. PSTR pstr = pParserData->pstrValue;
  2512. if (! BGetFloatFromString(&pstr, &lValue, FLTYPE_POINT) || lValue <= 0)
  2513. return ISyntaxError(pParserData->pFile, "Invalid media height");
  2514. if (! (pCustomSize = PCreateCustomSizeOption(pParserData)))
  2515. return PPDERR_MEMORY;
  2516. pCustomSize->szDimension.cy = lValue;
  2517. return PPDERR_NONE;
  2518. }
  2519. //
  2520. // Specifies the hardware margins on cut-sheet devices
  2521. //
  2522. PPDERROR
  2523. IHWMarginsProc(
  2524. PPARSERDATA pParserData
  2525. )
  2526. {
  2527. PPAPEROBJ pCustomSize;
  2528. RECT rc;
  2529. PSTR pstr = pParserData->pstrValue;
  2530. //
  2531. // Parse hardware margins: left, bottom, right, top
  2532. //
  2533. if (! BGetFloatFromString(&pstr, &rc.left, FLTYPE_POINT) ||
  2534. ! BGetFloatFromString(&pstr, &rc.bottom, FLTYPE_POINT) ||
  2535. ! BGetFloatFromString(&pstr, &rc.right, FLTYPE_POINT) ||
  2536. ! BGetFloatFromString(&pstr, &rc.top, FLTYPE_POINT))
  2537. {
  2538. return ISyntaxError(pParserData->pFile, "Invalid HWMargins");
  2539. }
  2540. if (! (pCustomSize = PCreateCustomSizeOption(pParserData)))
  2541. return PPDERR_MEMORY;
  2542. pCustomSize->rcImageArea = rc;
  2543. //
  2544. // The presence of HWMargins entry indicates the device supports cut-sheet
  2545. //
  2546. pParserData->dwCustomSizeFlags |= CUSTOMSIZE_CUTSHEET;
  2547. return PPDERR_NONE;
  2548. }
  2549. //
  2550. // Function to process *CenterRegistered entry
  2551. //
  2552. PPDERROR
  2553. ICenterRegProc(
  2554. PPARSERDATA pParserData
  2555. )
  2556. {
  2557. DWORD dwValue;
  2558. if (IParseBoolean(pParserData, &dwValue) != PPDERR_NONE)
  2559. return PPDERR_SYNTAX;
  2560. if (dwValue)
  2561. pParserData->dwCustomSizeFlags |= CUSTOMSIZE_CENTERREG;
  2562. else
  2563. pParserData->dwCustomSizeFlags &= ~CUSTOMSIZE_CENTERREG;
  2564. return PPDERR_NONE;
  2565. }
  2566. //
  2567. // Function to process *ADORequiresEExec entry
  2568. //
  2569. PPDERROR
  2570. IReqEExecProc(
  2571. PPARSERDATA pParserData
  2572. )
  2573. {
  2574. DWORD dwValue;
  2575. if (IParseBoolean(pParserData, &dwValue) != PPDERR_NONE)
  2576. return PPDERR_SYNTAX;
  2577. if (dwValue)
  2578. pParserData->dwPpdFlags |= PPDFLAG_REQEEXEC;
  2579. else
  2580. pParserData->dwPpdFlags &= ~PPDFLAG_REQEEXEC;
  2581. return PPDERR_NONE;
  2582. }
  2583. //
  2584. // Function to process *ADOTTFontSub entry
  2585. //
  2586. PPDERROR
  2587. ITTFontSubProc(
  2588. PPARSERDATA pParserData
  2589. )
  2590. {
  2591. PTTFONTSUB pTTFontSub;
  2592. //
  2593. // Create a new font substitution item
  2594. //
  2595. if (! (pTTFontSub = PvCreateXlatedItem(
  2596. pParserData,
  2597. &pParserData->pTTFontSubs,
  2598. sizeof(TTFONTSUB))))
  2599. {
  2600. return PPDERR_MEMORY;
  2601. }
  2602. //
  2603. // Parse the PS family name
  2604. //
  2605. if (pTTFontSub->PSName.pvData)
  2606. {
  2607. WARN_DUPLICATE();
  2608. return PPDERR_NONE;
  2609. }
  2610. if (*pParserData->pstrValue == NUL)
  2611. return ISyntaxError(pParserData->pFile, "Missing TrueType font family name");
  2612. return IParseInvocation(pParserData, &pTTFontSub->PSName);
  2613. }
  2614. //
  2615. // Function to process *Throughput entry
  2616. //
  2617. PPDERROR
  2618. IThroughputProc(
  2619. PPARSERDATA pParserData
  2620. )
  2621. {
  2622. return IParseInteger(pParserData, &pParserData->dwThroughput);
  2623. }
  2624. //
  2625. // Function to ignore the current entry
  2626. //
  2627. PPDERROR
  2628. INullProc(
  2629. PPARSERDATA pParserData
  2630. )
  2631. {
  2632. return PPDERR_NONE;
  2633. }
  2634. //
  2635. // Define a named symbol
  2636. //
  2637. PPDERROR
  2638. ISymbolValueProc(
  2639. PPARSERDATA pParserData
  2640. )
  2641. {
  2642. PSYMBOLOBJ pSymbol;
  2643. if (pParserData->dwValueType == VALUETYPE_SYMBOL)
  2644. return ISyntaxError(pParserData->pFile, "Symbol value cannot be another symbol");
  2645. //
  2646. // Create a new symbol item
  2647. //
  2648. if (! (pSymbol = PvCreateListItem(pParserData,
  2649. (PLISTOBJ *) &pParserData->pSymbols,
  2650. sizeof(SYMBOLOBJ),
  2651. "Symbol")))
  2652. {
  2653. return PPDERR_MEMORY;
  2654. }
  2655. //
  2656. // Parse the symbol value
  2657. //
  2658. if (pSymbol->Invocation.pvData)
  2659. {
  2660. WARN_DUPLICATE();
  2661. return PPDERR_NONE;
  2662. }
  2663. return IParseInvocation(pParserData, &pSymbol->Invocation);
  2664. }
  2665. //
  2666. // Built-in keyword table
  2667. //
  2668. const CHAR gstrDefault[] = "Default";
  2669. const CHAR gstrPageSizeKwd[] = "PageSize";
  2670. const CHAR gstrInputSlotKwd[] = "InputSlot";
  2671. const CHAR gstrManualFeedKwd[] = "ManualFeed";
  2672. const CHAR gstrCustomSizeKwd[] = "CustomPageSize";
  2673. const CHAR gstrLetterSizeKwd[] = "Letter";
  2674. const CHAR gstrA4SizeKwd[] = "A4";
  2675. const CHAR gstrLongKwd[] = "Long";
  2676. const CHAR gstrShortKwd[] = "Short";
  2677. const CHAR gstrTrueKwd[] = "True";
  2678. const CHAR gstrFalseKwd[] = "False";
  2679. const CHAR gstrOnKwd[] = "On";
  2680. const CHAR gstrOffKwd[] = "Off";
  2681. const CHAR gstrNoneKwd[] = "None";
  2682. const CHAR gstrVMOptionKwd[] = "VMOption";
  2683. const CHAR gstrInstallMemKwd[] = "InstalledMemory";
  2684. const CHAR gstrDuplexTumble[] = "DuplexTumble";
  2685. const CHAR gstrDuplexNoTumble[] = "DuplexNoTumble";
  2686. const KWDENTRY gPpdBuiltInKeywordTable[] =
  2687. {
  2688. { gstrPageSizeKwd, NULL, GENERIC_ENTRY(GID_PAGESIZE) },
  2689. { "PageRegion", NULL, GENERIC_ENTRY(GID_PAGEREGION) },
  2690. { gstrInputSlotKwd, NULL, GENERIC_ENTRY(GID_INPUTSLOT) },
  2691. { "MediaType", NULL, GENERIC_ENTRY(GID_MEDIATYPE) },
  2692. { "OutputBin", NULL, GENERIC_ENTRY(GID_OUTPUTBIN) },
  2693. { "Collate", NULL, GENERIC_ENTRY(GID_COLLATE) },
  2694. { "Resolution", NULL, GENERIC_ENTRY(GID_RESOLUTION) },
  2695. { "InstalledMemory", NULL, GENERIC_ENTRY(GID_MEMOPTION) },
  2696. { "LeadingEdge", NULL, GENERIC_ENTRY(GID_LEADINGEDGE) },
  2697. { "UseHWMargins", NULL, GENERIC_ENTRY(GID_USEHWMARGINS) },
  2698. { "Duplex", IDuplexProc, INVOCA_VALUE | REQ_OPTION },
  2699. { "DefaultDuplex", IDefaultDuplexProc, STRING_VALUE },
  2700. { "PaperDimension", IPaperDimProc, QUOTED_NOHEX | REQ_OPTION },
  2701. { "ImageableArea", IImageAreaProc, QUOTED_NOHEX | REQ_OPTION },
  2702. { "RequiresPageRegion", IReqPageRgnProc, STRING_VALUE | REQ_OPTION },
  2703. { gstrManualFeedKwd, IManualFeedProc, INVOCA_VALUE | REQ_OPTION },
  2704. { "DefaultManualFeed", IDefManualFeedProc, STRING_VALUE },
  2705. { "PageStackOrder", IPageStackOrderProc, STRING_VALUE | REQ_OPTION },
  2706. { "DefaultOutputOrder", IDefOutputOrderProc, STRING_VALUE },
  2707. { "JCLResolution", IJCLResProc, INVOCA_VALUE | REQ_OPTION | ALLOW_HEX },
  2708. { "DefaultJCLResolution", IDefaultJCLResProc, STRING_VALUE },
  2709. { "SetResolution", ISetResProc, INVOCA_VALUE | REQ_OPTION },
  2710. { "ScreenAngle", IScreenAngleProc, QUOTED_VALUE },
  2711. { "ScreenFreq", IScreenFreqProc, QUOTED_VALUE },
  2712. { "ResScreenAngle", IResScreenAngleProc, QUOTED_NOHEX | REQ_OPTION },
  2713. { "ResScreenFreq", IResScreenFreqProc, QUOTED_NOHEX | REQ_OPTION },
  2714. { "Font", IFontProc, STRING_VALUE | REQ_OPTION },
  2715. { "DefaultFont", IDefaultFontProc, STRING_VALUE },
  2716. { "OpenUI", IOpenUIProc, STRING_VALUE | REQ_OPTION },
  2717. { "CloseUI", ICloseUIProc, STRING_VALUE | ALLOW_MULTI },
  2718. { "JCLOpenUI", IOpenUIProc, STRING_VALUE | REQ_OPTION },
  2719. { "JCLCloseUI", ICloseUIProc, STRING_VALUE | ALLOW_MULTI },
  2720. { "OrderDependency", IOrderDepProc, STRING_VALUE | ALLOW_MULTI },
  2721. { "UIConstraints", IUIConstraintsProc, STRING_VALUE | ALLOW_MULTI },
  2722. { "QueryOrderDependency", IQueryOrderDepProc, STRING_VALUE | ALLOW_MULTI },
  2723. { "NonUIOrderDependency", IOrderDepProc, STRING_VALUE | ALLOW_MULTI },
  2724. { "NonUIConstraints", IUIConstraintsProc, STRING_VALUE | ALLOW_MULTI },
  2725. { "VMOption", IVMOptionProc, QUOTED_NOHEX | REQ_OPTION },
  2726. { "FCacheSize", IFCacheSizeProc, STRING_VALUE | REQ_OPTION },
  2727. { "FreeVM", IFreeVMProc, QUOTED_VALUE },
  2728. { "OpenGroup", IOpenGroupProc, STRING_VALUE | ALLOW_MULTI },
  2729. { "CloseGroup", ICloseGroupProc, STRING_VALUE | ALLOW_MULTI },
  2730. { "OpenSubGroup", IOpenSubGroupProc, STRING_VALUE | ALLOW_MULTI },
  2731. { "CloseSubGroup", ICloseSubGroupProc, STRING_VALUE | ALLOW_MULTI },
  2732. { "Include", IIncludeProc, QUOTED_VALUE | ALLOW_MULTI },
  2733. { "PPD-Adobe", IPPDAdobeProc, QUOTED_VALUE },
  2734. { "FormatVersion", IFormatVersionProc, QUOTED_VALUE },
  2735. { "FileVersion", IFileVersionProc, QUOTED_VALUE },
  2736. { "ColorDevice", IColorDeviceProc, STRING_VALUE },
  2737. { "Protocols", IProtocolsProc, STRING_VALUE | ALLOW_MULTI },
  2738. { "Extensions", IExtensionsProc, STRING_VALUE | ALLOW_MULTI },
  2739. { "FileSystem", IFileSystemProc, STRING_VALUE },
  2740. { "NickName", INickNameProc, QUOTED_VALUE },
  2741. { "ShortNickName", IShortNameProc, QUOTED_VALUE },
  2742. { "LanguageLevel", ILangLevelProc, QUOTED_NOHEX },
  2743. { "LanguageEncoding", ILangEncProc, STRING_VALUE },
  2744. { "LanguageVersion", ILangVersProc, STRING_VALUE },
  2745. { "TTRasterizer", ITTRasterizerProc, STRING_VALUE },
  2746. { "ExitServer", IExitServerProc, INVOCA_VALUE },
  2747. { "Password", IPasswordProc, INVOCA_VALUE },
  2748. { "PatchFile", IPatchFileProc, INVOCA_VALUE },
  2749. { "JobPatchFile", IJobPatchFileProc, INVOCA_VALUE | REQ_OPTION },
  2750. { "PSVersion", IPSVersionProc, QUOTED_NOHEX | ALLOW_MULTI },
  2751. { "ModelName", INullProc, QUOTED_VALUE },
  2752. { "Product", IProductProc, QUOTED_NOHEX | ALLOW_MULTI },
  2753. { "SuggestedJobTimeout", IJobTimeoutProc, QUOTED_VALUE },
  2754. { "SuggestedWaitTimeout", IWaitTimeoutProc, QUOTED_VALUE },
  2755. { "PrintPSErrors", IPrintPSErrProc, STRING_VALUE },
  2756. { "JCLBegin", IJCLBeginProc, QUOTED_VALUE },
  2757. { "JCLToPSInterpreter", IJCLToPSProc, QUOTED_VALUE },
  2758. { "JCLEnd", IJCLEndProc, QUOTED_VALUE },
  2759. { "LandscapeOrientation", ILSOrientProc, STRING_VALUE },
  2760. { gstrCustomSizeKwd, ICustomSizeProc, INVOCA_VALUE | REQ_OPTION },
  2761. { "ParamCustomPageSize", IParamCustomProc, STRING_VALUE | REQ_OPTION },
  2762. { "MaxMediaWidth", IMaxWidthProc, QUOTED_VALUE },
  2763. { "MaxMediaHeight", IMaxHeightProc, QUOTED_VALUE },
  2764. { "HWMargins", IHWMarginsProc, STRING_VALUE },
  2765. { "CenterRegistered", ICenterRegProc, STRING_VALUE },
  2766. { "ADORequiresEExec", IReqEExecProc, STRING_VALUE },
  2767. { "ADOTTFontSub", ITTFontSubProc, QUOTED_VALUE | REQ_OPTION },
  2768. { "ADTrueGray", ITrueGrayProc, STRING_VALUE },
  2769. { "ADHasEuro", IHasEuroProc, STRING_VALUE },
  2770. { "Throughput", IThroughputProc, QUOTED_NOHEX },
  2771. { "SymbolValue", ISymbolValueProc, INVOCA_VALUE | REQ_OPTION },
  2772. { "Status", INullProc, QUOTED_VALUE | ALLOW_MULTI },
  2773. { "PrinterError", INullProc, QUOTED_VALUE | ALLOW_MULTI },
  2774. { "SymbolLength", INullProc, STRING_VALUE | REQ_OPTION },
  2775. { "SymbolEnd", INullProc, STRING_VALUE | ALLOW_MULTI },
  2776. { "End", INullProc, VALUETYPE_NONE | ALLOW_MULTI },
  2777. };
  2778. #define NUM_BUILTIN_KEYWORDS (sizeof(gPpdBuiltInKeywordTable) / sizeof(KWDENTRY))
  2779. DWORD
  2780. DwHashKeyword(
  2781. PSTR pstrKeyword
  2782. )
  2783. /*++
  2784. Routine Description:
  2785. Compute the hash value for the specified keyword string
  2786. Arguments:
  2787. pstrKeyword - Pointer to the keyword string to be hashed
  2788. Return Value:
  2789. Hash value computed using the specified keyword string
  2790. --*/
  2791. {
  2792. PBYTE pub = (PBYTE) pstrKeyword;
  2793. DWORD dwHashValue = 0;
  2794. while (*pub)
  2795. dwHashValue = (dwHashValue << 1) ^ *pub++;
  2796. return dwHashValue;
  2797. }
  2798. PKWDENTRY
  2799. PSearchKeywordTable(
  2800. PPARSERDATA pParserData,
  2801. PSTR pstrKeyword,
  2802. INT *piIndex
  2803. )
  2804. /*++
  2805. Routine Description:
  2806. Check if a keyword appears in the built-in keyword table
  2807. Arguments:
  2808. pParserData - Points to parser data structure
  2809. pstrKeyword - Specifies the keyword to be searched
  2810. piIndex - Returns the index of the entry in the built-in keyword
  2811. table corresponding to the specified keyword.
  2812. Return Value:
  2813. Pointer to the entry in the built-in table corresponding to the
  2814. specified keyword. NULL if the specified keyword is not supported.
  2815. --*/
  2816. {
  2817. DWORD dwHashValue;
  2818. INT iIndex;
  2819. ASSERT(pstrKeyword != NULL);
  2820. dwHashValue = DwHashKeyword(pstrKeyword);
  2821. for (iIndex = 0; iIndex < NUM_BUILTIN_KEYWORDS; iIndex++)
  2822. {
  2823. if (pParserData->pdwKeywordHashs[iIndex] == dwHashValue &&
  2824. strcmp(gPpdBuiltInKeywordTable[iIndex].pstrKeyword, pstrKeyword) == EQUAL_STRING)
  2825. {
  2826. *piIndex = iIndex;
  2827. return (PKWDENTRY) &gPpdBuiltInKeywordTable[iIndex];
  2828. }
  2829. }
  2830. return NULL;
  2831. }
  2832. BOOL
  2833. BInitKeywordLookup(
  2834. PPARSERDATA pParserData
  2835. )
  2836. /*++
  2837. Routine Description:
  2838. Build up data structures to speed up keyword lookup
  2839. Arguments:
  2840. pParserData - Points to parser data structure
  2841. Return Value:
  2842. TRUE if successful, FALSE if there is an error
  2843. --*/
  2844. {
  2845. DWORD iIndex, iCount;
  2846. //
  2847. // Allocate memory to hold extra data structures
  2848. //
  2849. iCount = NUM_BUILTIN_KEYWORDS;
  2850. pParserData->pdwKeywordHashs = ALLOC_PARSER_MEM(pParserData, iCount * sizeof(DWORD));
  2851. pParserData->pubKeywordCounts = ALLOC_PARSER_MEM(pParserData, iCount * sizeof(BYTE));
  2852. if (!pParserData->pdwKeywordHashs || !pParserData->pubKeywordCounts)
  2853. {
  2854. ERR(("Memory allocation failed: %d\n", GetLastError()));
  2855. return FALSE;
  2856. }
  2857. //
  2858. // Precompute the hash values for built-in keywords
  2859. //
  2860. for (iIndex = 0; iIndex < iCount; iIndex++)
  2861. {
  2862. pParserData->pdwKeywordHashs[iIndex] =
  2863. DwHashKeyword((PSTR) gPpdBuiltInKeywordTable[iIndex].pstrKeyword);
  2864. }
  2865. return TRUE;
  2866. }