CopyQuality.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:39k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: CopyQuality.c++,v 1.17 2008/11/24 06:17:59 faxguy Exp $ */ /*
  2.  * Copyright (c) 1994-1996 Sam Leffler
  3.  * Copyright (c) 1994-1996 Silicon Graphics, Inc.
  4.  * HylaFAX is a trademark of Silicon Graphics
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. /*
  26.  * Page Data Receive and Copy Quality Support for Modem Drivers.
  27.  */
  28. #include "config.h"
  29. #include "Sys.h"
  30. #include "FaxModem.h"
  31. #include "FaxTrace.h"
  32. #include "ModemConfig.h"
  33. #include "StackBuffer.h"
  34. #include "FaxServer.h"
  35. #include <ctype.h>
  36. #define RCVBUFSIZ (32*1024) // XXX
  37. static void setupCompression(TIFF*, u_int, u_int, uint32);
  38. void
  39. FaxModem::setupStartPage(TIFF* tif, const Class2Params& params)
  40. {
  41.     /*
  42.      * Not doing copy quality checking so compression and
  43.      * Group3Options must reflect the negotiated session
  44.      * parameters for the forthcoming page data.
  45.      */
  46.     setupCompression(tif, params.df, params.jp, group3opts);
  47.     /*
  48.      * Do magic at page start to collect the file offset
  49.      * to the start of the page data--this is used in case
  50.      * of an error to overwrite unacceptable page data.
  51.      *
  52.      * NB: This must be done *after* setting the compression
  53.      *     scheme, otherwise the TIFF library will disallow
  54.      *     setting the Compression tag.
  55.      */
  56.     recvStartPage(tif);
  57. }
  58. void
  59. FaxModem::recvEndPage(TIFF* tif, const Class2Params& params)
  60. {
  61.     /*
  62.      * FAXRECVPARAMS is limited to a 32-bit value, and as that is quite
  63.      * limited in comparison to all possible fax parameters, FAXDCS is
  64.      * intended to be used to discern most fax parameters.  The DCS
  65.      * signal, however, does not contain bitrate information when V.34-Fax
  66.      * is used, so tiffinfo, for example, will use FAXDCS for all fax
  67.      * parameters except for bitrate which comes from FAXRECVPARAMS.
  68.      *
  69.      * As FAXDCS is more recent in libtiff than is FAXRECVPARAMS some
  70.      * installations may not be able to use FAXDCS, in which case those
  71.      * installations will be limited to the 32-bit restraints.
  72.      */
  73.     // NB: must set these after compression tag
  74. #ifdef TIFFTAG_FAXRECVPARAMS
  75.     TIFFSetField(tif, TIFFTAG_FAXRECVPARAMS, (uint32) params.encode());
  76. #endif
  77. #ifdef TIFFTAG_FAXDCS
  78.     FaxParams pageparams = FaxParams(params);
  79.     fxStr faxdcs = "";
  80.     pageparams.asciiEncode(faxdcs);
  81.     TIFFSetField(tif, TIFFTAG_FAXDCS, (const char*) faxdcs);
  82. #endif
  83. #ifdef TIFFTAG_FAXSUBADDRESS
  84.     if (sub != "")
  85. TIFFSetField(tif, TIFFTAG_FAXSUBADDRESS, (const char*) sub);
  86. #endif
  87. #ifdef TIFFTAG_FAXRECVTIME
  88.     TIFFSetField(tif, TIFFTAG_FAXRECVTIME,
  89. (uint32) server.setPageTransferTime());
  90. #endif
  91. }
  92. void
  93. FaxModem::resetLineCounts()
  94. {
  95.     recvEOLCount = 0; // count of EOL codes
  96.     recvBadLineCount = 0; // rows with a decoding error
  97.     recvConsecutiveBadLineCount = 0; // max consecutive bad rows
  98.     linesWereA4Width = 0; // rows that measured 1728 pels
  99. }
  100. void
  101. FaxModem::initializeDecoder(const Class2Params& params)
  102. {
  103.     setupDecoder(recvFillOrder, params.is2D(), (params.df == DF_2DMMR));
  104.     u_int rowpixels = params.pageWidth(); // NB: assume rowpixels <= 4864
  105.     tiff_runlen_t runs[2*4864]; // run arrays for cur+ref rows
  106.     setRuns(runs, runs+4864, rowpixels);
  107.     setIsECM(false);
  108.     resetLineCounts();
  109. }
  110. /*
  111.  * Receive Phase C data with or without copy
  112.  * quality checking and erroneous row fixup.
  113.  */
  114. bool
  115. FaxModem::recvPageDLEData(TIFF* tif, bool checkQuality,
  116.     const Class2Params& params, fxStr& emsg)
  117. {
  118.     /* For debugging purposes we may want to write the image-data to file. */
  119.     if (conf.saverawimage) imagefd = Sys::open("/tmp/in.fax", O_RDWR|O_CREAT|O_EXCL);
  120.     initializeDecoder(params);
  121.     u_int rowpixels = params.pageWidth(); // NB: assume rowpixels <= 4864
  122.     /*
  123.      * Data destined for the TIFF file is buffered in buf.
  124.      * recvRow points to the next place in buf where data
  125.      * (decoded or undecoded) is to be placed.  Beware
  126.      * that this is not an automatic variable because our
  127.      * use of setjmp/longjmp to deal with EOF and RTC detection
  128.      * does not guarantee correct values being restored to
  129.      * automatic variables when the stack is unwound.
  130.      */
  131.     u_char buf[RCVBUFSIZ]; // output buffer
  132.     recvRow = buf; // current decoded row
  133.     recvStrip = 0; // TIFF strip number
  134.     bytePending = 0;
  135.     if (EOFraised()) {
  136. abortPageRecv();
  137. emsg = "Missing EOL after 5 seconds {E050}";
  138. recvTrace("%s", (const char*) emsg);
  139. return (false);
  140.     }
  141.     if (checkQuality && params.ec == EC_DISABLE) {
  142. /*
  143.  * Receive a page of data w/ copy quality checking.
  144.  * Note that since we decode and re-encode we can
  145.  * trivially do transcoding by just changing the
  146.  * TIFF tag values setup for each received page.  This
  147.  * may however be too much work for some CPUs.
  148.  *
  149.  * Copy quality checking is superfluous when using ECM.
  150.  */
  151. tsize_t rowSize = TIFFScanlineSize(tif);// scanline buffer size
  152. /*
  153.  * When copy quality checking is done we generate multi-strip
  154.  * images where the strip size is dependent on the size of the
  155.  * receive buffer used to buffer decoded image data.  There is
  156.  * a balance here between reducing i/o, minimizing encoding
  157.  * overhead, and minimizing delays that occur in the middle of
  158.  * page data receive operations.  If the receive buffer is made
  159.  * too large then a modem with little buffering may have a
  160.  * data underrun occur.  On the other hand encoding each row of
  161.  * data adds to the overhead both in setup time for the encoder
  162.  * and in various accounting work done by the TIFF library when
  163.  * images are grown row-by-row.  All this is also dependent on
  164.  * the speed of the host CPU and i/o performance.
  165.  */
  166. TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, RCVBUFSIZ / rowSize);
  167. /*
  168.  * Since we decode and re-encode we can choose any
  169.  * compression scheme we want for the data that's
  170.  * eventually written to the file.
  171.  */
  172. u_int df = (conf.recvDataFormat == DF_ALL ?
  173.     params.df : conf.recvDataFormat);
  174. setupCompression(tif, df, 0, 0); // XXX maybe zero-fill EOLs?
  175. /*
  176.  * Do magic at page start to collect the file offset
  177.  * to the start of the page data--this is used in case
  178.  * of an error to overwrite unacceptable page data.
  179.  *
  180.  * NB: This must be done *after* setting the compression
  181.  *     scheme, otherwise the TIFF library will disallow
  182.  *     setting the Compression tag.
  183.  */
  184. recvStartPage(tif);
  185. u_char* curGood = (u_char*) malloc((size_t) rowSize);
  186. memset(curGood, 0, (size_t) rowSize); // clear to white
  187. recvBuf = NULL; // don't need raw data
  188. lastRowBad = false; // no previous row
  189. cblc = 0; // current bad line run
  190. if (!RTCraised()) {
  191.     for (;;) {
  192. /*
  193.  * Decode the next row of data into the raster.  If
  194.  * an error is encountered, replicate the last good
  195.  * row and continue.  We track statistics on bad
  196.  * lines and consecutive bad lines; these are used
  197.  * later for deciding whether or not the page quality
  198.  * is acceptable.
  199.  */
  200. decodedPixels = rowpixels; // assume no error
  201. bool decodeOK = decodeRow(recvRow, rowpixels);
  202. if (seenRTC()) // seen RTC, flush everything
  203.     continue;
  204. if (decodeOK) {
  205.     if (lastRowBad) { // reset run statistics
  206. lastRowBad = false;
  207. if (cblc > recvConsecutiveBadLineCount)
  208.     recvConsecutiveBadLineCount = cblc;
  209. cblc = 0;
  210.     }
  211. } else {
  212.     /*
  213.      * Our copy-quality correction mechanism involves decoding
  214.      * and re-encoding each line (as is being done), and if a
  215.      * line is decoded with error (short pixel count) then the
  216.      * remaining pixels are carried-over from the row above.
  217.      * This is done instead of replacing the corrupt row with
  218.      * the last good row to avoid severe data loss where the
  219.      * decoded data is still valid (only incomplete), and this
  220.      * is done instead of replacing the missing data with white
  221.      * to avoid visual disconnect of blackened areas.
  222.      */
  223.     if ((u_int) decodedPixels < rowpixels) {
  224. u_int filledchars = (decodedPixels + 7) / 8;
  225. u_short rembits = decodedPixels % 8;
  226. memcpy(recvRow + filledchars, curGood + filledchars, rowSize - filledchars);
  227. if (rembits) {
  228.     // now deal with the transitional character
  229.     u_char remmask = 0;
  230.     for (u_short bit = 0; bit < 8; bit++) {
  231. remmask<<=1;
  232. if (bit < rembits) remmask |= 1;
  233.     }
  234.     recvRow[filledchars-1] = (recvRow[filledchars-1] & remmask) | (curGood[filledchars-1] & ~remmask);
  235. }
  236.     } else if ((u_int) decodedPixels >= rowpixels) {
  237. /*
  238.  * If we get a long pixel count, then our correction mechanism
  239.  * involves trimming horizontal "streaks" at the end of the
  240.  * scanline and replacing that data with the corresponding data
  241.  * from the preceding scanline.  If the streak doesn't exceed
  242.  * rowpixels, then copy quality checking won't catch it, so
  243.  * streaks can still appear, but this does well at getting most
  244.  * of them in practice.
  245.  */
  246. u_int pos = rowSize - 1;
  247. u_char streak = recvRow[pos];
  248. if (streak == 0xFF || streak == 0x00) {
  249.     while (pos && recvRow[pos] == streak) {
  250. recvRow[pos] = curGood[pos];
  251. pos--;
  252.     }
  253. }
  254.     }
  255.     /*
  256.      * Some senders signal the wrong page width in DCS, such as A3,
  257.      * and then proceed to deliver A4 page image data.  The copy
  258.      * quality correction mechanism will allow the image data to get
  259.      * through, with white space on the right, but it's better to
  260.      * avoid sending RTN, as it will only cause more of the same or
  261.      * will cause the sender to disconnect.  So if the we seem to
  262.      * be getting A4 page data when something else was negotiated
  263.      * we don't count those lines as bad.
  264.      */
  265.     linesWereA4Width += decodedPixels == 1728 ? 1 : 0;
  266.     if (decodedPixels != 1728 || linesWereA4Width < ((recvEOLCount + 1) * 95 / 100)) {
  267. recvBadLineCount++;
  268. cblc++;
  269. lastRowBad = true;
  270.     }
  271. }
  272. if (decodedPixels) memcpy(curGood, recvRow, (size_t) rowSize);
  273. /*
  274.  * Advance forward a scanline and if necessary
  275.  * flush the buffer.  Note that we leave the
  276.  * pointer to the last good row of data at the
  277.  * last decoded line near the end of the buffer.
  278.  * We assume the buffer is large enough that we
  279.  * don't have to worry about overlapping with the
  280.  * next decoded scanline.
  281.  */
  282. recvRow += rowSize;
  283. recvEOLCount++;
  284. if (recvRow + rowSize > &buf[RCVBUFSIZ]) {
  285.     flushEncodedData(tif, recvStrip++, buf, recvRow - buf, emsg);
  286.     recvRow = buf;
  287. }
  288.     }
  289. }
  290. free(curGood);
  291. if (seenRTC()) { // RTC found in data stream
  292.     /*
  293.      * Adjust everything to reflect the location
  294.      * at which RTC was found in the data stream.
  295.      */
  296.     copyQualityTrace("Adjusting for RTC found at row %u", getRTCRow());
  297. // # EOL's in recognized RTC
  298.     u_int n = (u_int)(recvEOLCount - getRTCRow());
  299.     if (cblc - n  > recvConsecutiveBadLineCount)
  300. recvConsecutiveBadLineCount = cblc - n;
  301.     if ((recvRow -= n*rowSize) < buf)
  302. recvRow = buf;
  303.     if (n > recvBadLineCount) // deduct RTC
  304. recvBadLineCount = 0;
  305.     else
  306. recvBadLineCount -= n;
  307.     recvEOLCount = getRTCRow(); // adjust row count
  308. } else if (lastRowBad) {
  309.     /*
  310.      * Adjust the received line count to deduce the last
  311.      * consecutive bad line run since the RTC is often not
  312.      * readable and/or is followed by line noise or random
  313.      * junk from the sender.
  314.      */
  315.     copyQualityTrace("Adjusting for trailing noise (%lu run)", cblc);
  316.     if (cblc > recvConsecutiveBadLineCount)
  317. recvConsecutiveBadLineCount = cblc;
  318.     recvEOLCount -= cblc;
  319.     recvBadLineCount -= cblc;
  320.     if ((recvRow -= cblc*rowSize) < buf)
  321. recvRow = buf;
  322. }
  323. recvTrace("%lu total lines, %lu bad lines, %lu consecutive bad lines"
  324.     , recvEOLCount
  325.     , recvBadLineCount
  326.     , recvConsecutiveBadLineCount
  327. );
  328. if (recvRow > &buf[0])
  329.     flushEncodedData(tif, recvStrip, buf, recvRow - buf, emsg);
  330.     } else {
  331. /*
  332.  * Receive a page of data w/o doing copy quality analysis.
  333.  *
  334.  * NB: the image is written as a single strip of data.
  335.  */
  336. setupStartPage(tif, params);
  337. if (params.df == DF_JBIG || params.jp == JP_GREY || params.jp == JP_COLOR) {
  338.     if (params.df != DF_JBIG) {
  339. /*
  340.  * In the case of JPEG we have to buffer it all, alter SOF 
  341.  * after seeing DNL, and then write it to disk... because
  342.  * most JPEG parsers won't know how to handle DNL as it's
  343.  * rather fax-specific.
  344.  */
  345. recvEOLCount = 0;
  346. recvRow = (u_char*) malloc(1024*1000);    // 1M should do it?
  347. fxAssert(recvRow != NULL, "page buffering error (JPEG page).");
  348. recvPageStart = recvRow;
  349.     }
  350.     parserCount[0] = 0;
  351.     parserCount[1] = 0;
  352.     parserCount[2] = 0;
  353.     memset(parserBuf, 0, 16);
  354.     int cc = 0, c;
  355.     bool fin = false;
  356.     if (params.df == DF_JBIG) {
  357. for (; cc < 20; cc++) {
  358.     c = getModemChar(30000);
  359.     if (c == EOF || wasTimeout()) {
  360. fin = true;
  361. break;
  362.     }
  363.     if (c == DLE) {
  364. c = getModemChar(30000);
  365. if (c == EOF || c == ETX || wasTimeout()) {
  366.     fin = true;
  367.     break;
  368. }
  369.     }
  370.     buf[cc] = c;
  371. }
  372. parseJBIGBIH(buf);
  373. flushRawData(tif, 0, (const u_char*) buf, cc, emsg);
  374.     }
  375.     if (!fin) {
  376. do {
  377.     cc = 0;
  378.     do {
  379. c = getModemChar(30000);
  380. if (c == EOF || wasTimeout()) {
  381.     fin = true;
  382.     break;
  383. }
  384. if (c == DLE) {
  385.     c = getModemChar(30000);
  386.     if (c == EOF || c == ETX || wasTimeout()) {
  387. fin = true;
  388. break;
  389.     }
  390. }
  391. if (params.df == DF_JBIG) parseJBIGStream(c);
  392. else parseJPEGStream(c);
  393. buf[cc++] = c;
  394.     } while (cc < RCVBUFSIZ && !fin);
  395.     if (params.df == DF_JBIG) {
  396. flushRawData(tif, 0, (const u_char*) buf, cc, emsg);
  397.     } else {
  398. memcpy(recvRow, (const char*) buf, cc);
  399. recvRow += cc;
  400.     }
  401. } while (!fin);
  402. if (params.df == DF_JBIG) clearSDNORMCount();
  403. else fixupJPEG(tif, emsg);
  404.     }
  405.     if (imagefd > 0) Sys::close(imagefd);
  406.     recvEndPage(tif, params);
  407.     return (true);
  408. }
  409. /*
  410.  * NB: There is a potential memory leak here if the
  411.  * stack buffer gets expanded, such that memory gets
  412.  * malloc'd, and EOF is raised.  In that case the destructor
  413.  * may not be invoked (in fact it almost certainly won't).
  414.  * This is an unlikely scenario so for now we'll leave
  415.  * the code the way it is.
  416.  */
  417. fxStackBuffer raw; // XXX may leak
  418. recvBuf = &raw;
  419. if (!RTCraised()) {
  420.     for (;;) {
  421. raw.reset();
  422. (void) decodeRow(NULL, rowpixels);
  423. if (seenRTC())
  424.     continue;
  425. u_int n = raw.getLength();
  426. if (recvRow + n >= &buf[RCVBUFSIZ]) {
  427.     flushRawData(tif, 0, buf, recvRow - buf, emsg);
  428.     recvRow = buf;
  429. }
  430. if (n >= RCVBUFSIZ)
  431.     flushRawData(tif, 0, (const u_char*) raw, n, emsg);
  432. else {
  433.     memcpy(recvRow, (const char*) raw, n);
  434.     recvRow += n;
  435. }
  436. recvEOLCount++;
  437.     }
  438. }
  439. if (recvRow > &buf[0])
  440.     flushRawData(tif, 0, buf, recvRow - buf, emsg);
  441. if (seenRTC()) { // RTC found in data stream
  442.     /*
  443.      * Adjust the received line count to reflect the
  444.      * location at which RTC was found in the data stream.
  445.      */
  446.     if (params.df == DF_2DMMR) {
  447. copyQualityTrace("Adjusting for EOFB at row %u", getRTCRow());
  448.     } else {
  449. copyQualityTrace("Adjusting for RTC found at row %u", getRTCRow());
  450.     }
  451.     recvEOLCount = getRTCRow();
  452. }
  453.     }
  454.     if (imagefd > 0) Sys::close(imagefd);
  455.     recvEndPage(tif, params);
  456.     return (true);
  457. }
  458. /*
  459.  * Setup "stock TIFF tags" in preparation for receiving a page of data.
  460.  */
  461. void
  462. FaxModem::recvSetupTIFF(TIFF* tif, long, int fillOrder, const fxStr& id)
  463. {
  464.     TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
  465.     TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) params.pageWidth());
  466.     if (params.jp == JP_COLOR || params.jp == JP_GREY) {
  467. TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
  468. #ifdef PHOTOMETRIC_ITULAB
  469. /* If PHOTOMETRIC_ITULAB is not available the admin cannot enable color fax anyway.
  470.    This is done so that older libtiffs without it can build fine. */
  471. TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ITULAB);
  472. #endif
  473. TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  474. // libtiff requires IMAGELENGTH to be set before SAMPLESPERPIXEL, 
  475. // or StripOffsets and StripByteCounts will have SAMPLESPERPIXEL values
  476. TIFFSetField(tif, TIFFTAG_IMAGELENGTH, 2000); // we adjust this later
  477. TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, params.jp == JP_GREY ? 1 : 3);
  478.     } else {
  479. TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
  480. TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
  481. TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
  482. TIFFSetField(tif, TIFFTAG_FILLORDER, (uint16) fillOrder);
  483.     }
  484.     TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
  485.     TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, (uint32) -1);
  486.     TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  487.     TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float) params.horizontalRes());
  488.     TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float) params.verticalRes());
  489.     TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
  490.     TIFFSetField(tif, TIFFTAG_SOFTWARE, HYLAFAX_VERSION);
  491.     TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, (const char*) id);
  492.     char dateTime[24];
  493.     time_t now = Sys::now();
  494.     strftime(dateTime, sizeof (dateTime), "%Y:%m:%d %H:%M:%S", localtime(&now));
  495.     TIFFSetField(tif, TIFFTAG_DATETIME,     dateTime);
  496.     TIFFSetField(tif, TIFFTAG_MAKE,     (const char*) getManufacturer());
  497.     TIFFSetField(tif, TIFFTAG_MODEL,     (const char*) getModel());
  498.     TIFFSetField(tif, TIFFTAG_HOSTCOMPUTER, (const char*) server.hostname);
  499. }
  500. /*
  501.  * Setup the compression scheme and related tags.
  502.  */
  503. static void
  504. setupCompression(TIFF* tif, u_int df, u_int jp, uint32 opts)
  505. {
  506.     u_int dataform = df + (jp ? jp + 4 : 0);
  507.     switch (dataform) {
  508. case JP_GREY+4:
  509. case JP_COLOR+4:
  510.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
  511.     break;
  512. case DF_JBIG:
  513.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_JBIG);
  514.     break;
  515. case DF_2DMMR:
  516.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
  517.     TIFFSetField(tif, TIFFTAG_GROUP4OPTIONS, opts);
  518.     break;
  519. case DF_2DMRUNCOMP:
  520.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
  521.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS,
  522. opts | GROUP3OPT_2DENCODING|GROUP3OPT_UNCOMPRESSED);
  523.     break;
  524. case DF_2DMR:
  525.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
  526.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS, opts | GROUP3OPT_2DENCODING);
  527.     break;
  528. case DF_1DMH:
  529.     TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
  530.     TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS, opts &~ GROUP3OPT_2DENCODING);
  531.     break;
  532.     }
  533. }
  534. /*
  535.  * Write a strip of decoded data to the receive file.
  536.  */
  537. void
  538. FaxModem::flushEncodedData(TIFF* tif, tstrip_t strip, const u_char* buf, u_int cc, fxStr& emsg)
  539. {
  540.     if (imagefd > 0) Sys::write(imagefd, (const char*) buf, cc);
  541.     // NB: must update ImageLength for each new strip
  542.     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, recvEOLCount);
  543.     if (TIFFWriteEncodedStrip(tif, strip, (tdata_t)buf, cc) == -1) {
  544. serverTrace("RECV: %s: write error", TIFFFileName(tif));
  545.         abortPageRecv();
  546.         emsg = "Write error to TIFF file {E052}";
  547.     }
  548. }
  549. /*
  550.  * Write a strip of raw data to the receive file.
  551.  */
  552. void
  553. FaxModem::flushRawData(TIFF* tif, tstrip_t strip, const u_char* buf, u_int cc, fxStr& emsg)
  554. {
  555.     if (imagefd > 0) Sys::write(imagefd, (const char*) buf, cc);
  556.     recvTrace("%u bytes of data, %lu total lines", cc, recvEOLCount);
  557.     if (TIFFWriteRawStrip(tif, strip, (tdata_t)buf, cc) == -1) {
  558. serverTrace("RECV: %s: write error", TIFFFileName(tif));
  559.         abortPageRecv();
  560.         emsg = "Write error to TIFF file {E052}";
  561.     }
  562. }
  563. void
  564. FaxModem::clearSDNORMCount()
  565. {
  566.     if (parserCount[1]) {
  567. copyQualityTrace("Found %d SDNORM Marker Segments in BID", parserCount[1]);
  568. parserCount[1] = 0;
  569.     }
  570. }
  571. void
  572. FaxModem::parseJBIGStream(u_char c)
  573. {
  574.     /*
  575.      * parserCount[n]
  576.      *   n = 0, bytes since last marker
  577.      *   n = 1, SDNORM marker counter
  578.      *   n = 2, framelength bypass countdown
  579.      */
  580.     parserCount[0]++;
  581.     if (parserCount[2]) {
  582. // just skipping bytes
  583. parserCount[2]--;
  584. return;
  585.     }
  586.     for (u_short i = 15; i > 0; i--) parserBuf[i] = parserBuf[i-1];
  587.     parserBuf[0] = c;
  588.     u_long framelength = 0;
  589.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x04) {
  590. clearSDNORMCount();
  591. copyQualityTrace("Found ABORT Marker Segment in BID");
  592. parserCount[0] = 0;
  593. return;
  594.     }
  595.     if (parserCount[0] >= 8 && parserBuf[7] == 0xFF && parserBuf[6] == 0x06) {
  596. clearSDNORMCount();
  597. copyQualityTrace("Found ATMOVE Marker Segment in BID, Yat %d, tx %d, ty %d", 
  598.     256*256*256*parserBuf[5]+256*256*parserBuf[4]+256*parserBuf[3]+parserBuf[2], parserBuf[1], parserBuf[0]);
  599. parserCount[0] = 0;
  600. return;
  601.     }
  602.     if (parserCount[0] >= 6 && parserBuf[5] == 0xFF && parserBuf[4] == 0x07) {
  603. clearSDNORMCount();
  604. parserCount[2] = 256*256*256*parserBuf[3]+256*256*parserBuf[2]+256*parserBuf[1]+parserBuf[0];
  605. copyQualityTrace("Found COMMENT Marker Segment in BID");
  606. parserCount[0] = 0;
  607. return;
  608.     }
  609.     if (parserCount[0] >= 6 && parserBuf[5] == 0xFF && parserBuf[4] == 0x05) {
  610. clearSDNORMCount();
  611. framelength = 256*256*256*parserBuf[3];
  612. framelength += 256*256*parserBuf[2];
  613. framelength += 256*parserBuf[1];
  614. framelength += parserBuf[0];
  615. copyQualityTrace("Found NEWLEN Marker Segment in BID, Yd = %d", framelength);
  616. // T.82: "The new Yd shall never be greater than the original"
  617. if (framelength < 65535 && (!recvEOLCount || framelength < recvEOLCount)) recvEOLCount = framelength;
  618. parserCount[0] = 0;
  619. return;
  620.     }
  621.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x01) {
  622. clearSDNORMCount();
  623. copyQualityTrace("Found RESERVE Marker Segment in BID");
  624. parserCount[0] = 0;
  625. return;
  626.     }
  627.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x02) {
  628. parserCount[1]++; // SDNORM
  629. parserCount[0] = 0;
  630. return;
  631.     }
  632.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x03) {
  633. clearSDNORMCount();
  634. copyQualityTrace("Found SDRST Marker Segment in BID");
  635. parserCount[0] = 0;
  636. return;
  637.     }
  638. }
  639. void
  640. FaxModem::parseJBIGBIH(u_char* buf)
  641. {
  642.     copyQualityTrace("BIH: Dl %d, D %d, P %d, fill %d", buf[0], buf[1], buf[2], buf[3]);
  643.     /*
  644.      * Parse JBIG BIH to get the image length.
  645.      *
  646.      * See T.82 6.6.2
  647.      * These three integers are coded most significant byte first. In
  648.      * other words, XD is the sum of 256^3 times the fifth byte in BIH, 256^2
  649.      * times the sixth byte, 256 times the seventh byte, and the eighth byte.
  650.      */
  651.     u_long framelength = 0;
  652.     framelength = 256*256*256*buf[8];
  653.     framelength += 256*256*buf[9];
  654.     framelength += 256*buf[10];
  655.     framelength += buf[11];
  656.     /*
  657.      * Senders commonly use 0xFFFF and 0xFFFFFFFF as "maximum Yd".  We ignore such large 
  658.      * values because if we use them and no NEWLEN marker is received, then the page
  659.      * length causes problems for viewers (specifically libtiff).
  660.      */
  661.     if (framelength < 65535 && framelength > recvEOLCount) recvEOLCount = framelength;
  662.     copyQualityTrace("BIH: Xd %d, Yd %d, L0 %d, Mx %d, My %d",
  663. 256*256*256*buf[4]+256*256*buf[5]+256*buf[6]+buf[7],
  664. framelength,
  665. 256*256*256*buf[12]+256*256*buf[13]+256*buf[14]+buf[15],
  666. buf[16], buf[17]);
  667.     copyQualityTrace("BIH: fill %d, HITOLO %d, SEQ %d, ILEAVE %d, SMID %d", 
  668. (buf[18]&0xF0)>>4, (buf[18]&0x8)>>3, (buf[18]&0x4)>>2, (buf[18]&0x2)>>1, buf[18]&0x1);
  669.     copyQualityTrace("BIH: fill %d, LRLTWO %d, VLENGTH %d, TPDON %d, TPBON %d, DPON %d, DPPRIV %u, DPLAST %u", 
  670. (buf[19]&0x80)>>7, (buf[19]&0x40)>>6, (buf[19]&0x20)>>5, (buf[19]&0x10)>>4, (buf[19]&0x8)>>3, 
  671. (buf[19]&0x4)>>2, (buf[19]&0x2)>>1, buf[19]&0x1);
  672. }
  673. void
  674. FaxModem::parseJPEGStream(u_char c)
  675. {
  676.     /*
  677.      * parserCount[n]
  678.      *   n = 0, bytes since last marker
  679.      *   n = 1, framelength bypass countdown
  680.      */
  681.     parserCount[0]++;
  682.     if (parserCount[1]) {
  683. // just skipping bytes
  684. parserCount[1]--;
  685. return;
  686.     }
  687.     for (u_short i = 15; i > 0; i--) parserBuf[i] = parserBuf[i-1];
  688.     parserBuf[0] = c;
  689.     u_long framelength = 0, framewidth = 0, fsize = 0;
  690.     if (parserCount[0] >= 9 && parserBuf[8] == 0xFF && parserBuf[7] >= 0xC0 && parserBuf[7] <= 0xCF 
  691. && parserBuf[7] != 0xC4 && parserBuf[7] != 0xC8 && parserBuf[7] != 0xCC) {
  692. u_short type = parserBuf[7] - 0xC0;
  693. fsize = 256*parserBuf[6];
  694. fsize += parserBuf[5];
  695. framelength = 256*parserBuf[3];
  696. framelength += parserBuf[2];
  697. framewidth = 256*parserBuf[1];
  698. framewidth += parserBuf[0];
  699. copyQualityTrace("Found Start of Frame (SOF%u) Marker, size: %lu x %lu", type, framewidth, framelength);
  700. if (framelength < 65535 && framelength > recvEOLCount) recvEOLCount = framelength;
  701. parserCount[1] = fsize - 9;
  702. parserCount[0] = 0;
  703. return;
  704.     }
  705.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0xC8) {
  706. copyQualityTrace("Found JPEG Extensions (JPG) Marker");
  707. parserCount[0] = 0;
  708. return;
  709.     }
  710.     if (parserCount[0] >= 4 && parserBuf[3] == 0xFF && parserBuf[2] == 0xC4) {
  711. fsize = 256*parserBuf[1];
  712. fsize += parserBuf[0];
  713. copyQualityTrace("Found Define Huffman Tables (DHT) Marker");
  714. parserCount[1] = fsize - 4;
  715. parserCount[0] = 0;
  716. return;
  717.     }
  718.     if (parserCount[0] >= 4 && parserBuf[3] == 0xFF && parserBuf[2] == 0xCC) {
  719. fsize = 256*parserBuf[1];
  720. fsize += parserBuf[0];
  721. copyQualityTrace("Found Define Arithmatic Coding Conditionings (DAC) Marker");
  722. parserCount[1] = fsize - 4;
  723. parserCount[0] = 0;
  724. return;
  725.     }
  726.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] >= 0xD0 && parserBuf[0] <= 0xD7) {
  727. copyQualityTrace("Found Restart (RST) Marker");
  728. parserCount[0] = 0;
  729. return;
  730.     }
  731.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0xD8) {
  732. copyQualityTrace("Found Start of Image (SOI) Marker");
  733. parserCount[0] = 0;
  734. return;
  735.     }
  736.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0xD9) {
  737. copyQualityTrace("Found End of Image (EOI) Marker");
  738. parserCount[0] = 0;
  739. return;
  740.     }
  741.     if (parserCount[0] >= 4 && parserBuf[3] == 0xFF && parserBuf[2] == 0xDA) {
  742. fsize = 256*parserBuf[1];
  743. fsize += parserBuf[0];
  744. copyQualityTrace("Found Start of Scan (SOS) Marker");
  745. parserCount[1] = fsize - 4;
  746. parserCount[0] = 0;
  747. return;
  748.     }
  749.     if (parserCount[0] >= 4 && parserBuf[3] == 0xFF && parserBuf[2] == 0xDB) {
  750. fsize = 256*parserBuf[1];
  751. fsize += parserBuf[0];
  752. copyQualityTrace("Found Define Quantization Tables (DQT) Marker");
  753. parserCount[1] = fsize - 4;
  754. parserCount[0] = 0;
  755. return;
  756.     }
  757.     if (parserCount[0] >= 6 && parserBuf[5] == 0xFF && parserBuf[4] == 0xDC) {
  758. fsize = 256*parserBuf[3];
  759. fsize += parserBuf[2];
  760. framelength = 256*parserBuf[1];
  761. framelength += parserBuf[0];
  762. copyQualityTrace("Found Define Number of Lines (DNL) Marker, lines: %lu", framelength);
  763. if (framelength < 65535) recvEOLCount = framelength;
  764. parserCount[1] = fsize - 6;
  765. parserCount[0] = 0;
  766. return;
  767.     }
  768.     if (parserCount[0] >= 4 && parserBuf[3] == 0xFF && parserBuf[2] == 0xDD) {
  769. fsize = 256*parserBuf[1];
  770. fsize += parserBuf[0];
  771. copyQualityTrace("Found Define Restart Interval (DRI) Marker");
  772. parserCount[1] = fsize - 4;
  773. parserCount[0] = 0;
  774. return;
  775.     }
  776.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0xDE) {
  777. copyQualityTrace("Found Define Hierarchial Progression (DHP) Marker");
  778. parserCount[0] = 0;
  779. return;
  780.     }
  781.     if (parserCount[0] >= 4 && parserBuf[3] == 0xFF && parserBuf[2] == 0xDF) {
  782. fsize = 256*parserBuf[1];
  783. fsize += parserBuf[0];
  784. copyQualityTrace("Found Expand Reference Components (EXP) Marker");
  785. parserCount[1] = fsize - 4;
  786. parserCount[0] = 0;
  787. return;
  788.     }
  789.     if (parserCount[0] >= 4 && parserBuf[3] == 0xFF && parserBuf[2] >= 0xE0 && parserBuf[2] <= 0xEF) {
  790. u_short type = parserBuf[2] - 0xE0;
  791. fsize = 256*parserBuf[1];
  792. fsize += parserBuf[0];
  793. copyQualityTrace("Found Application Segment (APP%u) Marker", type);
  794. parserCount[1] = fsize - 4;
  795. parserCount[0] = 0;
  796. return;
  797.     }
  798.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] >= 0xF0 && parserBuf[0] <= 0xFD) {
  799. u_short type = parserBuf[0] - 0xF0;
  800. copyQualityTrace("Found JPEG Extension (JPG%u) Marker", type);
  801. parserCount[0] = 0;
  802. return;
  803.     }
  804.     if (parserCount[0] >= 4 && parserBuf[3] == 0xFF && parserBuf[2] == 0xFE) {
  805. fsize = 256*parserBuf[1];
  806. fsize += parserBuf[0];
  807. copyQualityTrace("Found Comment (COM) Marker");
  808. parserCount[1] = fsize - 4;
  809. parserCount[0] = 0;
  810. return;
  811.     }
  812.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] == 0x01) {
  813. copyQualityTrace("Found Temporary Private Use (TEM) Marker");
  814. parserCount[0] = 0;
  815. return;
  816.     }
  817.     if (parserCount[0] >= 2 && parserBuf[1] == 0xFF && parserBuf[0] >= 0x02 && parserBuf[0] <= 0xBF) {
  818. copyQualityTrace("Found Reserved (RES) Marker 0x%X", parserBuf[0]);
  819. parserCount[0] = 0;
  820. return;
  821.     }
  822. }
  823. void
  824. FaxModem::fixupJPEG(TIFF* tif, fxStr& emsg)
  825. {
  826.     if (!recvEOLCount) {
  827. /*
  828.  * We didn't detect an image length marker (DNL/NEWLEN).  So
  829.  * we use the session parameters to guess at one, and we hope that
  830.  * the eventual viewing decoder can cope with things if the data
  831.  * is short.
  832.  *
  833.  * This approach doesn't seem to work with JBIG, so for now we only do it with JPEG.
  834.  */
  835. u_int len, res;
  836. switch (params.ln) {
  837.     case LN_A4: len = 297; break;
  838.     default: len = 364; break; // LN_INF, LN_B4
  839. }
  840. switch (params.vr) { // values in mm/100 to avoid floats
  841.     case VR_NORMAL: res = 385; break;
  842.     case VR_FINE: res = 770; break;
  843.     case VR_200X100: res = 394; break;
  844.     case VR_200X200: res = 787; break;
  845.     case VR_200X400: res = 1575; break;
  846.     case VR_300X300: res = 1181; break;
  847.     default: res = 1540; break; // VR_R16, VR_R8
  848. }
  849. recvEOLCount = (u_long) ((len * res) / 100);
  850. protoTrace("RECV: assumed image length of %lu lines", recvEOLCount);
  851.     }
  852.     /*
  853.      * DNL markers generally are not usable in TIFF files.  Furthermore,
  854.      * many TIFF viewers cannot use them, either.  So, we go back 
  855.      * through the strip and replace any "zero" image length attributes
  856.      * of any SOF markers with recvEOLCount.  Perhaps we should strip
  857.      * out the DNL marker entirely, but leaving it in seems harmless.
  858.      */
  859.     u_long pagesize = recvRow - recvPageStart;
  860.     recvRow = recvPageStart;
  861.     for (uint32 i = 0; i < (pagesize - 6); i++) {
  862. if (recvRow[i] == 0xFF && recvRow[i+1] == 0xC0 && recvRow[i+5] == 0x00 && recvRow[i+6] == 0x00) {
  863.     recvRow[i+5] = recvEOLCount >> 8;
  864.     recvRow[i+6] = recvEOLCount & 0xFF;
  865.     protoTrace("RECV: fixing zero image frame length in SOF marker at byte %lu to %lu", i, recvEOLCount);
  866. }
  867.     }
  868.     if (TIFFWriteRawStrip(tif, 0, (tdata_t) recvRow, pagesize) == -1) {
  869. serverTrace("RECV: %s: write error", TIFFFileName(tif));
  870.         abortPageRecv();
  871.         emsg = "Write error to TIFF file {E052}";
  872.     }
  873.     free(recvRow);
  874. }
  875. /*
  876.  * In ECM mode the ECM module provides the line-counter.
  877.  */
  878. void
  879. FaxModem::writeECMData(TIFF* tif, u_char* buf, u_int cc, const Class2Params& params, u_short seq, fxStr& emsg)
  880. {
  881.     /*
  882.      * Start a decoding child process to which the parent pipes the image data 
  883.      * through a decoding pipe.  The child will return the line count back 
  884.      * through a second counting pipe.  The fork is only executed on the first 
  885.      * block, and the child exits after returning the line count after the last
  886.      * block.  In-between blocks merely dump data into the pipe.
  887.      */
  888.     u_int dataform = params.df + (params.jp ? params.jp + 4 : 0);
  889.     char cbuf[4]; // size of the page count signal
  890.     if (seq & 1) { // first block
  891. switch (dataform) {
  892.     case DF_1DMH:
  893.     case DF_2DMR:
  894.     case DF_2DMMR:
  895. {
  896.     decoderFd[1] = -1;
  897.     initializeDecoder(params);
  898.     setupStartPage(tif, params);
  899.     u_int rowpixels = params.pageWidth(); // NB: assume rowpixels <= 4864
  900.     recvBuf = NULL; // just count lines, don't save it
  901.     if (pipe(decoderFd) >= 0 && pipe(counterFd) >= 0) {
  902. setDecoderFd(decoderFd[0]);
  903. decoderPid = fork();
  904. switch (decoderPid) {
  905.     case -1: // error
  906. recvTrace("Could not fork decoding.");
  907. Sys::close(decoderFd[0]);
  908. Sys::close(decoderFd[1]);
  909. Sys::close(counterFd[0]);
  910. Sys::close(counterFd[1]);
  911. break;
  912.     case 0: // child
  913. Sys::close(decoderFd[1]);
  914. Sys::close(counterFd[0]);
  915. setIsECM(true); // point decoder to the pipe rather than the modem for data
  916. if (!EOFraised() && !RTCraised()) {
  917.     for (;;) {
  918. (void) decodeRow(NULL, rowpixels);
  919. if (seenRTC()) {
  920.     break;
  921. }
  922. recvEOLCount++;
  923.     }
  924. }
  925. if (seenRTC()) { // RTC found in data stream
  926.     if (params.df == DF_2DMMR) {
  927. /*
  928.  * In the case of MMR, it's not really RTC, but EOFB.
  929.  * However, we don't actually *find* EOFB, but rather we
  930.  * wait for the first line decoding error and assume it
  931.  * to be EOFB.  This is safe because MMR data after a
  932.  * corrupted line is useless anyway.
  933.  */
  934. copyQualityTrace("Adjusting for EOFB at row %u", getRTCRow());
  935.     } else
  936. copyQualityTrace("Adjusting for RTC found at row %u", getRTCRow());
  937.     recvEOLCount = getRTCRow();
  938. }
  939. // write the line count to the pipe
  940. Sys::write(counterFd[1], (const char*) &recvEOLCount, sizeof(recvEOLCount));
  941. _exit(0);
  942.     default: // parent
  943. Sys::close(decoderFd[0]);
  944. Sys::close(counterFd[1]);
  945. break;
  946. }
  947.     } else {
  948. recvTrace("Could not open decoding pipe.");
  949.     }
  950. }
  951. break;
  952.     case DF_JBIG:
  953. {
  954.     setupStartPage(tif, params);
  955.     parseJBIGBIH(buf);
  956.     parserCount[0] = 0;
  957.     parserCount[1] = 0;
  958.     parserCount[2] = 0;
  959.     memset(parserBuf, 0, 16);
  960. }
  961. break;
  962.     case JP_GREY+4:
  963.     case JP_COLOR+4:
  964. recvEOLCount = 0;
  965. recvRow = (u_char*) malloc(1024*1000);    // 1M should do it?
  966. fxAssert(recvRow != NULL, "page buffering error (JPEG page).");
  967. recvPageStart = recvRow;
  968. setupStartPage(tif, params);
  969. parserCount[0] = 0;
  970. parserCount[1] = 0;
  971. parserCount[2] = 0;
  972. memset(parserBuf, 0, 16);
  973. break;
  974. }
  975.     }
  976.     switch (dataform) {
  977. case DF_1DMH:
  978. case DF_2DMR:
  979. case DF_2DMMR:
  980.     {
  981. if (decoderFd[1] != -1) { // only if pipe succeeded
  982.     for (u_int i = 0; i < cc; i++) {
  983. cbuf[0] = 0x00; // data marker
  984. cbuf[1] = buf[i];
  985. Sys::write(decoderFd[1], cbuf, 2);
  986.     }
  987. }
  988. if (decoderFd[1] != -1 && seq & 2) { // last block
  989.     cbuf[0] = 0xFF; // this signals...
  990.     cbuf[1] = 0xFF; // ... end of data
  991.     Sys::write(decoderFd[1], cbuf, 2);
  992.     // read the page count from the counter pipe
  993.     Sys::read(counterFd[0], (char*) &recvEOLCount, sizeof(recvEOLCount));
  994.     (void) Sys::waitpid(decoderPid);
  995.     Sys::close(decoderFd[1]);
  996.     Sys::close(counterFd[0]);
  997. }
  998.     }
  999.     break;
  1000. case DF_JBIG:
  1001. case JP_GREY+4:
  1002. case JP_COLOR+4:
  1003.     // search for Marker Segments in Image Data
  1004.     {
  1005. u_int i = 0;
  1006. if ((dataform == DF_JBIG) && (seq & 1)) i += 20; // skip BIH
  1007. for (; i < cc; i++) {
  1008.     if (dataform == DF_JBIG) parseJBIGStream(buf[i]);
  1009.     else parseJPEGStream(buf[i]);
  1010. }
  1011. if (dataform == DF_JBIG) clearSDNORMCount();
  1012.     }
  1013.     break;
  1014.     }
  1015.     if (params.jp != JP_GREY && params.jp != JP_COLOR) {
  1016. flushRawData(tif, 0, (const u_char*) buf, cc, emsg);
  1017.     } else {
  1018. memcpy(recvRow, (const char*) buf, cc);
  1019. recvRow += cc;
  1020.     }
  1021.     if (seq & 2 && (params.jp == JP_GREY || params.jp == JP_COLOR)) {
  1022. fixupJPEG(tif, emsg);
  1023.     }
  1024. }
  1025. /*
  1026.  * Check if the configuration parameters indicate if
  1027.  * copy quality checking should be done on recvd pages.
  1028.  */
  1029. bool
  1030. FaxModem::checkQuality()
  1031. {
  1032.     return (conf.percentGoodLines != 0 && conf.maxConsecutiveBadLines != 0);
  1033. }
  1034. /*
  1035.  * Check the statistics accumulated during a page recived
  1036.  * against the configuration parameters and return an
  1037.  * indication of whether or not the page quality is acceptable.
  1038.  */
  1039. bool
  1040. FaxModem::isQualityOK(const Class2Params& params)
  1041. {
  1042.     if (conf.percentGoodLines != 0 && recvEOLCount != 0) {
  1043. u_long percent = 100 * (recvEOLCount - recvBadLineCount) / recvEOLCount;
  1044. if (percent < conf.percentGoodLines) {
  1045.     serverTrace("RECV: REJECT page quality, %u%% good lines (%u%% required)",
  1046. percent, conf.percentGoodLines);
  1047.     return (false);
  1048. }
  1049.     }
  1050.     u_int cblc = conf.maxConsecutiveBadLines;
  1051.     if (cblc != 0) {
  1052. if (params.vr == VR_FINE)
  1053.     cblc *= 2;
  1054. if (recvConsecutiveBadLineCount > cblc) {
  1055.     serverTrace("RECV: REJECT page quality, %u-line run (max %u)",
  1056. recvConsecutiveBadLineCount, cblc);
  1057.     return (false);
  1058. }
  1059.     }
  1060.     if (recvEOLCount == 0 || recvEOLCount < conf.minAcceptedLineCount) {
  1061. serverTrace("RECV: REJECT page quality, too few scanlines: %u",
  1062.     recvEOLCount);
  1063. return (false);
  1064.     }
  1065.     return (true);
  1066. }
  1067. /*
  1068.  * Return the next decoded byte of page data.
  1069.  */
  1070. int
  1071. FaxModem::nextByte()
  1072. {
  1073.     int b;
  1074.     if (getIsECM()) {
  1075. char buf[2];
  1076. decoderFd[0] = getDecoderFd();
  1077. while (Sys::read(decoderFd[0], buf, 2) < 1);
  1078. if (((unsigned) buf[0] & 0xFF) == 0xFF) raiseEOF();
  1079. b = (unsigned) buf[1] & 0xFF;
  1080.     } else {
  1081. if (bytePending & 0x100) {
  1082.     b = bytePending & 0xff;
  1083.     bytePending = 0;
  1084. } else {
  1085.     b = getModemDataChar();
  1086.     if (b == EOF) {
  1087. raiseEOF();
  1088.     }
  1089. }
  1090. if (b == DLE) {
  1091.     switch (b = getModemDataChar()) {
  1092.     case EOF: raiseEOF();
  1093.     case ETX: raiseRTC();
  1094.     case DLE: break; // <DLE><DLE> -> <DLE>
  1095.     default:
  1096. bytePending = b | 0x100;
  1097. b = DLE;
  1098. break;
  1099.     }
  1100. }
  1101.     }
  1102.     b = getBitmap()[b];
  1103.     if (recvBuf) // record raw data
  1104. recvBuf->put(b);
  1105.     return (b);
  1106. }
  1107. u_long FaxModem::getRecvEOLCount() const
  1108.     { return recvEOLCount; }
  1109. u_long FaxModem::getRecvBadLineCount() const
  1110.     { return recvBadLineCount; }
  1111. u_long FaxModem::getRecvConsecutiveBadLineCount() const
  1112.     { return recvConsecutiveBadLineCount; }
  1113. /*
  1114.  * Trace a protocol-receive related activity.
  1115.  */
  1116. void
  1117. FaxModem::recvTrace(const char* fmt ...)
  1118. {
  1119.     va_list ap;
  1120.     va_start(ap, fmt);
  1121.     static const fxStr recv("RECV: ");
  1122.     server.vtraceStatus(FAXTRACE_PROTOCOL, recv | fmt, ap);
  1123.     va_end(ap);
  1124. }
  1125. /*
  1126.  * Note an invalid G3 code word.
  1127.  */
  1128. void
  1129. FaxModem::invalidCode(const char* type, int x)
  1130. {
  1131.     if (!seenRTC())
  1132. copyQualityTrace("Invalid %s code word, row %u, x %d",
  1133.     type, getReferenceRow(), x);
  1134. }
  1135. /*
  1136.  * Note a row decode that gives the wrong pixel count.
  1137.  */
  1138. void
  1139. FaxModem::badPixelCount(const char* type, int got, int expected)
  1140. {
  1141.     if (!seenRTC()) {
  1142. copyQualityTrace("Bad %s pixel count, row %u, got %d, expected %d",
  1143.     type, getReferenceRow(), got, expected);
  1144. decodedPixels = got;
  1145.     }
  1146. }
  1147. void
  1148. FaxModem::badDecodingState(const char* type, int x)
  1149. {
  1150.     copyQualityTrace("Panic, bad %s decoding state, row %u, x %d",
  1151. type, getReferenceRow(), x);
  1152. }
  1153. /*
  1154.  * Trace a copy quality-reated activity.
  1155.  */
  1156. void
  1157. FaxModem::copyQualityTrace(const char* fmt ...)
  1158. {
  1159.     va_list ap;
  1160.     va_start(ap, fmt);
  1161.     static const fxStr cq("RECV/CQ: ");
  1162.     server.vtraceStatus(FAXTRACE_COPYQUALITY, cq | fmt, ap);
  1163.     va_end(ap);
  1164. }