"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "viewfax-2.6/faxexpand.c" of archive viewfax-2.6.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /* Expand one page of fax data
    2    Copyright (C) 1990, 1995  Frank D. Cringle.
    3 
    4 This file is part of viewfax - g3/g4 fax processing software.
    5 
    6 viewfax is free software; you can redistribute it and/or modify it
    7 under the terms of the GNU General Public License as published by the
    8 Free Software Foundation; either version 2 of the License, or (at your
    9 option) any later version.
   10 
   11 This program is distributed in the hope that it will be useful, but
   12 WITHOUT ANY WARRANTY; without even the implied warranty of
   13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14 General Public License for more details.
   15 
   16 You should have received a copy of the GNU General Public License
   17 along with this program; if not, write to the Free Software
   18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
   19 
   20 #include <stdlib.h>
   21 #include <stdio.h>
   22 #include <sys/types.h>
   23 #include "faxexpand.h"
   24 
   25 /* Note that NeedBits() only works for n <= 16 */
   26 #define NeedBits(n) do {						\
   27     if (BitsAvail < (n)) {						\
   28 	BitAcc |= *sp++ << BitsAvail;					\
   29 	BitsAvail += 16;						\
   30     }									\
   31 } while (0)
   32 #define GetBits(n)	(BitAcc & ((1<<(n))-1))
   33 #define ClrBits(n) do {							\
   34     BitAcc >>= (n);							\
   35     BitsAvail -= (n);							\
   36 } while (0)
   37 
   38 #ifdef DEBUG
   39 #define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
   40 #define LOOKUP(wid,tab)	do {						\
   41     int t;								\
   42     NeedBits(wid);							\
   43     TabEnt = tab + GetBits(wid);					\
   44     printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail,			\
   45 	   StateNames[TabEnt->State], TabEnt->Param);			\
   46     for (t = 0; t < TabEnt->Width; t++)					\
   47 	DEBUG_SHOW;							\
   48     putchar('\n');							\
   49     fflush(stdout);							\
   50     ClrBits(TabEnt->Width);						\
   51 } while (0)
   52 
   53 #define SETVAL(x) do {							\
   54     *pa++ = RunLength + (x);						\
   55     printf("SETVAL: %d\t%d\n", RunLength + (x), a0);			\
   56     a0 += x;								\
   57     RunLength = 0;							\
   58 } while (0)
   59 
   60 char *StateNames[] = {
   61     "Null   ",
   62     "Pass   ",
   63     "Horiz  ",
   64     "V0     ",
   65     "VR     ",
   66     "VL     ",
   67     "Ext    ",
   68     "TermW  ",
   69     "TermB  ",
   70     "MakeUpW",
   71     "MakeUpB",
   72     "MakeUp ",
   73     "EOL    ",
   74 };
   75 
   76 #else
   77 #define LOOKUP(wid,tab)	do {						\
   78     NeedBits(wid);							\
   79     TabEnt = tab + GetBits(wid);					\
   80     ClrBits(TabEnt->Width);						\
   81 } while (0)
   82 
   83 #define SETVAL(x) do {							\
   84     *pa++ = RunLength + (x);						\
   85     a0 += x;								\
   86     RunLength = 0;							\
   87 } while (0)
   88 #endif
   89 
   90 #define dumpruns(runs) do {						\
   91     printf("-------------------- %d\n", LineNum);			\
   92     for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++)			\
   93 	printf("%4d %d\n", a0, *pa);					\
   94 } while (0)
   95 
   96 #define EndOfData(pn)	(sp >= pn->data + pn->length/sizeof(*pn->data))
   97 
   98 /* This macro handles coding errors in G3 data.
   99    We redefine it below for the G4 case */
  100 #define SKIP_EOL do {							\
  101     while (!EndOfData(pn)) {						\
  102 	NeedBits(11);							\
  103 	if (GetBits(11) == 0)						\
  104 	    break;							\
  105 	ClrBits(1);							\
  106     }									\
  107     ClrBits(11);							\
  108     goto EOL;								\
  109 } while (0)
  110 #define eol2lab	EOL2:
  111 
  112 /* the line expanders are written as macros so that they can be reused
  113    (twice each) but still have direct access to the local variables of
  114    the "calling" function */
  115 #define expand1d() do {							\
  116     while (a0 < lastx) {						\
  117 	int done = 0;							\
  118 	while (!done) {		/* white first */			\
  119 	    LOOKUP(12, WhiteTable);					\
  120 	    switch (TabEnt->State) {					\
  121 	    case S_EOL:							\
  122 		EOLcnt = 1;						\
  123 		goto EOL;						\
  124 	    case S_TermW:						\
  125 		SETVAL(TabEnt->Param);					\
  126 		done = 1;						\
  127 		break;							\
  128 	    case S_MakeUpW:						\
  129 	    case S_MakeUp:						\
  130 		a0 += TabEnt->Param;					\
  131 		RunLength += TabEnt->Param;				\
  132 		break;							\
  133 	    case S_Ext:							\
  134 		unexpected("Extension code", LineNum);			\
  135 		SKIP_EOL;						\
  136 		break;							\
  137 	    default:							\
  138 		unexpected("WhiteTable", LineNum);			\
  139 		SKIP_EOL;						\
  140 		break;							\
  141 	    }								\
  142 	}								\
  143 	done = a0 >= lastx;						\
  144 	while (!done) {		/* then black */			\
  145 	    LOOKUP(13, BlackTable);					\
  146 	    switch (TabEnt->State) {					\
  147 	    case S_EOL:							\
  148 		EOLcnt = 1;						\
  149 		goto EOL;						\
  150 	    case S_TermB:						\
  151 		SETVAL(TabEnt->Param);					\
  152 		done = 1;						\
  153 		break;							\
  154 	    case S_MakeUpB:						\
  155 	    case S_MakeUp:						\
  156 		a0 += TabEnt->Param;					\
  157 		RunLength += TabEnt->Param;				\
  158 		break;							\
  159 	    case S_Ext:							\
  160 		unexpected("Extension code", LineNum);			\
  161 		SKIP_EOL;						\
  162 		break;							\
  163 	    default:							\
  164 		unexpected("BlackTable", LineNum);			\
  165 		SKIP_EOL;						\
  166 		break;							\
  167 	    }								\
  168 	}								\
  169     }									\
  170  EOL: ;									\
  171 } while (0)
  172 
  173 #define CHECK_b1 do {							\
  174     if (pa != thisrun) while (b1 <= a0 && b1 < lastx) {			\
  175 	b1 += pb[0] + pb[1];						\
  176 	pb += 2;							\
  177     }									\
  178 } while (0)
  179 
  180 #define expand2d(eolab) do {						\
  181     while (a0 < lastx) {						\
  182 	LOOKUP(7, MainTable);						\
  183 	switch (TabEnt->State) {					\
  184 	case S_Pass:							\
  185 	    CHECK_b1;							\
  186 	    b1 += *pb++;						\
  187 	    RunLength += b1 - a0;					\
  188 	    a0 = b1;							\
  189 	    b1 += *pb++;						\
  190 	    break;							\
  191 	case S_Horiz:							\
  192 	    if ((pa-run0)&1) {						\
  193 		int done = 0;						\
  194 		while (!done) { /* black first */			\
  195 		    LOOKUP(13, BlackTable);				\
  196 		    switch (TabEnt->State) {				\
  197 		    case S_TermB:					\
  198 			SETVAL(TabEnt->Param);				\
  199 			done = 1;					\
  200 			break;						\
  201 		    case S_MakeUpB:					\
  202 		    case S_MakeUp:					\
  203 			a0 += TabEnt->Param;				\
  204 			RunLength += TabEnt->Param;			\
  205 			break;						\
  206 		    default:						\
  207 			unexpected("BlackTable", LineNum);		\
  208 			SKIP_EOL;					\
  209 			break;						\
  210 		    }							\
  211 		}							\
  212 		done = 0;						\
  213 		while (!done) { /* then white */			\
  214 		    LOOKUP(12, WhiteTable);				\
  215 		    switch (TabEnt->State) {				\
  216 		    case S_TermW:					\
  217 			SETVAL(TabEnt->Param);				\
  218 			done = 1;					\
  219 			break;						\
  220 		    case S_MakeUpW:					\
  221 		    case S_MakeUp:					\
  222 			a0 += TabEnt->Param;				\
  223 			RunLength += TabEnt->Param;			\
  224 			break;						\
  225 		    default:						\
  226 			unexpected("WhiteTable", LineNum);		\
  227 			SKIP_EOL;					\
  228 			break;						\
  229 		    }							\
  230 		}							\
  231 	    }								\
  232 	    else {							\
  233 		int done = 0;						\
  234 		while (!done) { /* white first */			\
  235 		    LOOKUP(12, WhiteTable);				\
  236 		    switch (TabEnt->State) {				\
  237 		    case S_TermW:					\
  238 			SETVAL(TabEnt->Param);				\
  239 			done = 1;					\
  240 			break;						\
  241 		    case S_MakeUpW:					\
  242 		    case S_MakeUp:					\
  243 			a0 += TabEnt->Param;				\
  244 			RunLength += TabEnt->Param;			\
  245 			break;						\
  246 		    default:						\
  247 			unexpected("WhiteTable", LineNum);		\
  248 			SKIP_EOL;					\
  249 			break;						\
  250 		    }							\
  251 		}							\
  252 		done = 0;						\
  253 		while (!done) { /* then black */			\
  254 		    LOOKUP(13, BlackTable);				\
  255 		    switch (TabEnt->State) {				\
  256 		    case S_TermB:					\
  257 			SETVAL(TabEnt->Param);				\
  258 			done = 1;					\
  259 			break;						\
  260 		    case S_MakeUpB:					\
  261 		    case S_MakeUp:					\
  262 			a0 += TabEnt->Param;				\
  263 			RunLength += TabEnt->Param;			\
  264 			break;						\
  265 		    default:						\
  266 			unexpected("BlackTable", LineNum);		\
  267 			SKIP_EOL;					\
  268 			break;						\
  269 		    }							\
  270 		}							\
  271 	    }								\
  272 	    CHECK_b1;							\
  273 	    break;							\
  274 	case S_V0:							\
  275 	    CHECK_b1;							\
  276 	    SETVAL(b1 - a0);						\
  277 	    b1 += *pb++;						\
  278 	    break;							\
  279 	case S_VR:							\
  280 	    CHECK_b1;							\
  281 	    SETVAL(b1 - a0 + TabEnt->Param);				\
  282 	    b1 += *pb++;						\
  283 	    break;							\
  284 	case S_VL:							\
  285 	    CHECK_b1;							\
  286 	    SETVAL(b1 - a0 - TabEnt->Param);				\
  287 	    b1 -= *--pb;						\
  288 	    break;							\
  289 	case S_Ext:							\
  290 	    *pa++ = lastx - a0;						\
  291 	    if (verbose)						\
  292 		fprintf(stderr, "Line %d: extension code\n", LineNum);	\
  293 	    SKIP_EOL;							\
  294 	    break;							\
  295 	case S_EOL:							\
  296 	    *pa++ = lastx - a0;						\
  297 	    NeedBits(4);						\
  298 	    if (GetBits(4) && verbose) /* already seen 7 zeros */	\
  299 		fprintf(stderr, "Line %d: Bad EOL\n", LineNum);		\
  300 	    ClrBits(4);							\
  301 	    EOLcnt = 1;							\
  302 	    goto eolab;							\
  303 	    break;							\
  304 	default:							\
  305 	    unexpected("MainTable", LineNum);				\
  306 	    SKIP_EOL;							\
  307 	    break;							\
  308 	}								\
  309     }									\
  310     if (RunLength) {							\
  311 	if (RunLength + a0 < lastx) {					\
  312 	    /* expect a final V0 */					\
  313 	    NeedBits(1);						\
  314 	    if (!GetBits(1)) {						\
  315 		unexpected("MainTable", LineNum);			\
  316 		SKIP_EOL;						\
  317 	    }								\
  318 	    ClrBits(1);							\
  319 	}								\
  320 	SETVAL(0);							\
  321     }									\
  322  eol2lab ;								\
  323 } while (0)
  324 
  325 static void
  326 unexpected(char *what, int LineNum)
  327 {
  328     if (verbose)
  329 	fprintf(stderr, "Line %d: Unexpected state in %s\n",
  330 		LineNum, what);
  331 }
  332 
  333 /* Expand tiff modified huffman data (g3-1d without EOLs) */
  334 void
  335 MHexpand(struct pagenode *pn, drawfunc df)
  336 {
  337     int a0;			/* reference element */
  338     int lastx = pn->width;	/* copy line width to register */
  339     t32bits BitAcc;		/* bit accumulator */
  340     int BitsAvail;		/* # valid bits in BitAcc */
  341     int RunLength;		/* Length of current run */
  342     t16bits *sp;		/* pointer into compressed data */
  343     pixnum *pa;			/* pointer into new line */
  344     int EOLcnt;			/* number of consecutive EOLs */
  345     int	LineNum;		/* line number */
  346     pixnum *runs;		/* list of run lengths */
  347     struct tabent *TabEnt;
  348 
  349     sp = pn->data;
  350     BitAcc = 0;
  351     BitsAvail = 0;
  352     lastx = pn->width;
  353     runs = (pixnum *) xmalloc(lastx * sizeof(pixnum));
  354     for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
  355 #ifdef DEBUG
  356 	printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
  357 	printf("-------------------- %d\n", LineNum);
  358 	fflush(stdout);
  359 #endif
  360 	RunLength = 0;
  361 	pa = runs;
  362 	a0 = 0;
  363 	EOLcnt = 0;
  364 	if (BitsAvail & 7)	/* skip to byte boundary */
  365 	    ClrBits(BitsAvail & 7);
  366 	expand1d();
  367 	if (RunLength)
  368 	    SETVAL(0);
  369 	if (a0 != lastx) {
  370 	    if (verbose)
  371 		fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
  372 	    while (a0 > lastx)
  373 		a0 -= *--pa;
  374 	    if (a0 < lastx) {
  375 		if ((pa - runs) & 1)
  376 		    SETVAL(0);
  377 		SETVAL(lastx - a0);
  378 	    }
  379 	}
  380 	(*df)(runs, LineNum++, pn);
  381     }
  382     free(runs);
  383 }
  384 
  385 /* Expand group-3 1-dimensional data */
  386 void
  387 g31expand(struct pagenode *pn, drawfunc df)
  388 {
  389     int a0;			/* reference element */
  390     int lastx = pn->width;	/* copy line width to register */
  391     t32bits BitAcc;		/* bit accumulator */
  392     int BitsAvail;		/* # valid bits in BitAcc */
  393     int RunLength;		/* Length of current run */
  394     t16bits *sp;		/* pointer into compressed data */
  395     pixnum *pa;			/* pointer into new line */
  396     int EOLcnt;			/* number of consecutive EOLs */
  397     int	LineNum;		/* line number */
  398     pixnum *runs;		/* list of run lengths */
  399     struct tabent *TabEnt;
  400 
  401     sp = pn->data;
  402     BitAcc = 0;
  403     BitsAvail = 0;
  404     lastx = pn->width;
  405     runs = (pixnum *) xmalloc(lastx * sizeof(pixnum));
  406     EOLcnt = 0;
  407     for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
  408 #ifdef DEBUG
  409 	printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
  410 	printf("-------------------- %d\n", LineNum);
  411 	fflush(stdout);
  412 #endif
  413 	if (EOLcnt == 0)
  414 	    while (!EndOfData(pn)) {
  415 		/* skip over garbage after a coding error */
  416 		NeedBits(11);
  417 		if (GetBits(11) == 0)
  418 		    break;
  419 		ClrBits(1);
  420 	    }
  421 	for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
  422 	    /* we have seen 11 zeros, which implies EOL,
  423 	       skip possible fill bits too */
  424 	    while (1) {
  425 		NeedBits(8);
  426 		if (GetBits(8))
  427 		    break;
  428 		ClrBits(8);
  429 	    }
  430 	    while (GetBits(1) == 0)
  431 		ClrBits(1);
  432 	    ClrBits(1);		/* the eol flag */
  433 	    NeedBits(11);
  434 	    if (GetBits(11))
  435 		break;
  436 	    ClrBits(11);
  437 	}
  438 	if (EOLcnt > 1 && EOLcnt != 6 && verbose)
  439 	    fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt);
  440 	if (EOLcnt >= 6 || EndOfData(pn)) {
  441 	    free(runs);
  442 	    return;
  443 	}
  444 	RunLength = 0;
  445 	pa = runs;
  446 	a0 = 0;
  447 	EOLcnt = 0;
  448 	expand1d();
  449 	if (RunLength)
  450 	    SETVAL(0);
  451 	if (a0 != lastx) {
  452 	    if (verbose)
  453 		fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
  454 	    while (a0 > lastx)
  455 		a0 -= *--pa;
  456 	    if (a0 < lastx) {
  457 		if ((pa - runs) & 1)
  458 		    SETVAL(0);
  459 		SETVAL(lastx - a0);
  460 	    }
  461 	}
  462 	(*df)(runs, LineNum++, pn);
  463     }
  464     free(runs);
  465 }
  466 
  467 /* Expand group-3 2-dimensional data */
  468 void
  469 g32expand(struct pagenode *pn, drawfunc df)
  470 {
  471     int RunLength;		/* Length of current run */
  472     int a0;			/* reference element */
  473     int b1;			/* next change on previous line */
  474     int lastx = pn->width;	/* copy line width to register */
  475     pixnum *run0, *run1;	/* run length arrays */
  476     pixnum *thisrun, *pa, *pb;	/* pointers into runs */
  477     t16bits *sp;		/* pointer into compressed data */
  478     t32bits BitAcc;		/* bit accumulator */
  479     int BitsAvail;		/* # valid bits in BitAcc */
  480     int EOLcnt;			/* number of consecutive EOLs */
  481     int	refline = 0;		/* 1D encoded reference line */
  482     int	LineNum;		/* line number */
  483     struct tabent *TabEnt;
  484 
  485     sp = pn->data;
  486     BitAcc = 0;
  487     BitsAvail = 0;
  488     /* allocate space for 2 runlength arrays */
  489     run0 = (pixnum *) xmalloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
  490     run1 = run0 + ((lastx+5)&~1);
  491     run1[0] = lastx;
  492     run1[1] = 0;
  493     EOLcnt = 0;
  494     for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
  495 #ifdef DEBUG
  496 	printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
  497 	printf("-------------------- %d\n", LineNum);
  498 	fflush(stdout);
  499 #endif
  500 	if (EOLcnt == 0)
  501 	    while (!EndOfData(pn)) {
  502 		/* skip over garbage after a coding error */
  503 		NeedBits(11);
  504 		if (GetBits(11) == 0)
  505 		    break;
  506 		ClrBits(1);
  507 	    }
  508 	for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
  509 	    /* we have seen 11 zeros, which implies EOL,
  510 	       skip possible fill bits too */
  511 	    while (1) {
  512 		NeedBits(8);
  513 		if (GetBits(8))
  514 		    break;
  515 		ClrBits(8);
  516 	    }
  517 	    while (GetBits(1) == 0)
  518 		ClrBits(1);
  519 	    ClrBits(1);		/* the eol flag */
  520 	    NeedBits(12);
  521 	    refline = GetBits(1); /* 1D / 2D flag */
  522 	    ClrBits(1);
  523 	    if (GetBits(11))
  524 		break;
  525 	    ClrBits(11);
  526 	}
  527 	if (EOLcnt > 1 && EOLcnt != 6 && verbose)
  528 	    fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt);
  529 	if (EOLcnt >= 6 || EndOfData(pn)) {
  530 	    free(run0);
  531 	    return;
  532 	}
  533 	if (LineNum == 0 && refline == 0 && verbose)
  534 	    fprintf(stderr, "First line is 2-D encoded\n");
  535 	RunLength = 0;
  536 	if (LineNum & 1) {
  537 	    pa = run1;
  538 	    pb = run0;
  539 	}
  540 	else {
  541 	    pa = run0;
  542 	    pb = run1;
  543 	}
  544 	thisrun = pa;
  545 	EOLcnt = 0;
  546 	a0 = 0;
  547 	b1 = *pb++;
  548 
  549 	if (refline) {
  550 	    expand1d();
  551 	}
  552 	else {
  553 	    expand2d(EOL2);
  554 	}
  555 	if (RunLength)
  556 	    SETVAL(0);
  557 	if (a0 != lastx) {
  558 	    if (verbose)
  559 		fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
  560 	    while (a0 > lastx)
  561 		a0 -= *--pa;
  562 	    if (a0 < lastx) {
  563 		if ((pa - run0) & 1)
  564 		    SETVAL(0);
  565 		SETVAL(lastx - a0);
  566 	    }
  567 	}
  568 	SETVAL(0);	/* imaginary change at end of line for reference */
  569 	(*df)(thisrun, LineNum++, pn);
  570     }
  571     free(run0);
  572 }
  573 
  574 /* Redefine the "skip to eol" macro.  We cannot recover from coding
  575    errors in G4 data */
  576 #undef SKIP_EOL
  577 #undef eol2lab
  578 #define SKIP_EOL do {							\
  579     if (verbose)							\
  580 	fprintf(stderr, "Line %d: G4 coding error\n", LineNum);		\
  581     free(run0);								\
  582     return;								\
  583 } while (0)
  584 #define eol2lab
  585 
  586 /* Expand group-4 data */
  587 void
  588 g4expand(struct pagenode *pn, drawfunc df)
  589 {
  590     int RunLength;		/* Length of current run */
  591     int a0;			/* reference element */
  592     int b1;			/* next change on previous line */
  593     int lastx = pn->width;	/* copy line width to register */
  594     pixnum *run0, *run1;	/* run length arrays */
  595     pixnum *thisrun, *pa, *pb;	/* pointers into runs */
  596     t16bits *sp;		/* pointer into compressed data */
  597     t32bits BitAcc;		/* bit accumulator */
  598     int BitsAvail;		/* # valid bits in BitAcc */
  599     int	LineNum;		/* line number */
  600     int EOLcnt;
  601     struct tabent *TabEnt;
  602 
  603     sp = pn->data;
  604     BitAcc = 0;
  605     BitsAvail = 0;
  606     /* allocate space for 2 runlength arrays */
  607     run0 = (pixnum *) xmalloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
  608     run1 = run0 + ((lastx+5)&~1);
  609     run1[0] = lastx;		/* initial reference line */
  610     run1[1] = 0;
  611 
  612     for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
  613 #ifdef DEBUG
  614 	printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
  615 	printf("-------------------- %d\n", LineNum);
  616 	fflush(stdout);
  617 #endif
  618 	RunLength = 0;
  619 	if (LineNum & 1) {
  620 	    pa = run1;
  621 	    pb = run0;
  622 	}
  623 	else {
  624 	    pa = run0;
  625 	    pb = run1;
  626 	}
  627 	thisrun = pa;
  628 	a0 = 0;
  629 	b1 = *pb++;
  630 	expand2d(EOFB);
  631 	if (a0 < lastx) {
  632 	    if ((pa - run0) & 1)
  633 		SETVAL(0);
  634 	    SETVAL(lastx - a0);
  635 	}
  636 	SETVAL(0);	/* imaginary change at end of line for reference */
  637 	(*df)(thisrun, LineNum++, pn);
  638 	continue;
  639     EOFB:
  640 	NeedBits(13);
  641 	if (GetBits(13) != 0x1001 && verbose)
  642 	    fputs("Bad RTC\n", stderr);
  643 	break;
  644     }
  645     free(run0);
  646 }
  647 
  648 static unsigned char zerotab[256] = {
  649 	0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05,
  650 	0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04,
  651 	0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
  652 	0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
  653 	0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
  654 	0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
  655 	0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
  656 	0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
  657 	0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  658 	0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  659 	0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  660 	0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  661 	0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  662 	0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  663 	0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  664 	0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
  665 	0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  666 	0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  667 	0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  668 	0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  669 	0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  670 	0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  671 	0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  672 	0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  673 	0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  674 	0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  675 	0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  676 	0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  677 	0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  678 	0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  679 	0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
  680 	0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00
  681 };
  682 
  683 #define check(v) do {							\
  684     prezeros = zerotab[v];						\
  685     postzeros = prezeros & 15;						\
  686     prezeros >>= 4;							\
  687     if (prezeros == 8) {						\
  688 	zeros += 8;							\
  689 	continue;							\
  690     }									\
  691     if (zeros + prezeros < 11) {					\
  692 	empty = 0;							\
  693 	zeros = postzeros;						\
  694 	continue;							\
  695     }									\
  696     zeros = postzeros;							\
  697     if (empty)								\
  698 	EOLcnt++;							\
  699     lines++;								\
  700     empty = 1;								\
  701 } while (0)
  702 
  703 /* count fax lines */
  704 int
  705 G3count(struct pagenode *pn, int twoD)
  706 {
  707     t16bits *p = pn->data;
  708     t16bits *end = p + pn->length/sizeof(*p);
  709     int lines = 0;		/* lines seen so far */
  710     int zeros = 0;		/* number of consecutive zero bits seen */
  711     int EOLcnt = 0;		/* number of consecutive EOLs seen */
  712     int empty = 1;		/* empty line */
  713     int prezeros, postzeros;
  714 
  715     while (p < end && EOLcnt < 6) {
  716 	t16bits bits = *p++;
  717 	check(bits&255);
  718 	if (twoD && (prezeros + postzeros == 7)) {
  719 	    if (postzeros || ((bits & 0x100) == 0))
  720 		zeros--;
  721 	}
  722 	check(bits>>8);
  723 	if (twoD && (prezeros + postzeros == 7)) {
  724 	    if (postzeros || ((p < end) && ((*p & 1) == 0)))
  725 		zeros--;
  726 	}
  727     }
  728     return lines - EOLcnt;	/* don't count trailing EOLs */
  729 }