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



Home
Report any problems to webmaster@hylafax.org

HylaFAX is a trademark of Silicon Graphics Corporation.
Internet connectivity for hylafax.org is provided by:
VirtuALL Private Host Services