Source code of Windows XP (NT5)
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.

888 lines
25 KiB

  1. /********************************************************************/
  2. /** Microsoft NT printing - separator pages **/
  3. /********************************************************************/
  4. #include <precomp.h>
  5. #pragma hdrstop
  6. #define _CTYPE_DISABLE_MACROS
  7. #include <wingdip.h>
  8. #include <winbasep.h>
  9. /* this is max. no. of chars to be printed on a line */
  10. /* these numbers must be taken from somewhere else */
  11. #define MAXLINE 256
  12. #define DEFAULT_LINE_WIDTH 80
  13. #define BLOCK_CHAR_HEIGHT 16
  14. #define BLOCK_CHAR_WIDTH 8
  15. #define BLOCK_CHAR_DWIDTH 16
  16. #define NORMAL_MODE 'U'
  17. #define BLOCK_START 'B'
  18. #define SINGLE_WIDTH 'S'
  19. #define DOUBLE_WIDTH 'M'
  20. #define TEXT_MODE 'L'
  21. #define WIDTH_CHANGE 'W'
  22. #define END_PAGE 'E'
  23. #define FILE_INSERT 'F'
  24. #define USER_NAME 'N'
  25. #define JOB_ID 'I'
  26. #define DATE_INSERT 'D'
  27. #define TIME_INSERT 'T'
  28. #define HEX_CODE 'H'
  29. /* global structure (instance data) */
  30. typedef struct {
  31. PSPOOL pSpool;
  32. HANDLE hFile;
  33. HANDLE hFileMapping;
  34. DWORD dwFileCount;
  35. DWORD dwFileSizeLo;
  36. DWORD cbOutBufLength;
  37. DWORD cbLineLength;
  38. DWORD linewidth;
  39. char *OutBuf;
  40. char *pOutBufPos;
  41. char *pNextFileChar;
  42. char *pFileStart;
  43. char mode;
  44. char cEsc;
  45. char cLastChar; // Used to store DBCS lead byte.
  46. HDC hDCMem; // Used to create Kanji banner char.
  47. HFONT hFont; // Used to create Kanji banner char.
  48. HBITMAP hBitmap; // Used to create Kanji banner char.
  49. PVOID pvBits; // Used to create Kanji nanner char.
  50. } GLOBAL_SEP_DATA;
  51. /* static variables */
  52. static char *szDefaultSep = "@@B@S@N@4 @B@S@I@4 @U@L @D@1 @E";
  53. static char *sznewline = "\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n";
  54. static LPWSTR szDefaultSepName = L"DEFAULT.SEP";
  55. /* Forward declarations */
  56. int OpenSepFile(GLOBAL_SEP_DATA *, LPWSTR);
  57. int CloseSepFile(GLOBAL_SEP_DATA *);
  58. int ReadSepChar(GLOBAL_SEP_DATA *);
  59. void UngetSepChar(GLOBAL_SEP_DATA *, int);
  60. int WriteSepBuf(GLOBAL_SEP_DATA *, char *, DWORD);
  61. int DoSeparatorPage(GLOBAL_SEP_DATA *);
  62. int AddNormalChar(GLOBAL_SEP_DATA *, int);
  63. int AddBlockChar(GLOBAL_SEP_DATA *, int);
  64. int FlushOutBuf(GLOBAL_SEP_DATA *);
  65. int FlushNewLine(GLOBAL_SEP_DATA *);
  66. void ReadFileName(GLOBAL_SEP_DATA *, char *, DWORD);
  67. int ConvertAtoH(int);
  68. void ConvertTimetoChar(LPSYSTEMTIME,char *);
  69. void ConvertDatetoChar(LPSYSTEMTIME,char *);
  70. /**************************************************************\
  71. ** DoSeparator(pSpool)
  72. ** This function is called by the spooler. It is the
  73. ** entry point for the separator page code. It opens the
  74. ** separator page file, processes it, sends the output
  75. ** directly to the printer, and then returns control
  76. ** to the spooler.
  77. **
  78. ** RETURN VALUE: 1 = OK, 0 = error
  79. \**************************************************************/
  80. int DoSeparator(
  81. PSPOOL pSpool
  82. )
  83. {
  84. GLOBAL_SEP_DATA g;
  85. int status;
  86. g.pSpool = pSpool;
  87. if (!OpenSepFile(&g, pSpool->pIniJob->pIniPrinter->pSepFile)) {
  88. return(0);
  89. }
  90. //
  91. // We used to call OpenProfileUserMapping() and CloseProfileUserMapping()
  92. // before and after DoSeparatorPage. But they are not multi thread safe
  93. // and are not needed now that we use SystemTimeToTzSpecificLocalTime
  94. // instead of GetProfileInt etc..
  95. //
  96. status = DoSeparatorPage(&g);
  97. CloseSepFile(&g);
  98. if (!status) {
  99. return(0);
  100. }
  101. return(1);
  102. }
  103. /**************************************************************\
  104. ** OpenSepFile(pg, szFileName)
  105. ** open file for input.
  106. ** at the moment, this does nothing--stdin and stdout are used
  107. \**************************************************************/
  108. int OpenSepFile(
  109. GLOBAL_SEP_DATA *pg,
  110. LPWSTR szFileName
  111. )
  112. {
  113. if (!lstrcmpi(szFileName, szDefaultSepName)) {
  114. /* if szFileName is empty, just use default separator page string */
  115. pg->hFile = NULL;
  116. pg->hFileMapping = NULL;
  117. pg->pFileStart = pg->pNextFileChar = szDefaultSep;
  118. pg->dwFileSizeLo = strlen(szDefaultSep);
  119. }
  120. else {
  121. HANDLE hImpersonationToken = RevertToPrinterSelf();
  122. /* otherwise, open the file */
  123. pg->hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ,
  124. NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  125. ImpersonatePrinterClient(hImpersonationToken);
  126. if (pg->hFile==INVALID_HANDLE_VALUE) {
  127. return(0);
  128. }
  129. pg->dwFileSizeLo = GetFileSize(pg->hFile, NULL); /* assume < 4 GB! */
  130. pg->hFileMapping = CreateFileMapping(pg->hFile, NULL,
  131. PAGE_READONLY, 0, 0, NULL);
  132. if (!pg->hFileMapping || pg->dwFileSizeLo==-1) {
  133. CloseSepFile(pg);
  134. return(0);
  135. }
  136. pg->pFileStart =
  137. pg->pNextFileChar = (char *)
  138. MapViewOfFile(pg->hFileMapping, FILE_MAP_READ,
  139. 0, 0, pg->dwFileSizeLo);
  140. if (!pg->pFileStart) {
  141. CloseSepFile(pg);
  142. return(0);
  143. }
  144. } /* end of else (szFileName non-NULL) */
  145. pg->dwFileCount = 0;
  146. /* now, allocate local buffer for output */
  147. pg->OutBuf = (char *)AllocSplMem( BLOCK_CHAR_HEIGHT*(MAXLINE+2) );
  148. if (!pg->OutBuf) {
  149. CloseSepFile(pg);
  150. return(0);
  151. }
  152. return(1);
  153. }
  154. /**************************************************************\
  155. ** CloseSepFile(pg)
  156. ** close files.
  157. \**************************************************************/
  158. int CloseSepFile(GLOBAL_SEP_DATA *pg)
  159. {
  160. if (pg->OutBuf) {
  161. FreeSplMem(pg->OutBuf);
  162. }
  163. if (pg->hFileMapping) {
  164. if (pg->pFileStart) {
  165. UnmapViewOfFile(pg->pFileStart);
  166. }
  167. CloseHandle(pg->hFileMapping);
  168. }
  169. if (pg->hFile) {
  170. CloseHandle(pg->hFile);
  171. }
  172. return(1);
  173. }
  174. /**************************************************************\
  175. ** ReadSepChar(pg)
  176. ** reads a character from the separator file and returns it
  177. \**************************************************************/
  178. int ReadSepChar(GLOBAL_SEP_DATA *pg)
  179. {
  180. if (pg->dwFileCount >= pg->dwFileSizeLo) {
  181. return(EOF);
  182. }
  183. pg->dwFileCount++;
  184. return(*pg->pNextFileChar++);
  185. }
  186. /**************************************************************\
  187. ** UngetSepChar(pg, c)
  188. ** ungets a character to the separator file
  189. \**************************************************************/
  190. void UngetSepChar(
  191. GLOBAL_SEP_DATA *pg,
  192. int c
  193. )
  194. {
  195. if (c != EOF && pg->dwFileCount) {
  196. pg->dwFileCount--;
  197. pg->pNextFileChar--;
  198. }
  199. }
  200. /**************************************************************\
  201. ** WriteSepBuf(pg, str, cb)
  202. ** write cb bytes of a string to the printer
  203. \**************************************************************/
  204. int WriteSepBuf(
  205. GLOBAL_SEP_DATA *pg,
  206. char *str,
  207. DWORD cb
  208. )
  209. {
  210. DWORD cbWritten;
  211. return(LocalWritePrinter(pg->pSpool, str, cb, &cbWritten)
  212. && (cbWritten==cb)
  213. );
  214. #ifdef ALIP
  215. if (str[cb]) {
  216. char temp[3000];
  217. strncpy(temp, str, cb);
  218. temp[cb]=0;
  219. return(!fputs(temp,stdout));
  220. }
  221. return(!fputs(str,stdout));
  222. #endif
  223. }
  224. /**************************************************************\
  225. ** FlushOutBuf(pg)
  226. ** flush the output buffer (block or line mode)
  227. ** WHAT'S TRICKY HERE IS THAT IF WE'RE IN LINE MODE, WE SIMPLY
  228. ** WRITE THE STUFF TO THE FILE, WHEREAS IF WE'RE IN BLOCK
  229. ** CHARACTER MODE, WE FORCE CARRIAGE-RETURN / LINEFEEDS ON
  230. ** EACH OF THE EIGHT BUFFERED LINES THAT MAKE UP THE BLOCK
  231. ** CHARACTERS; i.e., FlushOutBuf() SERVES AS AN EOL IN BLOCK
  232. ** MODE, BUT NOT IN LINE MODE.
  233. **
  234. ** - return TRUE means ok
  235. ** - return FALSE means problem
  236. \**************************************************************/
  237. int FlushOutBuf(GLOBAL_SEP_DATA *pg)
  238. {
  239. int i,status = TRUE;
  240. char *pBlkLine;
  241. if (!pg->cbOutBufLength) {
  242. return(TRUE);
  243. }
  244. if (pg->mode == NORMAL_MODE) {
  245. /* write out entire buffer at once */
  246. status = WriteSepBuf(pg, pg->OutBuf, pg->cbOutBufLength);
  247. }
  248. else {
  249. /* BLOCK MODE:
  250. * force carriage-return and linefeed on all eight lines
  251. */
  252. pBlkLine = pg->OutBuf;
  253. for (i=0; (i < BLOCK_CHAR_HEIGHT) && status; i++) {
  254. *pg->pOutBufPos = '\r';
  255. *(pg->pOutBufPos+1) = '\n';
  256. status = WriteSepBuf(pg, pBlkLine, pg->cbLineLength+2);
  257. pg->pOutBufPos += MAXLINE+2;
  258. pBlkLine += MAXLINE+2;
  259. }
  260. pg->cbLineLength = 0;
  261. }
  262. pg->pOutBufPos = pg->OutBuf;
  263. pg->cbOutBufLength = 0;
  264. return(status);
  265. }
  266. /**************************************************************\
  267. ** FlushNewLine(pg)
  268. ** Starts a new line: if BLOCK MODE, just do FlushOutBuf();
  269. ** if not, send a '\r' '\n' combination, then flush.
  270. ** - return TRUE means ok
  271. ** - return FALSE means problem
  272. \**************************************************************/
  273. int FlushNewLine(GLOBAL_SEP_DATA *pg)
  274. {
  275. if (pg->mode==NORMAL_MODE && pg->cbLineLength) {
  276. if (!AddNormalChar(pg,'\r')) return(FALSE);
  277. if (!AddNormalChar(pg,'\n')) return(FALSE);
  278. }
  279. return(FlushOutBuf(pg));
  280. }
  281. /**************************************************************\
  282. ** AddNormalChar(pg, c)
  283. ** add a character to the output buffer (not block mode)
  284. ** - return TRUE means ok
  285. ** - return FALSE means problem
  286. \**************************************************************/
  287. int AddNormalChar(
  288. GLOBAL_SEP_DATA *pg,
  289. int c
  290. )
  291. {
  292. if (c=='\n') {
  293. /* reset line length count */
  294. pg->cbLineLength = 0;
  295. }
  296. else {
  297. if (isprint(c) && (++(pg->cbLineLength) > pg->linewidth)) {
  298. return(TRUE);
  299. }
  300. }
  301. *pg->pOutBufPos++ = (CHAR) c;
  302. if (++(pg->cbOutBufLength) == BLOCK_CHAR_HEIGHT*(MAXLINE+2)) {
  303. return(FlushOutBuf(pg));
  304. }
  305. return(TRUE);
  306. } /* end of AddNormalChar() */
  307. /**************************************************************\
  308. ** AddBlockChar(pg, c)
  309. ** add a character to the output buffer (block mode)
  310. ** return TRUE means ok
  311. ** return FALSE means problem
  312. \**************************************************************/
  313. int AddBlockChar(
  314. GLOBAL_SEP_DATA *pg,
  315. int c
  316. )
  317. {
  318. int w;
  319. register int i,k;
  320. register char *p;
  321. unsigned char cBits, *pcBits;
  322. char cBlkFill;
  323. register int j;
  324. unsigned char *pcBitsLine;
  325. HBITMAP hBitmapOld;
  326. HFONT hFontOld;
  327. CHAR aTextBuf[2];
  328. SHORT sTextIndex = 0;
  329. ULONG cjBitmap;
  330. ULONG cjWidth = BLOCK_CHAR_WIDTH;
  331. #define CJ_DIB16_SCAN(cx) ((((cx) + 15) & ~15) >> 3)
  332. #define CJ_DIB16( cx, cy ) (CJ_DIB16_SCAN(cx) * (cy))
  333. if( pg->cLastChar == (CHAR)NULL && IsDBCSLeadByte((CHAR)c) ) {
  334. pg->cLastChar = (CHAR) c;
  335. return(TRUE);
  336. }
  337. if(pg->hDCMem == NULL) {
  338. pg->hDCMem = CreateCompatibleDC(NULL);
  339. if (pg->hDCMem == NULL)
  340. {
  341. //
  342. // Only happens when memory is exhausted. Functionality may suffer
  343. // but we won't AV.
  344. //
  345. return FALSE;
  346. }
  347. }
  348. if(pg->hBitmap == NULL) {
  349. pg->hBitmap = CreateCompatibleBitmap(pg->hDCMem,BLOCK_CHAR_DWIDTH,BLOCK_CHAR_HEIGHT);
  350. if ( pg->hBitmap == NULL )
  351. {
  352. //
  353. // Only happens when memory is exhausted. Functionality may suffer
  354. // but we won't AV.
  355. //
  356. return FALSE;
  357. }
  358. }
  359. if(pg->pvBits == NULL) {
  360. pg->pvBits = AllocSplMem(CJ_DIB16(BLOCK_CHAR_DWIDTH,BLOCK_CHAR_HEIGHT));
  361. if ( pg->pvBits == NULL )
  362. {
  363. //
  364. // Only happens when memory is exhausted. Functionality may suffer
  365. // but we won't AV.
  366. //
  367. return FALSE;
  368. }
  369. }
  370. if(pg->hFont == NULL) {
  371. LOGFONT lf;
  372. RtlZeroMemory(&lf,sizeof(LOGFONT));
  373. lf.lfHeight = BLOCK_CHAR_HEIGHT;
  374. lf.lfWidth = ( pg->mode == DOUBLE_WIDTH ) ?
  375. BLOCK_CHAR_DWIDTH :
  376. BLOCK_CHAR_WIDTH;
  377. lf.lfWeight = FW_NORMAL;
  378. lf.lfPitchAndFamily = FIXED_PITCH | FF_MODERN;
  379. lf.lfCharSet = DEFAULT_CHARSET;
  380. pg->hFont = CreateFontIndirect(&lf);
  381. }
  382. hBitmapOld = SelectObject(pg->hDCMem,pg->hBitmap);
  383. hFontOld = SelectObject(pg->hDCMem,pg->hFont);
  384. if( pg->cLastChar != (CHAR) NULL ) {
  385. aTextBuf[sTextIndex] = pg->cLastChar;
  386. sTextIndex ++;
  387. cjWidth = BLOCK_CHAR_DWIDTH;
  388. }
  389. aTextBuf[sTextIndex] = (CHAR) c;
  390. PatBlt(pg->hDCMem,0,0,BLOCK_CHAR_DWIDTH,BLOCK_CHAR_HEIGHT,WHITENESS);
  391. TextOutA(pg->hDCMem,0,0,aTextBuf,sTextIndex+1);
  392. GetBitmapBits(pg->hBitmap,CJ_DIB16(cjWidth,BLOCK_CHAR_HEIGHT),pg->pvBits);
  393. SelectObject(pg->hDCMem,hBitmapOld);
  394. SelectObject(pg->hDCMem,hFontOld);
  395. w = (pg->mode==DOUBLE_WIDTH)? cjWidth * 2 : cjWidth;
  396. if (pg->cbLineLength+w > pg->linewidth) {
  397. return(TRUE);
  398. }
  399. cBlkFill = '#';
  400. pcBitsLine = (unsigned char *) pg->pvBits;
  401. for (i = 0 ;
  402. i < BLOCK_CHAR_HEIGHT;
  403. i++, pcBitsLine += CJ_DIB16_SCAN(BLOCK_CHAR_DWIDTH)) {
  404. /* put block character into buffer line by line, top first */
  405. pcBits = pcBitsLine;
  406. p = pg->pOutBufPos + i * (MAXLINE+2);
  407. cBits = *pcBits;
  408. j = 0;
  409. for (k = cjWidth; k--; ) {
  410. if (pg->mode==DOUBLE_WIDTH) {
  411. *p = *(p+1) = (cBits & 0x80)? ' ' : cBlkFill;
  412. p += 2;
  413. } else {
  414. *p++ = (cBits & 0x80)? ' ' : cBlkFill;
  415. }
  416. cBits <<= 1;
  417. j++;
  418. if( j==8 ) {
  419. pcBits++; cBits = *pcBits; j = 0;
  420. }
  421. }
  422. } /* end of loop through lines of block char */
  423. pg->cLastChar = (CHAR) NULL;
  424. pg->pOutBufPos += w;
  425. pg->cbLineLength += w;
  426. pg->cbOutBufLength += w;
  427. return(TRUE);
  428. } /* end of AddBlockChar() */
  429. /**************************************************************\
  430. ** DoSeparatorPage(pg)
  431. ** this is the actual processing
  432. \**************************************************************/
  433. int DoSeparatorPage(GLOBAL_SEP_DATA *pg)
  434. {
  435. int status = TRUE;
  436. int c;
  437. char *pchar;
  438. WCHAR *pwchar;
  439. char tempbuf[MAX_PATH]; /* assume length of date, time, or job_id < MAXPATH */
  440. int (*AddCharFxn)() = AddNormalChar;
  441. if ((c = ReadSepChar(pg))==EOF) {
  442. return(TRUE);
  443. }
  444. pg->linewidth = DEFAULT_LINE_WIDTH;
  445. pg->cEsc = (CHAR) c;
  446. pg->pOutBufPos = pg->OutBuf;
  447. pg->cbOutBufLength = 0;
  448. pg->cbLineLength = 0;
  449. pg->mode = NORMAL_MODE;
  450. pg->hDCMem = (HDC) NULL;
  451. pg->hFont = (HFONT) NULL;
  452. pg->hBitmap = (HBITMAP) NULL;
  453. pg->cLastChar = (CHAR) NULL;
  454. pg->pvBits = (PVOID) NULL;
  455. while (status && ((c=ReadSepChar(pg))!=EOF) ) {
  456. /* find the next escape sequence */
  457. if (c != pg->cEsc) continue;
  458. /* found an escape character: now, check the next character */
  459. if ((c=ReadSepChar(pg))==EOF) {
  460. break;
  461. }
  462. switch (c) {
  463. case TEXT_MODE:
  464. if (pg->mode==NORMAL_MODE) {
  465. while (status && ((c=ReadSepChar(pg)) != EOF)) {
  466. if (c!=pg->cEsc) {
  467. status = AddNormalChar(pg, c);
  468. }
  469. else {
  470. /* This is to treat <esc><esc> as a normal char */
  471. c = ReadSepChar(pg);
  472. if (c==pg->cEsc) {
  473. status = AddNormalChar(pg, c);
  474. }
  475. else {
  476. UngetSepChar(pg, c);
  477. UngetSepChar(pg, pg->cEsc);
  478. break; /* breaks from the while, returns to main loop */
  479. }
  480. }
  481. }
  482. } /* end of NORMAL_MODE processing */
  483. else {
  484. while (status && ((c=ReadSepChar(pg))!=EOF)) {
  485. if (c=='\n') {
  486. status = FlushOutBuf(pg);
  487. }
  488. else if (c=='\r') {
  489. /* if followed by '\n', ignore.
  490. * Otherwise, AddBlockChar() the '\r'.
  491. */
  492. c = ReadSepChar(pg);
  493. if (c!='\n') {
  494. status = AddBlockChar(pg, '\r');
  495. }
  496. UngetSepChar(pg, c);
  497. }
  498. else {
  499. if (c==pg->cEsc) {
  500. /* This is to treat <esc><esc> as a normal char */
  501. c = ReadSepChar(pg);
  502. if (c==pg->cEsc) {
  503. status = AddBlockChar(pg, c);
  504. }
  505. else {
  506. UngetSepChar(pg, c);
  507. UngetSepChar(pg, pg->cEsc);
  508. break; /* breaks from the while, returns to main loop */
  509. }
  510. }
  511. else {
  512. status = AddBlockChar(pg, c);
  513. }
  514. }
  515. }
  516. } /* end of BLOCK mode processing */
  517. break;
  518. case BLOCK_START:
  519. case SINGLE_WIDTH:
  520. case DOUBLE_WIDTH:
  521. case NORMAL_MODE:
  522. status = FlushNewLine(pg);
  523. pg->mode = (CHAR) c;
  524. AddCharFxn = (pg->mode==NORMAL_MODE)? AddNormalChar : AddBlockChar;
  525. break;
  526. case USER_NAME:
  527. pwchar = pg->pSpool->pIniJob->pUser;
  528. if (pwchar) {
  529. char *pchar;
  530. UNICODE_STRING UnicodeString;
  531. ANSI_STRING AnsiString;
  532. RtlInitUnicodeString(&UnicodeString,pwchar);
  533. RtlUnicodeStringToAnsiString(&AnsiString,&UnicodeString,TRUE);
  534. pchar = AnsiString.Buffer;
  535. if ( pchar )
  536. {
  537. while (*pchar && status) status = (*AddCharFxn)(pg, *pchar++);
  538. }
  539. RtlFreeAnsiString(&AnsiString);
  540. }
  541. break;
  542. case DATE_INSERT:
  543. ConvertDatetoChar(&pg->pSpool->pIniJob->Submitted, tempbuf);
  544. pchar = tempbuf;
  545. while (*pchar && status) status = (*AddCharFxn)(pg, *pchar++);
  546. break;
  547. case TIME_INSERT:
  548. ConvertTimetoChar(&pg->pSpool->pIniJob->Submitted, tempbuf);
  549. pchar = tempbuf;
  550. while (*pchar && status) status = (*AddCharFxn)(pg, *pchar++);
  551. break;
  552. case JOB_ID:
  553. _itoa(pg->pSpool->pIniJob->JobId, tempbuf, 10);
  554. pchar = tempbuf;
  555. while (*pchar && status) status = (*AddCharFxn)(pg, *pchar++);
  556. break;
  557. case HEX_CODE:
  558. /* print a control character--read the hexadecimal code */
  559. c = ReadSepChar(pg);
  560. if (isxdigit(c)) {
  561. int c2 = ReadSepChar(pg);
  562. if (isxdigit(c2)) {
  563. c = (char)((ConvertAtoH(c) << 4) + ConvertAtoH(c2));
  564. status = (*AddCharFxn)(pg, c);
  565. }
  566. else {
  567. UngetSepChar(pg, c2);
  568. /* perhaps shouldn't do this? If they say @Hxx,
  569. * implying xx is a hexadecimal code, and the second
  570. * x is not a hex digit, should we leave that char
  571. * on the input line to be interpreted next, or should
  572. * we skip it? This only matters if it was an escape char,
  573. * i.e. @Hx@.... Right now, the second @ is considered
  574. * the start of a new command, and the @Hx is ignored
  575. * entirely. The same applies for the UngetSepChar() below.
  576. */
  577. }
  578. }
  579. else {
  580. UngetSepChar(pg, c);
  581. }
  582. break;
  583. case WIDTH_CHANGE:
  584. {
  585. /* read the decimal number; change line width if reasonable */
  586. int new_width = 0;
  587. for (c = ReadSepChar(pg); isdigit(c); c = ReadSepChar(pg)) {
  588. new_width = 10 * new_width + c - '0';
  589. }
  590. UngetSepChar(pg, c);
  591. if (new_width <= MAXLINE) {
  592. pg->linewidth = new_width;
  593. }
  594. else {
  595. pg->linewidth = MAXLINE;
  596. }
  597. break;
  598. }
  599. case '9':
  600. case '8':
  601. case '7':
  602. case '6':
  603. case '5':
  604. case '4':
  605. case '3':
  606. case '2':
  607. case '1':
  608. case '0':
  609. if (pg->mode==NORMAL_MODE) {
  610. status = AddNormalChar(pg,'\n');
  611. }
  612. if (status) status = FlushOutBuf(pg);
  613. if (status) status = WriteSepBuf(pg, sznewline, 2*(c-'0'));
  614. break;
  615. case END_PAGE:
  616. /* this just outputs a formfeed character */
  617. status = FlushNewLine(pg);
  618. if (status) status = WriteSepBuf(pg, "\f",1);
  619. break;
  620. case FILE_INSERT:
  621. {
  622. HANDLE hFile2, hMapping2;
  623. DWORD dwSizeLo2;
  624. char *pFirstChar;
  625. HANDLE hImpersonationToken;
  626. if (!(status = FlushNewLine(pg))) {
  627. break;
  628. }
  629. ReadFileName(pg, tempbuf, sizeof(tempbuf));
  630. hImpersonationToken = RevertToPrinterSelf();
  631. hFile2 = CreateFileA(tempbuf, GENERIC_READ, FILE_SHARE_READ,
  632. NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  633. ImpersonatePrinterClient(hImpersonationToken);
  634. if (hFile2 != INVALID_HANDLE_VALUE) {
  635. dwSizeLo2 = GetFileSize(hFile2, NULL); /* assume < 4 gigabytes! */
  636. hMapping2 = CreateFileMapping(hFile2,NULL,PAGE_READONLY,0,0,NULL);
  637. if (hMapping2 && (dwSizeLo2 > 0)) {
  638. pFirstChar = (char *)
  639. MapViewOfFile(hMapping2, FILE_MAP_READ, 0, 0, dwSizeLo2);
  640. if (pFirstChar) {
  641. status = WriteSepBuf(pg, pFirstChar, dwSizeLo2);
  642. UnmapViewOfFile(pFirstChar);
  643. }
  644. CloseHandle(hMapping2);
  645. }
  646. CloseHandle(hFile2);
  647. }
  648. /* NOTE: if couldn't open file, or error while reading file,
  649. * status is NOT set to false. We will simply stop the file
  650. * insert operation, and continue processing the rest of the
  651. * the separator page as before.
  652. */
  653. else {
  654. DBGMSG(DBG_WARNING, ("SEPARATOR PAGE: Could not open file %s \n",tempbuf));
  655. }
  656. break;
  657. }
  658. default:
  659. break;
  660. }
  661. } /* end of main while loop...find next escape sequence, process */
  662. if (status) status = FlushOutBuf(pg);
  663. if (pg->hDCMem != (HDC) NULL) DeleteDC(pg->hDCMem);
  664. if (pg->hFont != (HFONT) NULL) DeleteObject(pg->hFont);
  665. if (pg->hBitmap != (HBITMAP) NULL) DeleteObject(pg->hBitmap);
  666. if (pg->pvBits != (PVOID) NULL) FreeSplMem(pg->pvBits);
  667. return(status);
  668. } /* end of DoSeparatorPage() */
  669. /**************************************************************\
  670. ** ConvertAtoH(c)
  671. ** Converts an ASCII character to hexadecimal.
  672. \**************************************************************/
  673. int ConvertAtoH(int c)
  674. {
  675. return( c - (isdigit(c)? '0' :
  676. ((isupper(c)? 'A':'a') - 10)));
  677. }
  678. /**************************************************************\
  679. ** ConvertTimetoChar()
  680. ** converts system time to a string (internationalized).
  681. \**************************************************************/
  682. void ConvertTimetoChar(
  683. SYSTEMTIME *pSystemTime,
  684. char *string
  685. )
  686. {
  687. SYSTEMTIME LocalTime;
  688. LCID lcid;
  689. // Convert to local time
  690. SystemTimeToTzSpecificLocalTime(NULL, pSystemTime, &LocalTime);
  691. // Get lcid of local machine
  692. lcid=GetSystemDefaultLCID();
  693. // Convert to string, , using default format for that locale
  694. GetTimeFormatA(lcid, 0, &LocalTime, NULL, string, MAX_PATH-1);
  695. }
  696. /**************************************************************\
  697. ** ConvertDatetoChar()
  698. ** converts system date to a string (internationalized).
  699. \**************************************************************/
  700. void ConvertDatetoChar(
  701. SYSTEMTIME *pSystemTime,
  702. char *string
  703. )
  704. {
  705. SYSTEMTIME LocalTime;
  706. LCID lcid;
  707. // Convert to local time
  708. SystemTimeToTzSpecificLocalTime(NULL, pSystemTime, &LocalTime);
  709. // Get lcid of local machine
  710. lcid = GetSystemDefaultLCID();
  711. // Convert to string, using default format for that locale
  712. GetDateFormatA(lcid, 0, &LocalTime, NULL, string, MAX_PATH-1);
  713. }
  714. /**************************************************************\
  715. ** ReadFileName(pg, szfilename, dwbufsize)
  716. ** parses a filename from the separator file (following <esc>F).
  717. ** the following scheme is used:
  718. **
  719. ** - read until a single escape, EOF, newline, or carriage return
  720. ** is encountered. Put this string into a temporary buffer,
  721. ** passed by the calling function.
  722. **
  723. ** - if string begins with a double quote, skip this double quote,
  724. ** and consider the double quote character as an end of string
  725. ** marker, just like the newline. Thus, @F"myfile
  726. ** will be read as @Fmyfile
  727. **
  728. \**************************************************************/
  729. void ReadFileName(
  730. GLOBAL_SEP_DATA *pg,
  731. char *szfilename,
  732. DWORD dwbufsize
  733. )
  734. {
  735. char *pchar = szfilename;
  736. char c;
  737. DWORD dwcount = 0;
  738. BOOL bNotQuote = TRUE;
  739. if ((pg->dwFileCount < pg->dwFileSizeLo) && (*pg->pNextFileChar=='\"')) {
  740. pg->dwFileCount++;
  741. pg->pNextFileChar++;
  742. bNotQuote = FALSE;
  743. }
  744. while ((dwcount < dwbufsize - 1) && (pg->dwFileCount < pg->dwFileSizeLo) && (c=*pg->pNextFileChar)!='\n'
  745. && c!='\r' && (bNotQuote || c!='\"')) {
  746. if (c!=pg->cEsc) {
  747. *pchar++ = c;
  748. dwcount++;
  749. pg->pNextFileChar++;
  750. pg->dwFileCount++;
  751. }
  752. else {
  753. if ((pg->dwFileCount+1) < pg->dwFileSizeLo
  754. && *(pg->pNextFileChar+1)==pg->cEsc) {
  755. *pchar++ = pg->cEsc;
  756. dwcount++;
  757. pg->pNextFileChar+=2;
  758. pg->dwFileCount+=2;
  759. }
  760. else {
  761. break;
  762. }
  763. }
  764. } /* end of loop to read characters */
  765. *pchar = '\0';
  766. } /* end of ReadFileName() */