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.

467 lines
22 KiB

  1. /*++
  2. Copyright (c) 1990-2003 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. MsNull.c
  6. Abstract:
  7. Implements lanman's msnull type parsing for FFs.
  8. Author:
  9. Environment:
  10. User Mode -Win32
  11. Revision History:
  12. --*/
  13. #include <windows.h>
  14. #include "winprint.h"
  15. #include "msnull.h"
  16. #define sgn(x) (((x)>0) ? 1:-1)
  17. struct EscapeSequence EscapeStrings[] =
  18. {
  19. { "-",prdg_ActConstIgnore, 1},
  20. { "0",prdg_ActNull,0},
  21. { "1",prdg_ActNull,0},
  22. { "2",prdg_ActNull,0},
  23. { "3",prdg_ActConstIgnore, 1},
  24. { "4",prdg_ActNull,0},
  25. { "5",prdg_ActConstIgnore, 1},
  26. { "6",prdg_ActNull,0},
  27. { "7",prdg_ActNull,0},
  28. { ":",prdg_ActNull,0},
  29. { "=",prdg_ActNull,0},
  30. { "A",prdg_ActConstIgnore, 1},
  31. { "B",prdg_ActDelimited, '\0'},
  32. { "C\0",prdg_ActConstIgnore, 1},
  33. { "D",prdg_ActDelimited, '\0'},
  34. { "E",prdg_ActReset,0},
  35. { "F",prdg_ActNull,0},
  36. { "G",prdg_ActNull,0},
  37. { "H",prdg_ActNull,0},
  38. { "I",prdg_ActConstIgnore, 1},
  39. { "J",prdg_ActConstIgnore, 1},
  40. { "K",prdg_ActCountIgnore, 0},
  41. { "L",prdg_ActCountIgnore, 0},
  42. { "N",prdg_ActConstIgnore, 1},
  43. { "O",prdg_ActNull,0},
  44. { "P",prdg_ActConstIgnore, 1},
  45. { "Q",prdg_ActConstIgnore, 1},
  46. { "R",prdg_ActNull,0},
  47. { "S",prdg_ActConstIgnore, 1},
  48. { "T",prdg_ActNull,0},
  49. { "U",prdg_ActConstIgnore, 1},
  50. { "W",prdg_ActConstIgnore, 1},
  51. { "X",prdg_ActConstIgnore, 2},
  52. { "Y",prdg_ActCountIgnore, 0},
  53. { "Z",prdg_ActCountIgnore, 0},
  54. { "[@",prdg_ActCountIgnore, 0},
  55. { "[C",prdg_ActCountIgnore, 0},
  56. { "[F",prdg_ActCountIgnore, 0},
  57. { "[I",prdg_ActCountIgnore, 0},
  58. { "[S",prdg_ActCountIgnore, 0},
  59. { "[T",prdg_ActCountIgnore, 0},
  60. { "[\\",prdg_ActCountIgnore, 0},
  61. { "[g",prdg_ActCountIgnore, 0},
  62. { "\\",prdg_ActCountIgnore, 0},
  63. { "]",prdg_ActNull,0},
  64. { "^",prdg_ActNull,0},
  65. { "_",prdg_ActConstIgnore, 1},
  66. { "d",prdg_ActConstIgnore, 2},
  67. { "e",prdg_ActConstIgnore, 2},
  68. { "j",prdg_ActNull,0},
  69. { "n",prdg_ActNull,0},
  70. { "\x6f", prdg_ActFF, 0}
  71. };
  72. VOID
  73. CheckFormFeedStream(
  74. lpDCI pDCIData,
  75. unsigned char inch)
  76. /**********************************************************************/
  77. /* */
  78. /* FUNCTION: prdg_ParseRawData */
  79. /* */
  80. /* PARAMETERS: */
  81. /* */
  82. /* lpDCI pDCIData; Pointer to DC instance data */
  83. /* unsigned char inch; The next byte in data stream */
  84. /* */
  85. /* DESCRIPTION: */
  86. /* */
  87. /* This function parses the stream of raw data which is being */
  88. /* passed to the printer so that the driver can handle form feeds */
  89. /* correctly. The function must follow all the escape sequences */
  90. /* which occur in the sequence of raw data. */
  91. /* */
  92. /* CHANGES: */
  93. /* */
  94. /* This function is table driven (from the table in in the ddata */
  95. /* module) so it should hopefully only require this to be changed */
  96. /* to reflect the escape sequences for a different printer. If */
  97. /* however there are escape sequneces which don't fall into the */
  98. /* categories this parser can handle then extra code will have */
  99. /* to be written to handle them. The parser can handle escape */
  100. /* sequences with any number of unique identifying characters */
  101. /* possibly followed by: a count then the number of charcters given */
  102. /* in the count; a fixed number of characters; a stream of */
  103. /* characters followed by a delimeter. */
  104. /* */
  105. /**********************************************************************/
  106. {
  107. /******************************************************************/
  108. /* Local Variables */
  109. /******************************************************************/
  110. INT Direction; /* Variables used in the */
  111. UINT HiIndex; /* binary chop routine for */
  112. UINT LoIndex; /* searching for a matching */
  113. UINT Index; /* escape sequence */
  114. UINT PrevIndex;
  115. char * optr; /* Pointers to access the */
  116. char * nptr; /* escape sequence strings */
  117. struct EscapeSequence *NewSequence; /* Pointer to an escape */
  118. /* sequence */
  119. /******************************************************************/
  120. /* Process the input character through the parsing function. */
  121. /* Switch depending on which state we are currently in. One of */
  122. /* prdg_Text, prdg_ESC_match, prdg_ESC_n_ignore, prdg_ESC_d_ignore*/
  123. /* prdg_ESC_read_lo_count, prdg_ESC_read_hi_count. */
  124. /******************************************************************/
  125. switch (pDCIData->ParserState)
  126. {
  127. case prdg_Text:
  128. /**********************************************************/
  129. /* Text state. Usual state, handled in line by a macro. */
  130. /* The code is included here for completeness only. */
  131. /* The FFaction (Form Feed action) state is maintained - */
  132. /* if the character is text (ie >= 0x20) then set it to */
  133. /* prdg_FFstate, if the character is a FF then set it to */
  134. /* prdg_FFx0c. If the input character is an escape then */
  135. /* start up the sequence matching mode. */
  136. /**********************************************************/
  137. if (inch >= 0x20)
  138. pDCIData->FFstate = prdg_FFtext;
  139. else if (inch == 0x0c)
  140. pDCIData->FFstate = prdg_FFx0c;
  141. else if (inch == 0x1b)
  142. {
  143. /******************************************************/
  144. /* The character is an escape so set ParserState and */
  145. /* indicate we have not matched a sequence yet by */
  146. /* setting ParserSequence to NULL. */
  147. /******************************************************/
  148. pDCIData->ParserState = prdg_ESC_match;
  149. pDCIData->ParserSequence = NULL;
  150. }
  151. break;
  152. case prdg_ESC_match:
  153. /**********************************************************/
  154. /* Matching an escape sequence so try to match a new */
  155. /* character. */
  156. /**********************************************************/
  157. if (!pDCIData->ParserSequence)
  158. {
  159. /******************************************************/
  160. /* ParserSequence is NULL indicating that this is the */
  161. /* first character of an escape sequence so use a */
  162. /* binary chop to get to the correct area of the */
  163. /* table of escape sequences (based on the first */
  164. /* character of the escape sequence which is the */
  165. /* cuurent input character). */
  166. /******************************************************/
  167. HiIndex = MaxEscapeStrings;
  168. LoIndex = 0;
  169. Index = (LoIndex + HiIndex)/2;
  170. PrevIndex = MaxEscapeStrings;
  171. /******************************************************/
  172. /* while inch does not match the first character of */
  173. /* the sequence indicated by Index move up or down */
  174. /* the table depending on whether inch is < or > the */
  175. /* first character of the escape sequence at Index. */
  176. /******************************************************/
  177. while (Direction =
  178. (inch - *EscapeStrings[Index].ESCString))
  179. {
  180. if (Direction > 0)
  181. {
  182. LoIndex = Index;
  183. }
  184. else
  185. {
  186. HiIndex = Index;
  187. };
  188. PrevIndex = Index;
  189. if (PrevIndex == (Index = (LoIndex + HiIndex)/2))
  190. {
  191. /**********************************************/
  192. /* There is no escape sequence with a first */
  193. /* character matching the current input */
  194. /* character so resume text mode. */
  195. /**********************************************/
  196. pDCIData->ParserState = prdg_Text;
  197. return;
  198. }
  199. }
  200. /*.. while (Direction = ...no match yet...............*/
  201. /******************************************************/
  202. /* Set up the ParserSequence and ParserString for the */
  203. /* first match found. */
  204. /******************************************************/
  205. pDCIData->ParserSequence = &EscapeStrings[Index];
  206. pDCIData->ParserString = EscapeStrings[Index].ESCString;
  207. };
  208. /*.. if (!pDCIData->ParserSequence) .......................*/
  209. /**********************************************************/
  210. /* Loop forever trying to match escape sequences. */
  211. /* First, try the new character against the current */
  212. /* escape sequence and if it matches then check if it is */
  213. /* the end of the sequence and if it is switch to the */
  214. /* appropriate matching mode. If the new character does */
  215. /* not match try the next escape sequence (in either */
  216. /* ascending or descending order depending on whether the */
  217. /* current character was < or > the character we were */
  218. /* trying to match it to). If the new sequence we are */
  219. /* trying to match against does not exist (ie we are at */
  220. /* one end of the table) or it does not match upto (but */
  221. /* not including) the position we are currently at then */
  222. /* the escape sequence in the raw data we are trying to */
  223. /* match is invalid so revert to prdg_Text mode. If it */
  224. /* does match upto (but not including) the position we */
  225. /* are currently trying to match then go back to try and */
  226. /* match. */
  227. /**********************************************************/
  228. for (Direction = sgn(inch - *pDCIData->ParserString);;)
  229. {
  230. /******************************************************/
  231. /* Partway along a sequence, try the new character and*/
  232. /* if it matches then check for end of string. */
  233. /******************************************************/
  234. if (!(inch - *pDCIData->ParserString))
  235. {
  236. if (*++pDCIData->ParserString != '\0')
  237. /**********************************************/
  238. /* Escape sequence not finished yet so return */
  239. /* and wait for the next character. Note that*/
  240. /* this is where the pointer to the position */
  241. /* in the escape sequence we are checking is */
  242. /* updated. */
  243. /**********************************************/
  244. return;
  245. else
  246. /**********************************************/
  247. /* The escape sequence has matched till the */
  248. /* end so break to the next section which will*/
  249. /* take the appropriate action. */
  250. /**********************************************/
  251. break;
  252. }
  253. /*.. if (!(inch - *pDCIData->ParserString)) ...match...*/
  254. else
  255. {
  256. /**************************************************/
  257. /* The current sequence does not match so we must */
  258. /* try another sequence. Direction determines */
  259. /* which way in the table we should go. */
  260. /**************************************************/
  261. NewSequence = pDCIData->ParserSequence + Direction;
  262. if (NewSequence < EscapeStrings ||
  263. NewSequence> &EscapeStrings[MaxEscapeStrings-1])
  264. {
  265. /**********************************************/
  266. /* The new sequence is beyond one end of the */
  267. /* table so revert to prdg_Text mode because */
  268. /* we will not be able to find a match. */
  269. /**********************************************/
  270. pDCIData->ParserState = prdg_Text;
  271. return;
  272. }
  273. /**************************************************/
  274. /* Check that all the characters in the new */
  275. /* escape sequence upto (but not including) the */
  276. /* current one match the old escape sequence */
  277. /* (because those characters from the old escape */
  278. /* sequence have already been matched to the */
  279. /* raw data). */
  280. /**************************************************/
  281. for (optr=pDCIData->ParserSequence->ESCString,
  282. nptr=NewSequence->ESCString;
  283. optr<pDCIData->ParserString; ++optr,++nptr)
  284. if (*nptr != *optr)
  285. {
  286. /*****************************************/
  287. /* If the new sequence does not match the*/
  288. /* old then a match is not possible so */
  289. /* return. */
  290. /*****************************************/
  291. pDCIData->ParserState = prdg_Text;
  292. return;
  293. }
  294. /**************************************************/
  295. /* The new sequence is correct upto the character */
  296. /* before the current character so loop back and */
  297. /* check the current character. */
  298. /**************************************************/
  299. pDCIData->ParserSequence = NewSequence;
  300. pDCIData->ParserString = nptr;
  301. }
  302. /*.. else ! (!(inch - *pDCIData->ParserString.no match.*/
  303. }
  304. /*.. for ( ... ;;) ....for ever...........................*/
  305. /**********************************************************/
  306. /* The escape sequence has been matched from our table of */
  307. /* escape sequences so take the appropriate action for */
  308. /* the particular sequence. */
  309. /**********************************************************/
  310. switch (pDCIData->ParserSequence->ESCAction)
  311. {
  312. case prdg_ActNull:
  313. /**************************************************/
  314. /* No further action so revert to prdg_Text mode */
  315. /**************************************************/
  316. pDCIData->ParserState = prdg_Text;
  317. break;
  318. case prdg_ActDelimited:
  319. /**************************************************/
  320. /* Ignore subsequent characters upto a specified */
  321. /* delimeter. */
  322. /**************************************************/
  323. pDCIData->ParserState = prdg_ESC_d_ignore;
  324. pDCIData->ParserDelimiter =
  325. (char)pDCIData->ParserSequence->ESCValue;
  326. break;
  327. case prdg_ActConstIgnore:
  328. /**************************************************/
  329. /* Ignore a specified number of characters. */
  330. /**************************************************/
  331. pDCIData->ParserState = prdg_ESC_n_ignore;
  332. pDCIData->ParserCount =
  333. pDCIData->ParserSequence->ESCValue;
  334. break;
  335. case prdg_ActCountIgnore:
  336. /**************************************************/
  337. /* A two byte count follows so prepare to read it */
  338. /* in. */
  339. /**************************************************/
  340. pDCIData->ParserState = prdg_ESC_read_lo_count;
  341. break;
  342. case prdg_ActFF:
  343. /**************************************************/
  344. /* A special action for recognising the 0x1b6f */
  345. /* "No Formfeed" sequence */
  346. /**************************************************/
  347. pDCIData->ParserState = prdg_Text;
  348. pDCIData->FFstate = prdg_FFx1b6f;
  349. break;
  350. case prdg_ActReset:
  351. /**************************************************/
  352. /* On Esc-E (reset) don't eject a page if this is */
  353. /* the last sequence in the stream. */
  354. /**************************************************/
  355. pDCIData->ParserState = prdg_Text;
  356. pDCIData->FFstate = prdg_FFx1b45;
  357. break;
  358. }
  359. /*.. switch (pDCIData->ParserSequence->ESCAction) .........*/
  360. break;
  361. case prdg_ESC_n_ignore:
  362. /**********************************************************/
  363. /* Ignoring n characters. Decrement the count, move back */
  364. /* to text state if all ignored. */
  365. /**********************************************************/
  366. if (!(--pDCIData->ParserCount))
  367. pDCIData->ParserState = prdg_Text;
  368. break;
  369. case prdg_ESC_d_ignore:
  370. /**********************************************************/
  371. /* Ignoring up to a delimiter. If this is it, then stop */
  372. /* ignoring. */
  373. /**********************************************************/
  374. if (inch == pDCIData->ParserDelimiter)
  375. pDCIData->ParserState = prdg_Text;
  376. break;
  377. case prdg_ESC_read_lo_count:
  378. /**********************************************************/
  379. /* Reading first byte of count. Save it, advance state. */
  380. /**********************************************************/
  381. pDCIData->ParserCount = (UINT)inch;
  382. pDCIData->ParserState = prdg_ESC_read_hi_count;
  383. break;
  384. case prdg_ESC_read_hi_count:
  385. /**********************************************************/
  386. /* Reading second byte of count. Save it, move to ignore */
  387. /* a specified number of characters if there are any. */
  388. /**********************************************************/
  389. pDCIData->ParserCount += 256*(UINT)inch;
  390. if (pDCIData->ParserCount)
  391. pDCIData->ParserState = prdg_ESC_n_ignore;
  392. else
  393. pDCIData->ParserState = prdg_Text;
  394. break;
  395. };
  396. /*.. switch (pDCIData->ParserState) ...............................*/
  397. return;
  398. }
  399. BOOL
  400. CheckFormFeed(
  401. lpDCI pDCIData)
  402. {
  403. if (pDCIData->FFstate != prdg_FFx1b6f &&
  404. pDCIData->FFstate != prdg_FFx1b45) {
  405. if (pDCIData->uType == PRINTPROCESSOR_TYPE_RAW_FF ||
  406. (pDCIData->uType == PRINTPROCESSOR_TYPE_RAW_FF_AUTO &&
  407. pDCIData->FFstate == prdg_FFtext)) {
  408. return TRUE;
  409. }
  410. }
  411. return FALSE;
  412. }