"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 }