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.

580 lines
13 KiB

  1. /*==============================================================================
  2. This code module handles T4 conversion instances.
  3. DATE NAME COMMENTS
  4. 12-Apr-93 RajeevD Adapted to C++ from WFW.
  5. 20-Apr-93 RajeevD Overhauled buffer handling.
  6. ==============================================================================*/
  7. #include <ifaxos.h>
  8. #include <memory.h>
  9. #include <faxcodec.h>
  10. #include "context.hpp"
  11. #define RTC_EOL 5
  12. #define VALIDATE_CHANGE
  13. typedef short FAR *LPSHORT;
  14. //==============================================================================
  15. #pragma warning(disable:4704)
  16. #ifdef WIN32
  17. UINT // size of change vector (0 if invalid)
  18. ValidChangeVector
  19. (
  20. LPSHORT lpsChange, // change vector buffer
  21. SHORT xExt // pixel width of line
  22. )
  23. {
  24. SHORT sPrev = -1;
  25. SHORT cChange = xExt;
  26. while (cChange--)
  27. {
  28. // Check monotonicity.
  29. if (*lpsChange <= sPrev)
  30. return 0;
  31. sPrev = *lpsChange++;
  32. if (sPrev == xExt)
  33. {
  34. // Check EOL termination.
  35. if
  36. ( *lpsChange++ == xExt
  37. && *lpsChange++ == xExt
  38. && *lpsChange++ == xExt
  39. && *lpsChange++ == -1
  40. && *lpsChange++ == -1
  41. )
  42. return sizeof(WORD) * (xExt - cChange) ;
  43. else
  44. return 0;
  45. }
  46. } // while (cChange--)
  47. return 0; // Hit end of change vector buffer.
  48. }
  49. #else // ifndef WIN32
  50. UINT // size of change vector (0 if invalid)
  51. ValidChangeVector
  52. (
  53. LPSHORT lpsChange, // change vector buffer
  54. SHORT xExt // pixel width of line
  55. )
  56. {
  57. UINT uRet;
  58. _asm
  59. {
  60. push ds
  61. push si
  62. lds si, DWORD PTR [lpsChange] ; lpsChange
  63. mov dx, -1 ; sPrev
  64. mov cx, xExt ; cChange
  65. mov bx, cx ; xExt
  66. jmp enterloop
  67. fooie:
  68. lodsw
  69. cmp ax, dx
  70. jle error ; need SIGNED compare
  71. mov dx, ax
  72. cmp dx, bx
  73. je goteol
  74. enterloop:
  75. loop fooie
  76. error:
  77. xor ax, ax
  78. jmp done
  79. goteol:
  80. lodsw
  81. cmp ax, bx ; bx == xExt
  82. jne error
  83. lodsw
  84. cmp ax, bx
  85. jne error
  86. lodsw
  87. cmp ax, bx
  88. jne error
  89. xor bx, bx
  90. not bx ; bx == -1
  91. lodsw
  92. cmp ax, bx
  93. jne error
  94. lodsw
  95. cmp ax, bx
  96. jne error
  97. // uRet = sizeof(WORD) * (xExt - cChange) ;
  98. mov ax, xExt
  99. sub ax, cx
  100. inc ax
  101. shl ax, 1
  102. done:
  103. pop si
  104. pop ds
  105. mov uRet, ax
  106. }
  107. return uRet;
  108. }
  109. #endif // WIN32
  110. //==============================================================================
  111. void CODEC::ResetBad (void)
  112. {
  113. DEBUGMSG (1,("FAXCODEC: decoded %d bad line(s)\r\n", wBad));
  114. if (fcCount.cMaxRunBad < wBad)
  115. fcCount.cMaxRunBad = wBad;
  116. wBad = 0;
  117. }
  118. //==============================================================================
  119. void CODEC::SwapChange (void)
  120. {
  121. LPBYTE lpbTemp;
  122. lpbTemp = lpbChange;
  123. lpbChange = lpbRef;
  124. lpbRef = lpbTemp;
  125. }
  126. //==============================================================================
  127. void CODEC::EndLine (void)
  128. {
  129. if (f2D)
  130. {
  131. // Reset consumer and producer.
  132. t4C.lpbRef = lpbRef;
  133. t4C.lpbBegRef = lpbRef;
  134. t4P.lpbRef = lpbRef;
  135. t4P.lpbBegRef = lpbRef;
  136. // Increment K Factor
  137. t4P.iKFactor++;
  138. if (t4P.iKFactor == nKFactor)
  139. t4P.iKFactor = 0;
  140. }
  141. // Clear change vector buffer (debug only).
  142. DEBUGSTMT (_fmemset (lpbChange, 0xCD, sizeof(WORD) * xExt + CHANGE_SLACK));
  143. // Reset consumer.
  144. t4C.wColumn = 0;
  145. t4C.wColor = 0;
  146. t4C.lpbOut = lpbChange;
  147. t4C.wOffset = LOWORD(lpbChange);
  148. t4C.wToggle = 0;
  149. // Reset producer.
  150. t4P.wColumn = 0;
  151. t4P.wColor = 0;
  152. t4P.lpbIn = lpbChange;
  153. }
  154. //==============================================================================
  155. void CODEC::StartPage (void)
  156. {
  157. if (wBad) ResetBad();
  158. cSpurious = 0;
  159. EndLine ();
  160. // Reset consumer.
  161. t4C.wWord = 0;
  162. t4C.wBit = 0;
  163. t4C.wRet = RET_BEG_OF_PAGE;
  164. // Reset producer.
  165. t4P.wWord = 0;
  166. t4P.wBit = 0;
  167. t4P.wRet = RET_BEG_OF_PAGE;
  168. // Blank buffered output line.
  169. _fmemset (lpbLine, 0, cbLine);
  170. if (f2D)
  171. {
  172. // Blank reference vector.
  173. LPWORD lpwRef = (LPWORD) lpbRef;
  174. *lpwRef++ = (WORD)xExt;
  175. *lpwRef++ = (WORD)xExt;
  176. *lpwRef++ = (WORD)xExt;
  177. *lpwRef++ = (WORD)xExt;
  178. *lpwRef++ = 0xFFFF;
  179. *lpwRef++ = 0xFFFF;
  180. t4C.wMode = 0;
  181. t4P.wMode = 0;
  182. t4P.iKFactor = 0;
  183. }
  184. }
  185. //==============================================================================
  186. void CODEC::EndPage (LPBUFFER lpbufOut)
  187. {
  188. // Flush last byte and end-of-block code.
  189. switch (nTypeOut)
  190. {
  191. case LRAW_DATA:
  192. case NULL_DATA:
  193. return;
  194. case MH_DATA:
  195. case MR_DATA:
  196. #ifndef WIN32
  197. return;
  198. #endif
  199. case MMR_DATA:
  200. {
  201. LPBYTE lpbBeg = lpbufOut->EndData();
  202. t4P.lpbOut = lpbBeg;
  203. t4P.cbOut = (WORD)(lpbufOut->EndBuf() - t4P.lpbOut);
  204. t4P.wRet = RET_END_OF_PAGE;
  205. Producer (&t4P);
  206. lpbufOut->wLengthData += (WORD)(t4P.lpbOut - lpbBeg);
  207. return;
  208. }
  209. default: DEBUGCHK (FALSE);
  210. }
  211. }
  212. /*==============================================================================
  213. This method initializes a CODEC context.
  214. ==============================================================================*/
  215. void CODEC::Init (LPFC_PARAM lpParam, BOOL f2DInit)
  216. {
  217. DEBUGMSG (1, ("FAXCODEC: nTypeIn = %lx\n\r", lpParam->nTypeIn));
  218. DEBUGMSG (1, ("FAXCODEC: nTypeOut = %lx\n\r", lpParam->nTypeOut));
  219. DEBUGMSG (1, ("FAXCODEC: cbLine = %d\n\r", lpParam->cbLine));
  220. DEBUGMSG (1, ("FAXCODEC: nKFactor = %d\n\r", lpParam->nKFactor));
  221. // Initialize constants.
  222. _fmemcpy (this, lpParam, sizeof(FC_PARAM));
  223. xExt = 8 * cbLine;
  224. f2D = f2DInit;
  225. switch (nTypeIn) // Determine the consumer.
  226. {
  227. case LRAW_DATA: Consumer = RawToChange; break;
  228. case MH_DATA: Consumer = MHToChange; break;
  229. case MR_DATA: Consumer = MRToChange; break;
  230. case MMR_DATA: Consumer = MMRToChange; break;
  231. default: DEBUGCHK (FALSE);
  232. }
  233. switch (nTypeOut) // Determine the producer.
  234. {
  235. case NULL_DATA: Producer = NULL; break;
  236. case LRAW_DATA: Producer = ChangeToRaw; break;
  237. case MH_DATA: Producer = ChangeToMH; break;
  238. case MR_DATA: Producer = ChangeToMR; break;
  239. case MMR_DATA: Producer = ChangeToMMR; break;
  240. default: DEBUGCHK (FALSE);
  241. }
  242. // Initialize memory buffers.
  243. lpbLine = (LPBYTE) (this + 1);
  244. lpbChange = lpbLine + cbLine + RAWBUF_SLACK;
  245. lpbRef = lpbChange;
  246. if (f2D)
  247. lpbRef += xExt * sizeof(USHORT) + CHANGE_SLACK;
  248. // Initialize consumer state.
  249. t4C.cbSlack = CHANGE_SLACK;
  250. t4C.cbLine = (WORD)cbLine;
  251. t4C.nType = nTypeIn;
  252. // Initialize producer state.
  253. t4P.cbSlack = OUTBUF_SLACK;
  254. t4P.cbLine = (WORD)cbLine;
  255. t4P.nType = nTypeOut;
  256. // Initialize error counts.
  257. _fmemset (&fcCount, 0, sizeof(fcCount));
  258. wBad = 0;
  259. // Reset for beginning of page.
  260. StartPage();
  261. }
  262. /*==============================================================================
  263. This method executes a CODEC conversion.
  264. ==============================================================================*/
  265. FC_STATUS CODEC::Convert (LPBUFFER lpbufIn, LPBUFFER lpbufOut)
  266. {
  267. FC_STATUS ret;
  268. // A null input buffer is flag for end of page.
  269. if (!lpbufIn || lpbufIn->dwMetaData == END_OF_PAGE)
  270. {
  271. DEBUGMSG (1,("FAXCODEC: got EOP\r\n"));
  272. EndPage (lpbufOut);
  273. StartPage ();
  274. return FC_INPUT_EMPTY;
  275. }
  276. // Ignore input after RTC but before end of page.
  277. if (cSpurious == RTC_EOL)
  278. {
  279. DEBUGMSG (1,("FAXCODEC: ignoring input after RTC or EOFB\r\n"));
  280. return FC_INPUT_EMPTY;
  281. }
  282. #ifndef WIN32
  283. if (t4C.wRet == RET_BEG_OF_PAGE)
  284. {
  285. if (nTypeOut == MH_DATA || nTypeOut == MR_DATA)
  286. {
  287. // Start page with EOL.
  288. if (lpbufOut->EndBuf() - lpbufOut->EndData() < OUTBUF_SLACK)
  289. return FC_OUTPUT_FULL;
  290. *((LPWORD) lpbufOut->EndData()) = 0x8000;
  291. lpbufOut->wLengthData += 2;
  292. }
  293. }
  294. #endif // WIN32
  295. // Initialize input buffer of consumer.
  296. t4C.lpbIn = lpbufIn->lpbBegData;
  297. t4C.cbIn = lpbufIn->wLengthData;
  298. // Dispatch to 2 or 3 phase conversion.
  299. if (nTypeOut == LRAW_DATA || nTypeOut == NULL_DATA)
  300. ret = ConvertToRaw (lpbufIn, lpbufOut);
  301. else
  302. ret = ConvertToT4 (lpbufIn, lpbufOut);
  303. // Adjust input buffer header.
  304. lpbufIn->lpbBegData = t4C.lpbIn;
  305. lpbufIn->wLengthData = t4C.cbIn;
  306. return ret;
  307. }
  308. //==============================================================================
  309. FC_STATUS CODEC::ConvertToRaw (LPBUFFER lpbufIn, LPBUFFER lpbufOut)
  310. {
  311. LPBYTE lpbOut = lpbufOut->EndData();
  312. UINT cbOut = (UINT)(lpbufOut->EndBuf() - lpbOut);
  313. if (t4P.wRet == RET_OUTPUT_FULL)
  314. goto copy_phase;
  315. while (1)
  316. {
  317. Consumer (&t4C); // generate change vector
  318. switch (t4C.wRet)
  319. {
  320. case RET_INPUT_EMPTY1:
  321. case RET_INPUT_EMPTY2:
  322. return FC_INPUT_EMPTY;
  323. case RET_SPURIOUS_EOL:
  324. if (++cSpurious == RTC_EOL)
  325. return FC_INPUT_EMPTY;
  326. EndLine();
  327. continue;
  328. case RET_DECODE_ERR:
  329. break; // handle it later
  330. case RET_END_OF_PAGE:
  331. if (wBad) ResetBad();
  332. cSpurious = RTC_EOL;
  333. return FC_INPUT_EMPTY;
  334. case RET_END_OF_LINE:
  335. t4P.cbIn = (USHORT)ValidChangeVector ((LPSHORT) lpbChange, (SHORT)xExt);
  336. if (!t4P.cbIn)
  337. t4C.wRet = RET_DECODE_ERR; // consumer lied!
  338. else
  339. {
  340. // Adjust counters.
  341. fcCount.cTotalGood++;
  342. if (wBad) ResetBad();
  343. cSpurious = 0;
  344. }
  345. break;
  346. default: DEBUGCHK (FALSE);
  347. }
  348. // Handle decode errors.
  349. if (t4C.wRet == RET_DECODE_ERR)
  350. {
  351. if (nTypeIn == MMR_DATA)
  352. return FC_DECODE_ERR;
  353. wBad++;
  354. fcCount.cTotalBad++;
  355. #ifdef DEBUG
  356. _fmemset (lpbLine, 0xFF, cbLine); // emit black line
  357. #endif
  358. if (f2D)
  359. {
  360. // Replicate change vector.
  361. t4P.cbIn = (WORD)ValidChangeVector ((LPSHORT) lpbRef, (WORD)xExt);
  362. DEBUGCHK (t4P.cbIn);
  363. _fmemcpy (lpbChange, lpbRef, t4P.cbIn + CHANGE_SLACK);
  364. }
  365. if (nTypeOut == NULL_DATA)
  366. goto EOL;
  367. if (!f2D)
  368. goto copy_phase;
  369. }
  370. // Optimize validation.
  371. if (nTypeOut == NULL_DATA)
  372. goto EOL;
  373. // Run the producer.
  374. t4P.lpbOut = lpbLine;
  375. t4P.cbOut = (WORD)cbLine;
  376. ChangeToRaw (&t4P);
  377. copy_phase:
  378. if (cbOut < cbLine)
  379. {
  380. t4P.wRet = RET_OUTPUT_FULL;
  381. return FC_OUTPUT_FULL;
  382. }
  383. // Append buffered line to output.
  384. t4P.wRet = RET_END_OF_LINE;
  385. _fmemcpy (lpbOut, lpbLine, cbLine);
  386. lpbufOut->wLengthData += (WORD)cbLine;
  387. lpbOut += cbLine;
  388. cbOut -= cbLine;
  389. EOL:
  390. SwapChange ();
  391. EndLine ();
  392. } // while (1)
  393. // C8 thinks we can get here, but I know better.
  394. DEBUGCHK (FALSE);
  395. return FC_DECODE_ERR;
  396. }
  397. //==============================================================================
  398. FC_STATUS CODEC::ConvertToT4 (LPBUFFER lpbufIn, LPBUFFER lpbufOut)
  399. {
  400. LPBYTE lpbBegOut;
  401. t4P.lpbOut = lpbufOut->EndData();
  402. t4P.cbOut = (WORD)(lpbufOut->EndBuf() - t4P.lpbOut);
  403. if (t4P.wRet == RET_OUTPUT_FULL)
  404. goto producer_phase;
  405. while (1) // Loop until input is empty or output is full.
  406. {
  407. Consumer (&t4C);
  408. switch (t4C.wRet)
  409. {
  410. case RET_INPUT_EMPTY1:
  411. case RET_INPUT_EMPTY2:
  412. return FC_INPUT_EMPTY;
  413. case RET_SPURIOUS_EOL:
  414. if (++cSpurious == RTC_EOL)
  415. return FC_INPUT_EMPTY;
  416. EndLine();
  417. continue;
  418. case RET_DECODE_ERR:
  419. break; // handle it later
  420. case RET_END_OF_PAGE:
  421. if (wBad) ResetBad();
  422. cSpurious = RTC_EOL;
  423. return FC_INPUT_EMPTY;
  424. case RET_END_OF_LINE:
  425. t4P.cbIn = (WORD)ValidChangeVector ((LPSHORT) lpbChange, (WORD)xExt);
  426. if (!t4P.cbIn)
  427. t4C.wRet = RET_DECODE_ERR; // consumer lied!
  428. else
  429. {
  430. // Adjust counters.
  431. fcCount.cTotalGood++;
  432. if (wBad) ResetBad();
  433. cSpurious = 0;
  434. }
  435. break;
  436. default: DEBUGCHK (FALSE);
  437. }
  438. if (t4C.wRet == RET_DECODE_ERR)
  439. {
  440. DEBUGCHK (f2D && nTypeIn != LRAW_DATA);
  441. if (nTypeIn == MMR_DATA)
  442. return FC_DECODE_ERR;
  443. wBad++;
  444. fcCount.cTotalBad++;
  445. #ifdef DEBUG
  446. {
  447. // Substitute all black line.
  448. LPWORD lpwChange = (LPWORD) lpbChange;
  449. *lpwChange++ = 0;
  450. *lpwChange++ = xExt;
  451. *lpwChange++ = xExt;
  452. *lpwChange++ = xExt;
  453. *lpwChange++ = xExt;
  454. *lpwChange++ = 0xFFFF;
  455. *lpwChange++ = 0xFFFF;
  456. t4P.cbIn = 4;
  457. }
  458. #else
  459. // Replicate previous line
  460. t4P.cbIn = (WORD)ValidChangeVector ((LPSHORT) lpbRef, (WORD)xExt);
  461. DEBUGCHK (t4P.cbIn);
  462. _fmemcpy (lpbChange, lpbRef, t4P.cbIn + CHANGE_SLACK);
  463. #endif
  464. }
  465. producer_phase:
  466. lpbBegOut = t4P.lpbOut;
  467. Producer (&t4P);
  468. lpbufOut->wLengthData += (WORD)(t4P.lpbOut - lpbBegOut);
  469. // Check if output is full.
  470. if (t4P.wRet == RET_OUTPUT_FULL)
  471. return FC_OUTPUT_FULL;
  472. // EOL:
  473. SwapChange();
  474. EndLine ();
  475. } // while (1)
  476. // C8 thinks we can get here, but I know better.
  477. DEBUGCHK (FALSE);
  478. return FC_DECODE_ERR;
  479. }