Hylafax Developers Mailing List Archives
|
[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
[hylafax-devel] new (I hope complete) RTN fixes
With a help of Harald Pollack from Austria I have found 2 new (3 total)
bugs in Hylafax, that can potentially lead to the RTN failure (byte-aligned
first EOL, extra RTC in the TIFF file, extra RTC send by Hylafax in Class
2.0 mode). All of them have hopefully been fixed (for both Class1 and
Class2/2.0) -- those Canon machines now respond with normal and proper and
of connection :-)
Here is my fixes; they should be applied to the fresh 4.1beta2. You should
also ./configure after applying them (to update faxd/Makefile).
Some people except me are already testing the fixes (Bernd Proissl and
others). They tell the RTN bug is over :-)
I also post my discussion with Mr. Pollack in hope that it may be
interesting for somebody.
Hope to hear from you soon,
Dmitry
diff -uNr hylafax-4.1beta2.orig/faxd/Class1Send.c++ hylafax-4.1beta2/faxd/Class1Send.c++
--- hylafax-4.1beta2.orig/faxd/Class1Send.c++ Sun Jun 13 11:41:00 1999
+++ hylafax-4.1beta2/faxd/Class1Send.c++ Mon Mar 27 12:40:59 2000
@@ -733,6 +733,12 @@
totdata = totdata+ts - (dp-data);
} else
dp = data;
+
+ /*
+ * correct broken Phase C (T.4) data if neccessary
+ */
+ correctPhaseCData(dp, &totdata, fillorder, params);
+
/*
* Send the page of data. This is slightly complicated
* by the fact that we may have to add zero-fill before the
diff -uNr hylafax-4.1beta2.orig/faxd/Class20.c++ hylafax-4.1beta2/faxd/Class20.c++
--- hylafax-4.1beta2.orig/faxd/Class20.c++ Sun Jun 13 11:41:01 1999
+++ hylafax-4.1beta2/faxd/Class20.c++ Fri Mar 24 18:36:17 2000
@@ -131,7 +131,7 @@
bool rc = sendPageData(tif, pageChop);
if (!rc)
abortDataTransfer();
- else
+ else if( conf.class2SendRTC )
rc = sendRTC(params.is2D());
if (flowControl == FLOW_XONXOFF)
setXONXOFF(getInputFlow(), FLOW_XONXOFF, ACT_DRAIN);
@@ -162,12 +162,24 @@
case AT_FHNG:
if (!isNormalHangup())
return (false);
- /* fall thru... */
- case AT_OK: // page data good
- ppr = PPR_MCF; // could be PPR_RTP/PPR_PIP
+ ppr = PPR_MCF;
return (true);
- case AT_ERROR: // page data bad
- ppr = PPR_RTN; // could be PPR_PIN
+ case AT_OK:
+ case AT_ERROR:
+ /*
+ * Despite of the (wrong) comment above,
+ * we do explicit status query e.g. to
+ * distinguish between RTN and PIN
+ */
+ {
+ fxStr s;
+ if(!atQuery("AT+FPS?", s) ||
+ sscanf(s, "%u", &ppr) != 1){
+ protoTrace("MODEM protocol botch (\"%s\"), %s",
+ (char*)s, "can not parse PPR");
+ return (false); // force termination
+ }
+ }
return (true);
case AT_EMPTYLINE:
case AT_TIMEOUT:
diff -uNr hylafax-4.1beta2.orig/faxd/Class2Send.c++ hylafax-4.1beta2/faxd/Class2Send.c++
--- hylafax-4.1beta2.orig/faxd/Class2Send.c++ Sun Jun 13 11:41:01 1999
+++ hylafax-4.1beta2/faxd/Class2Send.c++ Mon Mar 27 18:24:46 2000
@@ -387,6 +387,12 @@
totdata = totdata+ts - (dp-data);
} else
dp = data;
+
+ /*
+ * correct broken Phase C (T.4) data if neccessary
+ */
+ correctPhaseCData(dp, &totdata, fillorder, params);
+
beginTimedTransfer();
rc = putModemDLEData(dp, (u_int) totdata, bitrev, getDataTimeout());
endTimedTransfer();
diff -uNr hylafax-4.1beta2.orig/faxd/FaxModem.c++ hylafax-4.1beta2/faxd/FaxModem.c++
--- hylafax-4.1beta2.orig/faxd/FaxModem.c++ Sun Jun 13 11:41:03 1999
+++ hylafax-4.1beta2/faxd/FaxModem.c++ Mon Mar 27 12:47:04 2000
@@ -624,3 +624,186 @@
if (curreq)
server.notifyPageSent(*curreq, TIFFFileName(tif));
}
+
+/*
+ * Phase C data correction
+ */
+
+#include "G3Decoder.h"
+#include "G3Encoder.h"
+#include "StackBuffer.h"
+#include "Class2Params.h"
+
+class MemoryDecoder : public G3Decoder {
+private:
+ u_char* bp;
+ u_int width;
+ u_int byteWidth;
+ u_long cc;
+
+ u_int fillorder;
+ bool is2D;
+
+ u_char* endOfData; // used by cutExtraRTC
+
+ uint16* runs;
+ u_char* rowBuf;
+
+ int decodeNextByte();
+public:
+ MemoryDecoder(u_char* data, u_int wid, u_long n,
+ u_int fillorder, bool twoDim);
+ ~MemoryDecoder();
+ u_char* current() { return bp; }
+ void fixFirstEOL();
+ u_char* cutExtraRTC();
+};
+
+MemoryDecoder::MemoryDecoder(u_char* data, u_int wid, u_long n,
+ u_int order, bool twoDim)
+{
+ bp = data;
+ width = wid;
+ byteWidth = howmany(width, 8);
+ cc = n;
+
+ fillorder = order;
+ is2D = twoDim;
+
+ runs = new uint16[2*width]; // run arrays for cur+ref rows
+ rowBuf = new u_char[byteWidth];
+ setupDecoder(fillorder, is2D);
+ setRuns(runs, runs+width, width);
+}
+MemoryDecoder::~MemoryDecoder()
+{
+ delete rowBuf;
+ delete runs;
+}
+
+int
+MemoryDecoder::decodeNextByte()
+{
+ if (cc == 0)
+ raiseRTC(); // XXX don't need to recognize EOF
+ cc--;
+ return (*bp++);
+}
+
+#ifdef roundup
+#undef roundup
+#endif
+#define roundup(a,b) ((((a)+((b)-1))/(b))*(b))
+
+/*
+ * TIFF Class F specs say:
+ *
+ * "As illustrated in FIGURE 1/T.4 in Recommendation T.4 (the Red
+ * Book, page 20), facsimile documents begin with an EOL (which in
+ * Class F is byte-aligned)..."
+ *
+ * This is wrong! "Byte-aligned" first EOL means extra zero bits
+ * which are not allowed by T.4. Reencode first row to fix this
+ * "byte-alignment".
+ */
+void MemoryDecoder::fixFirstEOL()
+{
+ fxStackBuffer result;
+ G3Encoder enc(result);
+ enc.setupEncoder(fillorder, is2D);
+
+ memset(rowBuf, 0, byteWidth*sizeof(u_char)); // clear row to white
+ if(!RTCraised()) {
+ u_char* start = current();
+ (void)decodeRow(rowBuf, width);
+ /*
+ * syncronize to the next EOL and calculate pointer to it
+ * (see detailed explanation of look_ahead in TagLine.c++)
+ */
+ (void)isNextRow1D();
+ u_int look_ahead = roundup(getPendingBits(),8) / 8;
+ u_int decoded = current() - look_ahead - start;
+
+ enc.encode(rowBuf, width, 1);
+ u_int encoded = result.getLength();
+
+ while( encoded < decoded ){
+ result.put((char) 0);
+ encoded++;
+ }
+ if( encoded == decoded ){
+ memcpy(start, (u_char*)result, encoded);
+ }
+ }
+}
+
+
+/*
+ * TIFF Class F specs say:
+ *
+ * "Aside from EOL's, TIFF Class F files contain only image data. This
+ * means that the Return To Control sequence (RTC) is specifically
+ * prohibited..."
+ *
+ * Nethertheless Ghostscript and possibly other TIFF Class F writers
+ * append RTC or single EOL to the last encoded line. Remove them.
+ */
+u_char* MemoryDecoder::cutExtraRTC()
+{
+ u_char* start = current();
+
+ /*
+ * We expect RTC near the end of data and thus
+ * do not check all image to save processing time.
+ * It's safe because we will resync on the first
+ * encountered EOL.
+ *
+ * NB: We expect G3Decoder::data==0 and
+ * G3Decoder::bit==0 (no data in the accumulator).
+ * As we cannot explicitly clear the accumulator
+ * (bit and data are private), cutExtraRTC()
+ * should be called immediately after
+ * MemoryDecoder() constructing.
+ */
+ const u_long CheckArea = 20;
+ if( cc > CheckArea ){
+ bp += (cc-CheckArea);
+ cc = CheckArea;
+ }
+
+ endOfData = NULL;
+ if(!RTCraised()) {
+ /*
+ * syncronize to the next EOL and calculate pointer to it
+ * (see detailed explanation of look_ahead in TagLine.c++)
+ */
+ (void)isNextRow1D();
+ u_int look_ahead = roundup(getPendingBits(),8) / 8;
+ endOfData = current() - look_ahead;
+ for (;;) {
+ if( decodeRow(NULL, width) ){
+ /*
+ * endOfData is now after last good row. Thus we correctly handle
+ * RTC, single EOL in the end, or no RTC/EOL at all
+ */
+ endOfData = current();
+ }
+ }
+ }
+ return endOfData;
+}
+
+void
+FaxModem::correctPhaseCData(u_char* buf, u_long* pBufSize,
+ u_int fillorder, const Class2Params& params)
+{
+ MemoryDecoder dec1(buf, params.pageWidth(), *pBufSize, fillorder, params.is2D());
+ dec1.fixFirstEOL();
+ /*
+ * We have to construct new decoder. See comments to cutExtraRTC().
+ */
+ MemoryDecoder dec2(buf, params.pageWidth(), *pBufSize, fillorder, params.is2D());
+ u_char* endOfData = dec2.cutExtraRTC();
+ if( endOfData )
+ *pBufSize = endOfData - buf;
+}
diff -uNr hylafax-4.1beta2.orig/faxd/FaxModem.h hylafax-4.1beta2/faxd/FaxModem.h
--- hylafax-4.1beta2.orig/faxd/FaxModem.h Sun Jun 13 11:41:03 1999
+++ hylafax-4.1beta2/faxd/FaxModem.h Mon Mar 27 18:23:13 2000
@@ -132,6 +132,11 @@
bool setupTagLineSlop(const Class2Params&);
u_int getTagLineSlop() const;
u_char* imageTagLine(u_char* buf, u_int fillorder, const Class2Params&);
+/*
+ * Correct Phase C (T.4) data (remove extra RTC etc.) if neccessary
+ */
+ void correctPhaseCData(u_char* buf, u_long* pBufSize,
+ u_int fillorder, const Class2Params& params);
public:
virtual ~FaxModem();
diff -uNr hylafax-4.1beta2.orig/faxd/G3Encoder.c++ hylafax-4.1beta2/faxd/G3Encoder.c++
--- hylafax-4.1beta2.orig/faxd/G3Encoder.c++ Sun Jun 13 11:41:03 1999
+++ hylafax-4.1beta2/faxd/G3Encoder.c++ Mon Mar 27 13:19:51 2000
@@ -71,10 +71,13 @@
G3Encoder::encode(const void* vp, u_int w, u_int h)
{
u_int rowbytes = howmany(w, 8);
+ bool firstEOL = true;
while (h-- > 0) {
- if (bit != 4) // byte-align EOL
- putBits(0, (bit < 4) ? bit+4 : bit-4);
+ if( firstEOL ) // according to T.4 first EOL
+ firstEOL = false; // should not be aligned
+ else if (bit != 4)
+ putBits(0, (bit < 4) ? bit+4 : bit-4); // byte-align other EOLs
if (is2D)
putBits((EOL<<1)|1, 12+1);
else
diff -uNr hylafax-4.1beta2.orig/faxd/Makefile.in hylafax-4.1beta2/faxd/Makefile.in
--- hylafax-4.1beta2.orig/faxd/Makefile.in Tue Oct 13 00:47:49 1998
+++ hylafax-4.1beta2/faxd/Makefile.in Sun Mar 26 15:16:14 2000
@@ -91,6 +91,7 @@
faxSendApp.c++ \
tagtest.c++ \
tsitest.c++ \
+ t4test.c++ \
pageSendApp.c++
MODEM_OBJS=ClassModem.o \
FaxModem.o \
@@ -143,7 +144,7 @@
FAXGETTYOBJS= Getty.o Getty@GETTY@.o faxGettyApp.o
TARGETS=libfaxserver.${DSO} \
faxq faxsend faxgetty pagesend faxqclean \
- tsitest tagtest cqtest choptest
+ tsitest tagtest cqtest choptest t4test
default all::
@${MAKE} incdepend
@@ -200,10 +201,12 @@
${C++F} -o $@ tsitest.o libfaxserver.${DSO} ${LDFLAGS}
trigtest: trigtest.o libfaxserver.${DSO} ${LIBS}
${C++F} -o $@ trigtest.o libfaxserver.${DSO} ${LDFLAGS}
+t4test: t4test.o libfaxserver.${DSO} ${LIBS}
+ ${C++F} -o $@ t4test.o libfaxserver.${DSO} ${LDFLAGS}
PUTSERV=${INSTALL} -idb ${PRODUCT}.sw.server
install: default
${PUTSERV} -F ${SBIN} -m 755 -O faxq faxqclean
${PUTSERV} -F ${LIBEXEC} -m 755 -O faxgetty faxsend pagesend
- ${PUTSERV} -F ${SBIN} -m 755 -O tsitest tagtest cqtest choptest
+ ${PUTSERV} -F ${SBIN} -m 755 -O tsitest tagtest cqtest choptest t4test
diff -uNr hylafax-4.1beta2.orig/faxd/t4test.c++ hylafax-4.1beta2/faxd/t4test.c++
--- hylafax-4.1beta2.orig/faxd/t4test.c++ Thu Jan 1 03:00:00 1970
+++ hylafax-4.1beta2/faxd/t4test.c++ Mon Mar 27 18:59:05 2000
@@ -0,0 +1,405 @@
+/*
+ * This file does not exist in the original Hylafax distribution.
+ * Created by Dmitry Bely, March 2000
+ */
+/*
+ * Copyright (c) 1994-1996 Sam Leffler
+ * Copyright (c) 1994-1996 Silicon Graphics, Inc.
+ * HylaFAX is a trademark of Silicon Graphics
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+/*
+ * Program for testing T.4 data correction routines
+ *
+ * Usage: t4test [-o output.tif] input.tif
+ */
+#include "Sys.h"
+
+#include "G3Decoder.h"
+#include "G3Encoder.h"
+#include "StackBuffer.h"
+#include "tiffio.h"
+#include "Class2Params.h"
+#if HAS_LOCALE
+extern "C" {
+#include <locale.h>
+}
+#endif
+
+class MemoryDecoder : public G3Decoder {
+private:
+ u_char* bp;
+ u_int width;
+ u_int byteWidth;
+ u_long cc;
+
+ u_int fillorder;
+ bool is2D;
+
+ u_char* endOfData; // used by cutExtraRTC
+
+ uint16* runs;
+ u_char* rowBuf;
+
+ int decodeNextByte();
+
+ void invalidCode(const char* type, int x);
+ void badPixelCount(const char* type, int got, int expected);
+ void badDecodingState(const char* type, int x);
+public:
+ MemoryDecoder(u_char* data, u_int wid, u_long n,
+ u_int fillorder, bool twoDim);
+ ~MemoryDecoder();
+ u_char* current() { return bp; }
+ void fixFirstEOL();
+ u_char* cutExtraRTC();
+};
+
+MemoryDecoder::MemoryDecoder(u_char* data, u_int wid, u_long n,
+ u_int order, bool twoDim)
+{
+ bp = data;
+ width = wid;
+ byteWidth = howmany(width, 8);
+ cc = n;
+
+ fillorder = order;
+ is2D = twoDim;
+
+ runs = new uint16[2*width]; // run arrays for cur+ref rows
+ rowBuf = new u_char[byteWidth];
+ setupDecoder(fillorder, is2D);
+ setRuns(runs, runs+width, width);
+}
+MemoryDecoder::~MemoryDecoder()
+{
+ delete rowBuf;
+ delete runs;
+}
+
+int
+MemoryDecoder::decodeNextByte()
+{
+ if (cc == 0)
+ raiseRTC(); // XXX don't need to recognize EOF
+ cc--;
+ return (*bp++);
+}
+void
+MemoryDecoder::invalidCode(const char* type, int x)
+{
+ printf("Invalid %s code word, x %d\n", type, x);
+}
+void
+MemoryDecoder::badPixelCount(const char* type, int got, int expected)
+{
+ printf("Bad %s pixel count, got %d, expected %d\n",
+ type, got, expected);
+}
+void
+MemoryDecoder::badDecodingState(const char* type, int x)
+{
+ printf("Panic, bad %s decoding state, x %d\n", type, x);
+}
+
+#ifdef roundup
+#undef roundup
+#endif
+#define roundup(a,b) ((((a)+((b)-1))/(b))*(b))
+
+/*
+ * TIFF Class F specs say:
+ *
+ * "As illustrated in FIGURE 1/T.4 in Recommendation T.4 (the Red
+ * Book, page 20), facsimile documents begin with an EOL (which in
+ * Class F is byte-aligned)..."
+ *
+ * This is wrong! "Byte-aligned" first EOL means extra zero bits
+ * which are not allowed by T.4. Reencode first row to fix this
+ * "byte-alignment".
+ */
+void MemoryDecoder::fixFirstEOL()
+{
+ printf( "fixFirstEOL()\n" );
+ fxStackBuffer result;
+ G3Encoder enc(result);
+ enc.setupEncoder(fillorder, is2D);
+
+ memset(rowBuf, 0, byteWidth*sizeof(u_char)); // clear row to white
+ if(!RTCraised()) {
+ u_char* start = current();
+ (void)decodeRow(rowBuf, width);
+ /*
+ * syncronize to the next EOL and calculate pointer to it
+ * (see detailed explanation of look_ahead in TagLine.c++)
+ */
+ (void)isNextRow1D();
+ u_int look_ahead = roundup(getPendingBits(),8) / 8;
+ u_int decoded = current() - look_ahead - start;
+
+ enc.encode(rowBuf, width, 1);
+ u_int encoded = result.getLength();
+
+ while( encoded < decoded ){
+ result.put((char) 0);
+ encoded++;
+ }
+ if( encoded == decoded ){
+ memcpy(start, (u_char*)result, encoded);
+ printf( "Ok\n" );
+ }
+ }
+}
+
+
+/*
+ * TIFF Class F specs say:
+ *
+ * "Aside from EOL's, TIFF Class F files contain only image data. This
+ * means that the Return To Control sequence (RTC) is specifically
+ * prohibited..."
+ *
+ * Nethertheless Ghostscript and possibly other TIFF Class F writers
+ * append RTC or single EOL to the last encoded line. Remove them.
+ */
+u_char* MemoryDecoder::cutExtraRTC()
+{
+ printf( "cutExtraRTC()\n" );
+ printf("initial size = %ul\n", cc );
+ u_char* start = current();
+
+ /*
+ * We expect RTC near the end of data and thus
+ * do not check all image to save processing time.
+ * It's safe because we will resync on the first
+ * encountered EOL.
+ *
+ * NB: We expect G3Decoder::data==0 and
+ * G3Decoder::bit==0 (no data in the accumulator).
+ * As we cannot explicitly clear the accumulator
+ * (bit and data are private), cutExtraRTC()
+ * should be called immediately after
+ * MemoryDecoder() constructing.
+ */
+ const u_long CheckArea = 20;
+ if( cc > CheckArea ){
+ bp += (cc-CheckArea);
+ cc = CheckArea;
+ }
+
+ endOfData = NULL;
+ if(!RTCraised()) {
+ /*
+ * syncronize to the next EOL and calculate pointer to it
+ * (see detailed explanation of look_ahead in TagLine.c++)
+ */
+ (void)isNextRow1D();
+ u_int look_ahead = roundup(getPendingBits(),8) / 8;
+ endOfData = current() - look_ahead;
+ printf( "endOfData = %p\n", endOfData );
+ for (;;) {
+ if( decodeRow(NULL, width) ){
+ /*
+ * endOfData is now after last good row. Thus we correctly handle
+ * RTC, single EOL in the end, or no RTC/EOL at all
+ */
+ endOfData = current();
+ printf( "endOfData = %p\n", endOfData );
+ }
+ }
+ }
+
+ printf("endOfData = %p, size after RTC cut = %ul\n", endOfData, endOfData-start );
+ return endOfData;
+}
+
+void
+correctPhaseCData(u_char* buf, u_long* pBufSize,
+ u_int fillorder, const Class2Params& params)
+{
+ MemoryDecoder dec1(buf, params.pageWidth(), *pBufSize, fillorder, params.is2D());
+ dec1.fixFirstEOL();
+ /*
+ * We have to construct new decoder. See comments to cutExtraRTC().
+ */
+ MemoryDecoder dec2(buf, params.pageWidth(), *pBufSize, fillorder, params.is2D());
+ u_char* endOfData = dec2.cutExtraRTC();
+ if( endOfData )
+ *pBufSize = endOfData - buf;
+}
+
+void
+vlogError(const char* fmt, va_list ap)
+{
+ vfprintf(stderr, fmt, ap);
+ fputs(".\n", stderr);
+}
+
+// NB: must duplicate this to avoid pulling faxApp&co.
+
+extern "C" void
+_fxassert(const char* msg, const char* file, int line)
+{
+ fprintf(stderr, "Assertion failed \"%s\", file \"%s\" line %d.\n",
+ msg, file, line);
+ abort();
+ /*NOTREACHED*/
+}
+
+const char* appName;
+
+void
+usage()
+{
+ fprintf(stderr,
+ "usage: %s [-m format] [-o t.tif] [-f font.pcf] input.tif\n",
+ appName);
+ exit(-1);
+}
+
+void
+fatal(const char* fmt ...)
+{
+ fprintf(stderr, "%s: ", appName);
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputs(".\n", stderr);
+ exit(-1);
+}
+
+int
+main(int argc, char* argv[])
+{
+ extern int optind, opterr;
+ extern char* optarg;
+ int c;
+ const char* output = "t.tif";
+
+#ifdef LC_CTYPE
+ setlocale(LC_CTYPE, ""); // for <ctype.h> calls
+#endif
+#ifdef LC_TIME
+ setlocale(LC_TIME, ""); // for strftime calls
+#endif
+ appName = argv[0];
+ while ((c = getopt(argc, argv, "o:")) != -1)
+ switch (c) {
+ case 'o':
+ output = optarg;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 1)
+ usage();
+ TIFF* tif = TIFFOpen(argv[optind], "r");
+ if (!tif)
+ fatal("%s: Cannot open, or not a TIFF file", argv[optind]);
+ uint16 comp;
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &comp);
+ if (comp != COMPRESSION_CCITTFAX3)
+ fatal("%s: Not a Group 3-encoded TIFF file", argv[optind]);
+
+ TIFF* otif = TIFFOpen(output, "w");
+ if (!otif)
+ fatal("%s: Cannot create output file", output);
+ TIFFSetDirectory(tif, 0);
+
+ Class2Params params;
+ params.vr = VR_NORMAL;
+ params.wd = WD_1728;
+ params.ln = LN_INF;
+ params.df = DF_1DMR;
+
+ do {
+ TIFFSetField(otif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
+ TIFFSetField(otif, TIFFTAG_IMAGEWIDTH, 1728);
+ uint32 l;
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &l);
+ params.vr = (l < 1500 ? VR_NORMAL : VR_FINE);
+ TIFFSetField(otif, TIFFTAG_XRESOLUTION, 204.);
+ TIFFSetField(otif, TIFFTAG_YRESOLUTION, (float) params.verticalRes());
+ TIFFSetField(otif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ TIFFSetField(otif, TIFFTAG_IMAGELENGTH, l);
+ TIFFSetField(otif, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(otif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(otif, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
+ TIFFSetField(otif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
+ TIFFSetField(otif, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB);
+ uint32 r;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &r);
+ /*
+ * output all data in a single strip
+ */
+ TIFFSetField(otif, TIFFTAG_ROWSPERSTRIP, uint32(-1));
+ TIFFSetField(otif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(otif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
+ uint32 opts = 0;
+ TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS, &opts);
+ params.df = (opts & GROUP3OPT_2DENCODING) ? DF_2DMR : DF_1DMR;
+ TIFFSetField(otif, TIFFTAG_GROUP3OPTIONS, opts);
+ uint16 o;
+ if (TIFFGetField(otif, TIFFTAG_ORIENTATION, &o))
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, o);
+
+ uint16 fillorder;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
+ /*
+ * Calculate total amount of space needed to read
+ * the image into memory (in its encoded format).
+ */
+ uint32* stripbytecount;
+ (void) TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbytecount);
+ tstrip_t nstrips = TIFFNumberOfStrips(tif);
+ tstrip_t strip;
+ uint32 totdata = 0;
+ for (strip = 0; strip < nstrips; strip++)
+ totdata += stripbytecount[strip];
+ /*
+ * Read the image into memory.
+ */
+ u_char* data = new u_char[totdata];
+ u_int off = 0; // skip tag line slop area
+ for (strip = 0; strip < nstrips; strip++) {
+ uint32 sbc = stripbytecount[strip];
+ if (sbc > 0 && TIFFReadRawStrip(tif, strip, data+off, sbc) >= 0)
+ off += (u_int) sbc;
+ }
+
+ correctPhaseCData( data, &totdata, fillorder, params );
+
+ /*
+ * write result as a single strip to
+ * the output file
+ */
+ if (fillorder != FILLORDER_LSB2MSB)
+ TIFFReverseBits(data, totdata);
+ if (TIFFWriteRawStrip(otif, 0, data, totdata) == -1)
+ fatal("%s: Write error at strip %u, writing %lu bytes",
+ output, strip, (u_long) totdata);
+ delete data;
+ } while (TIFFReadDirectory(tif) && TIFFWriteDirectory(otif));
+ TIFFClose(otif);
+ return (0);
+}
diff -uNr hylafax-4.1beta2.orig/man/config.4f hylafax-4.1beta2/man/config.4f
--- hylafax-4.1beta2.orig/man/config.4f Tue Jan 5 10:48:18 1999
+++ hylafax-4.1beta2/man/config.4f Mon Mar 27 17:03:39 2000
@@ -304,6 +304,7 @@
Class2PTSCmd string \s-1AT+FPS\s+1 Class 2.0: command to set received page status
Class2RecvDataTrigger string \s-1``\e22''\s+1 Class 2.0: character to send to trigger recv
Class2RELCmd string \- Class 2.0: command to enable byte-aligned \s-1EOL\s+1 codes
+Class2SendRTC boolean \s-1No\s+1 Class 2.0: append \s-1RTC\s+1 to page data on transmit
Class2SFLOCmd string \s-1AT+FLO=1\s+1 Class 2.0: command to set software flow control
Class2SPLCmd string \s-1AT+FSP\s+1 Class 2.0: command to set polling request
Class2TBCCmd string \s-1AT+FPP=0\s+1 Class 2.0: command to enable stream mode
@@ -2091,7 +2092,8 @@
.B Class2SendRTC
Whether or not to append an explicit ``Return To Control'' (\s-1RTC\s+1)
signal to the page data when transmitting.
-The Class 2 spec (i.e. SP-2388-A) states the modem will append
+The Class 2 and Class 2.0 specs (i.e. SP-2388-A and TIA/EIA-592) state
+that the modem will append
.SM RTC
when it receives the post-page message command from the host; this
parameter is provided in case the modem does not correctly implement