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.

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