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.

602 lines
13 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. ppdentry.c
  5. Abstract:
  6. Functions for parsing syntactical elements of a PPD file
  7. Environment:
  8. PostScript driver, PPD parser
  9. Revision History:
  10. 08/20/96 -davidx-
  11. Common coding style for NT 5.0 drivers.
  12. 03/26/96 -davidx-
  13. Created it.
  14. --*/
  15. #include "lib.h"
  16. #include "ppd.h"
  17. #include "ppdparse.h"
  18. //
  19. // Forward declaration of local functions
  20. //
  21. PPDERROR IParseKeyword(PPARSERDATA);
  22. PPDERROR IParseValue(PPARSERDATA);
  23. PPDERROR IParseField(PFILEOBJ, PBUFOBJ, BYTE);
  24. PPDERROR
  25. IParseEntry(
  26. PPARSERDATA pParserData
  27. )
  28. /*++
  29. Routine Description:
  30. Parse one entry from a PPD file
  31. Arguments:
  32. pParserData - Points to parser data structure
  33. Return Value:
  34. Status code
  35. --*/
  36. {
  37. PPDERROR iStatus;
  38. INT iChar;
  39. PFILEOBJ pFile = pParserData->pFile;
  40. //
  41. // Clear values from previous entry
  42. //
  43. CLEAR_BUFFER(&pParserData->Keyword);
  44. CLEAR_BUFFER(&pParserData->Option);
  45. CLEAR_BUFFER(&pParserData->Xlation);
  46. CLEAR_BUFFER(&pParserData->Value);
  47. pParserData->dwValueType = VALUETYPE_NONE;
  48. //
  49. // Parse the keyword field and skip over trailing white spaces
  50. //
  51. if ((iStatus = IParseKeyword(pParserData)) != PPDERR_NONE)
  52. return iStatus;
  53. //
  54. // Look at the first non-space character after the keyword field
  55. //
  56. VSkipSpace(pFile);
  57. if ((iChar = IGetNextChar(pFile)) == EOF_CHAR)
  58. return PPDERR_EOF;
  59. if (IS_NEWLINE(iChar))
  60. return PPDERR_NONE;
  61. if (iChar != SEPARATOR_CHAR)
  62. {
  63. //
  64. // Parse the option field and skip over trailing white spaces
  65. //
  66. ASSERT(iChar != EOF_CHAR);
  67. VUngetChar(pFile);
  68. if ((iStatus = IParseField(pFile, &pParserData->Option, KEYWORD_MASK)) != PPDERR_NONE)
  69. return iStatus;
  70. VSkipSpace(pFile);
  71. //
  72. // Look at the first non-space character after the option field
  73. //
  74. if ((iChar = IGetNextChar(pFile)) == XLATION_CHAR)
  75. {
  76. //
  77. // Parse the translation string field
  78. //
  79. if ((iStatus = IParseField(pFile, &pParserData->Xlation, XLATION_MASK)) != PPDERR_NONE)
  80. return iStatus;
  81. iChar = IGetNextChar(pFile);
  82. }
  83. if (iChar != SEPARATOR_CHAR)
  84. return ISyntaxError(pFile, "Missing ':'");
  85. }
  86. //
  87. // Parse the value field and interpret the entry if it's valid
  88. //
  89. if ((iStatus = IParseValue(pParserData)) == PPDERR_NONE)
  90. {
  91. //
  92. // Take care of any embedded hexdecimals in the translation string
  93. //
  94. if (! IS_BUFFER_EMPTY(&pParserData->Xlation) &&
  95. ! BConvertHexString(&pParserData->Xlation))
  96. {
  97. return ISyntaxError(pFile, "Invalid hexdecimals in the translation string");
  98. }
  99. //
  100. // Interpret the current entry
  101. //
  102. iStatus = IInterpretEntry(pParserData);
  103. }
  104. return iStatus;
  105. }
  106. PPDERROR
  107. IParseKeyword(
  108. PPARSERDATA pParserData
  109. )
  110. /*++
  111. Routine Description:
  112. Parse the keyword field of a PPD file entry
  113. Arguments:
  114. pParserData - Points to parser data structure
  115. Return Value:
  116. Status code
  117. --*/
  118. {
  119. PFILEOBJ pFile = pParserData->pFile;
  120. INT iChar;
  121. while (TRUE)
  122. {
  123. //
  124. // Get the first character of a line
  125. //
  126. if ((iChar = IGetNextChar(pFile)) == EOF_CHAR)
  127. return PPDERR_EOF;
  128. //
  129. // Ignore empty lines
  130. //
  131. if (IS_NEWLINE(iChar))
  132. continue;
  133. if (IS_SPACE(iChar))
  134. {
  135. VSkipSpace(pFile);
  136. if ((iChar = IGetNextChar(pFile)) == EOF_CHAR)
  137. return PPDERR_EOF;
  138. if (IS_NEWLINE(iChar))
  139. continue;
  140. return ISyntaxError(pFile, "Missing '*'");
  141. }
  142. //
  143. // If the line is not empty, the first character must be the keyword character
  144. //
  145. if (! IS_KEYWORD_CHAR(iChar))
  146. return ISyntaxError(pFile, "Missing '*'");
  147. //
  148. // If the second character is not %, then the line is a normal entry.
  149. // Otherwise, the line is a comment.
  150. //
  151. if ((iChar = IGetNextChar(pFile)) == EOF_CHAR)
  152. return PPDERR_EOF;
  153. if (!IS_NEWLINE(iChar) && iChar != COMMENT_CHAR)
  154. {
  155. VUngetChar(pFile);
  156. break;
  157. }
  158. VSkipLine(pFile);
  159. }
  160. return IParseField(pFile, &pParserData->Keyword, KEYWORD_MASK);
  161. }
  162. PPDERROR
  163. IParseValue(
  164. PPARSERDATA pParserData
  165. )
  166. /*++
  167. Routine Description:
  168. Parse the value field of a PPD file entry
  169. Arguments:
  170. pParserData - Points to parser data structure
  171. Return Value:
  172. Status code
  173. --*/
  174. {
  175. PPDERROR iStatus;
  176. INT iChar;
  177. PBUFOBJ pBufObj = &pParserData->Value;
  178. PFILEOBJ pFile = pParserData->pFile;
  179. //
  180. // The value is either a StringValue, a SymbolValue, or a QuotedValue
  181. // depending on the first non-space character
  182. //
  183. VSkipSpace(pFile);
  184. if ((iChar = IGetNextChar(pFile)) == EOF_CHAR)
  185. return PPDERR_EOF;
  186. if (iChar == QUOTE_CHAR)
  187. {
  188. //
  189. // The value is a quoted string
  190. //
  191. pParserData->dwValueType = VALUETYPE_QUOTED;
  192. if ((iStatus = IParseField(pFile, pBufObj, QUOTED_MASK)) != PPDERR_NONE)
  193. return iStatus;
  194. //
  195. // Read the closing quote character
  196. //
  197. if ((iChar = IGetNextChar(pFile)) != QUOTE_CHAR)
  198. return ISyntaxError(pFile, "Unbalanced '\"'");
  199. }
  200. else if (iChar == SYMBOL_CHAR)
  201. {
  202. //
  203. // The value is a symbol reference
  204. //
  205. pParserData->dwValueType = VALUETYPE_SYMBOL;
  206. ADD_CHAR_TO_BUFFER(pBufObj, iChar);
  207. if ((iStatus = IParseField(pFile, pBufObj, KEYWORD_MASK)) != PPDERR_NONE)
  208. return iStatus;
  209. }
  210. else
  211. {
  212. PBYTE pubEnd;
  213. //
  214. // The value is a string
  215. //
  216. pParserData->dwValueType = VALUETYPE_STRING;
  217. VUngetChar(pFile);
  218. if ((iStatus = IParseField(pFile, pBufObj, STRING_MASK)) != PPDERR_NONE)
  219. return iStatus;
  220. //
  221. // Ignore any trailing spaces
  222. //
  223. ASSERT(pBufObj->dwSize > 0);
  224. pubEnd = pBufObj->pbuf + (pBufObj->dwSize - 1);
  225. while (IS_SPACE(*pubEnd))
  226. *pubEnd-- = NUL;
  227. pBufObj->dwSize= (DWORD)(pubEnd - pBufObj->pbuf) + 1;
  228. ASSERT(pBufObj->dwSize > 0);
  229. }
  230. //
  231. // Ignore extra characters after the entry value
  232. //
  233. VSkipSpace(pFile);
  234. iChar = IGetNextChar(pFile);
  235. if (! IS_NEWLINE(iChar))
  236. {
  237. if (iChar != XLATION_CHAR)
  238. {
  239. TERSE(("%ws: Extra chars at the end of line %d\n",
  240. pFile->ptstrFileName,
  241. pFile->iLineNumber));
  242. }
  243. VSkipLine(pFile);
  244. }
  245. return PPDERR_NONE;
  246. }
  247. PPDERROR
  248. IParseField(
  249. PFILEOBJ pFile,
  250. PBUFOBJ pBufObj,
  251. BYTE ubMask
  252. )
  253. /*++
  254. Routine Description:
  255. Parse one field of a PPD file entry
  256. Arguments:
  257. pFile - Specifies the input file object
  258. pBufObj - Specifies the buffer for storing the field value
  259. ubMask - Mask to limit the set of allowable characters
  260. Return Value:
  261. Status code
  262. --*/
  263. {
  264. PPDERROR iStatus;
  265. INT iChar;
  266. while ((iChar = IGetNextChar(pFile)) != EOF_CHAR)
  267. {
  268. if (! IS_MASKED_CHAR(iChar, ubMask))
  269. {
  270. //
  271. // Encountered a not-allowed character
  272. //
  273. if (IS_BUFFER_EMPTY(pBufObj) && !(ubMask & QUOTED_MASK))
  274. return ISyntaxError(pFile, "Empty field");
  275. //
  276. // Always put a null byte at the end
  277. //
  278. pBufObj->pbuf[pBufObj->dwSize] = 0;
  279. VUngetChar(pFile);
  280. return PPDERR_NONE;
  281. }
  282. else
  283. {
  284. //
  285. // If we're parsing a quoted string and we encountered a line
  286. // starting with the keyword character, then we'll assume
  287. // the closing quote is missing. Just give a warning and continue.
  288. //
  289. if ((ubMask & QUOTED_MASK) &&
  290. IS_KEYWORD_CHAR(iChar) &&
  291. !IS_BUFFER_EMPTY(pBufObj) &&
  292. IS_NEWLINE(pBufObj->pbuf[pBufObj->dwSize - 1]))
  293. {
  294. (VOID) ISyntaxError(pFile, "Expecting '\"'");
  295. }
  296. //
  297. // Grow the buffer if it's full. If we're not allowed to
  298. // grow it, then return a syntax error.
  299. //
  300. if (IS_BUFFER_FULL(pBufObj))
  301. {
  302. if (ubMask & (STRING_MASK|QUOTED_MASK))
  303. {
  304. if ((iStatus = IGrowValueBuffer(pBufObj)) != PPDERR_NONE)
  305. return iStatus;
  306. }
  307. else
  308. {
  309. return ISyntaxError(pFile, "Field too long");
  310. }
  311. }
  312. ADD_CHAR_TO_BUFFER(pBufObj, iChar);
  313. }
  314. }
  315. return PPDERR_EOF;
  316. }
  317. BOOL
  318. BConvertHexString(
  319. PBUFOBJ pBufObj
  320. )
  321. /*++
  322. Routine Description:
  323. Convert embedded hexdecimal strings into binary data
  324. Arguments:
  325. pBufObj - Specifies the buffer object to be converted
  326. Return Value:
  327. TRUE if everything is ok
  328. FALSE if the embedded hexdecimal string is ill-formed
  329. --*/
  330. #define HexDigitValue(c) \
  331. (((c) >= '0' && (c) <= '9') ? ((c) - '0') : \
  332. ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) : ((c) - 'a' + 10))
  333. {
  334. PBYTE pubSrc, pubDest;
  335. DWORD dwSize;
  336. DWORD dwHexMode = 0;
  337. pubSrc = pubDest = pBufObj->pbuf;
  338. dwSize = pBufObj->dwSize;
  339. while (dwSize--)
  340. {
  341. if (dwHexMode)
  342. {
  343. //
  344. // We're currently inside a hex string:
  345. // switch to normal mode if '>' is encountered
  346. // otherwise, only valid hex digits, newline, and spaces are allowed
  347. //
  348. if (IS_HEX_DIGIT(*pubSrc))
  349. {
  350. //
  351. // If we're currently on odd hex digit, save the hex digit value
  352. // in the upper nibble of the destination byte.
  353. // If we're on even hex digit, save the hex digit value in the
  354. // lower nibble of the destination byte. If the destination byte
  355. // is zero and NUL is not allowed, then return with error.
  356. //
  357. if (dwHexMode & 1)
  358. *pubDest = HexDigitValue(*pubSrc) << 4;
  359. else
  360. *pubDest++ |= HexDigitValue(*pubSrc);
  361. dwHexMode++;
  362. }
  363. else if (*pubSrc == '>')
  364. {
  365. if ((dwHexMode & 1) == 0)
  366. {
  367. TERSE(("Odd number of hexdecimal digits\n"));
  368. return FALSE;
  369. }
  370. dwHexMode = 0;
  371. }
  372. else if (!IS_SPACE(*pubSrc) && !IS_NEWLINE(*pubSrc))
  373. {
  374. TERSE(("Invalid hexdecimal digit\n"));
  375. return FALSE;
  376. }
  377. }
  378. else
  379. {
  380. //
  381. // We're not currently inside a hex string:
  382. // switch to hex mode if '<' is encountered
  383. // otherwise, simply copy the source byte to the destination
  384. //
  385. if (*pubSrc == '<')
  386. dwHexMode = 1;
  387. else
  388. *pubDest++ = *pubSrc;
  389. }
  390. pubSrc++;
  391. }
  392. if (dwHexMode)
  393. {
  394. TERSE(("Missing '>' in hexdecimal string\n"));
  395. return FALSE;
  396. }
  397. //
  398. // Modified the buffer size if it's changed
  399. //
  400. *pubDest = 0;
  401. pBufObj->dwSize = (DWORD)(pubDest - pBufObj->pbuf);
  402. return TRUE;
  403. }
  404. PPDERROR
  405. ISyntaxErrorMessage(
  406. PFILEOBJ pFile,
  407. PSTR pstrMsg
  408. )
  409. /*++
  410. Routine Description:
  411. Display syntax error message
  412. Arguments:
  413. pFile - Specifies the input file object
  414. pstrMsg - Indicate the reason for the syntax error
  415. Return Value:
  416. PPDERR_SYNTAX
  417. --*/
  418. {
  419. //
  420. // Display an error message
  421. //
  422. TERSE(("%ws: %s on line %d\n", pFile->ptstrFileName, pstrMsg, pFile->iLineNumber));
  423. //
  424. // Skip any remaining characters on the current line
  425. //
  426. VSkipLine(pFile);
  427. return PPDERR_SYNTAX;
  428. }