File indexing completed on 2024-05-12 16:06:42

0001 /*
0002     Expand one page of fax data
0003     This file is part of viewfax - g3/g4 fax processing software.
0004     SPDX-FileCopyrightText: 1990, 1995  Frank D. Cringle.
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "faxexpand.h"
0009 
0010 #include <stdio.h>
0011 #include <stdlib.h>
0012 
0013 #include <QDebug>
0014 
0015 #include "fax_debug.h"
0016 // Uncomment this for verbose debug output
0017 //#define DEBUG_FAX
0018 #define verbose false
0019 
0020 pagenode::pagenode()
0021 {
0022 }
0023 
0024 /* Note that NeedBits() only works for n <= 16 */
0025 #define NeedBits(n)                                                                                                                                                                                                                            \
0026     do {                                                                                                                                                                                                                                       \
0027         if (BitsAvail < (n)) {                                                                                                                                                                                                                 \
0028             BitAcc |= *sp++ << BitsAvail;                                                                                                                                                                                                      \
0029             BitsAvail += 16;                                                                                                                                                                                                                   \
0030         }                                                                                                                                                                                                                                      \
0031     } while (0)
0032 #define GetBits(n) (BitAcc & ((1 << (n)) - 1))
0033 #define ClrBits(n)                                                                                                                                                                                                                             \
0034     do {                                                                                                                                                                                                                                       \
0035         BitAcc >>= (n);                                                                                                                                                                                                                        \
0036         BitsAvail -= (n);                                                                                                                                                                                                                      \
0037     } while (0)
0038 
0039 #ifdef DEBUG_FAX
0040 #define DEBUG_SHOW putchar(BitAcc &(1 << t) ? '1' : '0')
0041 #define LOOKUP(wid, tab)                                                                                                                                                                                                                       \
0042     do {                                                                                                                                                                                                                                       \
0043         int t;                                                                                                                                                                                                                                 \
0044         NeedBits(wid);                                                                                                                                                                                                                         \
0045         TabEnt = tab + GetBits(wid);                                                                                                                                                                                                           \
0046         printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail, StateNames[TabEnt->State], TabEnt->Param);                                                                                                                                              \
0047         for (t = 0; t < TabEnt->Width; t++)                                                                                                                                                                                                    \
0048             DEBUG_SHOW;                                                                                                                                                                                                                        \
0049         putchar('\n');                                                                                                                                                                                                                         \
0050         fflush(stdout);                                                                                                                                                                                                                        \
0051         ClrBits(TabEnt->Width);                                                                                                                                                                                                                \
0052     } while (0)
0053 
0054 #define SETVAL(x)                                                                                                                                                                                                                              \
0055     do {                                                                                                                                                                                                                                       \
0056         *pa++ = RunLength + (x);                                                                                                                                                                                                               \
0057         printf("SETVAL: %d\t%d\n", RunLength + (x), a0);                                                                                                                                                                                       \
0058         a0 += x;                                                                                                                                                                                                                               \
0059         RunLength = 0;                                                                                                                                                                                                                         \
0060     } while (0)
0061 
0062 const char *StateNames[] = {
0063     "Null   ",
0064     "Pass   ",
0065     "Horiz  ",
0066     "V0     ",
0067     "VR     ",
0068     "VL     ",
0069     "Ext    ",
0070     "TermW  ",
0071     "TermB  ",
0072     "MakeUpW",
0073     "MakeUpB",
0074     "MakeUp ",
0075     "EOL    ",
0076 };
0077 
0078 #else
0079 #define LOOKUP(wid, tab)                                                                                                                                                                                                                       \
0080     do {                                                                                                                                                                                                                                       \
0081         NeedBits(wid);                                                                                                                                                                                                                         \
0082         TabEnt = tab + GetBits(wid);                                                                                                                                                                                                           \
0083         ClrBits(TabEnt->Width);                                                                                                                                                                                                                \
0084     } while (0)
0085 
0086 #define SETVAL(x)                                                                                                                                                                                                                              \
0087     do {                                                                                                                                                                                                                                       \
0088         *pa++ = RunLength + (x);                                                                                                                                                                                                               \
0089         a0 += x;                                                                                                                                                                                                                               \
0090         RunLength = 0;                                                                                                                                                                                                                         \
0091     } while (0)
0092 #endif
0093 
0094 #define dumpruns(runs)                                                                                                                                                                                                                         \
0095     do {                                                                                                                                                                                                                                       \
0096         printf("-------------------- %d\n", LineNum);                                                                                                                                                                                          \
0097         for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++)                                                                                                                                                                                       \
0098             printf("%4d %d\n", a0, *pa);                                                                                                                                                                                                       \
0099     } while (0)
0100 
0101 #define EndOfData(pn) (sp >= pn->data + pn->length / sizeof(*pn->data))
0102 
0103 /* This macro handles coding errors in G3 data.
0104    We redefine it below for the G4 case */
0105 #define SKIP_EOL                                                                                                                                                                                                                               \
0106     do {                                                                                                                                                                                                                                       \
0107         while (!EndOfData(pn)) {                                                                                                                                                                                                               \
0108             NeedBits(11);                                                                                                                                                                                                                      \
0109             if (GetBits(11) == 0)                                                                                                                                                                                                              \
0110                 break;                                                                                                                                                                                                                         \
0111             ClrBits(1);                                                                                                                                                                                                                        \
0112         }                                                                                                                                                                                                                                      \
0113         ClrBits(11);                                                                                                                                                                                                                           \
0114         goto EOL;                                                                                                                                                                                                                              \
0115     } while (0)
0116 #define eol2lab                                                                                                                                                                                                                                \
0117     EOL2:
0118 
0119 /* the line expanders are written as macros so that they can be reused
0120    (twice each) but still have direct access to the local variables of
0121    the "calling" function */
0122 #define expand1d()                                                                                                                                                                                                                             \
0123     do {                                                                                                                                                                                                                                       \
0124         while (a0 < lastx) {                                                                                                                                                                                                                   \
0125             int done = 0;                                                                                                                                                                                                                      \
0126             while (!done) { /* white first */                                                                                                                                                                                                  \
0127                 LOOKUP(12, WhiteTable);                                                                                                                                                                                                        \
0128                 switch (TabEnt->State) {                                                                                                                                                                                                       \
0129                 case S_EOL:                                                                                                                                                                                                                    \
0130                     EOLcnt = 1;                                                                                                                                                                                                                \
0131                     goto EOL;                                                                                                                                                                                                                  \
0132                 case S_TermW:                                                                                                                                                                                                                  \
0133                     SETVAL(TabEnt->Param);                                                                                                                                                                                                     \
0134                     done = 1;                                                                                                                                                                                                                  \
0135                     break;                                                                                                                                                                                                                     \
0136                 case S_MakeUpW:                                                                                                                                                                                                                \
0137                 case S_MakeUp:                                                                                                                                                                                                                 \
0138                     a0 += TabEnt->Param;                                                                                                                                                                                                       \
0139                     RunLength += TabEnt->Param;                                                                                                                                                                                                \
0140                     break;                                                                                                                                                                                                                     \
0141                 case S_Ext:                                                                                                                                                                                                                    \
0142                     unexpected("Extension code", LineNum);                                                                                                                                                                                     \
0143                     SKIP_EOL;                                                                                                                                                                                                                  \
0144                     break;                                                                                                                                                                                                                     \
0145                 default:                                                                                                                                                                                                                       \
0146                     unexpected("WhiteTable", LineNum);                                                                                                                                                                                         \
0147                     SKIP_EOL;                                                                                                                                                                                                                  \
0148                     break;                                                                                                                                                                                                                     \
0149                 }                                                                                                                                                                                                                              \
0150             }                                                                                                                                                                                                                                  \
0151             done = a0 >= lastx;                                                                                                                                                                                                                \
0152             while (!done) { /* then black */                                                                                                                                                                                                   \
0153                 LOOKUP(13, BlackTable);                                                                                                                                                                                                        \
0154                 switch (TabEnt->State) {                                                                                                                                                                                                       \
0155                 case S_EOL:                                                                                                                                                                                                                    \
0156                     EOLcnt = 1;                                                                                                                                                                                                                \
0157                     goto EOL;                                                                                                                                                                                                                  \
0158                 case S_TermB:                                                                                                                                                                                                                  \
0159                     SETVAL(TabEnt->Param);                                                                                                                                                                                                     \
0160                     done = 1;                                                                                                                                                                                                                  \
0161                     break;                                                                                                                                                                                                                     \
0162                 case S_MakeUpB:                                                                                                                                                                                                                \
0163                 case S_MakeUp:                                                                                                                                                                                                                 \
0164                     a0 += TabEnt->Param;                                                                                                                                                                                                       \
0165                     RunLength += TabEnt->Param;                                                                                                                                                                                                \
0166                     break;                                                                                                                                                                                                                     \
0167                 case S_Ext:                                                                                                                                                                                                                    \
0168                     unexpected("Extension code", LineNum);                                                                                                                                                                                     \
0169                     SKIP_EOL;                                                                                                                                                                                                                  \
0170                     break;                                                                                                                                                                                                                     \
0171                 default:                                                                                                                                                                                                                       \
0172                     unexpected("BlackTable", LineNum);                                                                                                                                                                                         \
0173                     SKIP_EOL;                                                                                                                                                                                                                  \
0174                     break;                                                                                                                                                                                                                     \
0175                 }                                                                                                                                                                                                                              \
0176             }                                                                                                                                                                                                                                  \
0177         }                                                                                                                                                                                                                                      \
0178     EOL:;                                                                                                                                                                                                                                      \
0179     } while (0)
0180 
0181 #define CHECK_b1                                                                                                                                                                                                                               \
0182     do {                                                                                                                                                                                                                                       \
0183         if (pa != thisrun)                                                                                                                                                                                                                     \
0184             while (b1 <= a0 && b1 < lastx) {                                                                                                                                                                                                   \
0185                 b1 += pb[0] + pb[1];                                                                                                                                                                                                           \
0186                 pb += 2;                                                                                                                                                                                                                       \
0187             }                                                                                                                                                                                                                                  \
0188     } while (0)
0189 
0190 #define expand2d(eolab)                                                                                                                                                                                                                        \
0191     do {                                                                                                                                                                                                                                       \
0192         while (a0 < lastx) {                                                                                                                                                                                                                   \
0193             LOOKUP(7, MainTable);                                                                                                                                                                                                              \
0194             switch (TabEnt->State) {                                                                                                                                                                                                           \
0195             case S_Pass:                                                                                                                                                                                                                       \
0196                 CHECK_b1;                                                                                                                                                                                                                      \
0197                 b1 += *pb++;                                                                                                                                                                                                                   \
0198                 RunLength += b1 - a0;                                                                                                                                                                                                          \
0199                 a0 = b1;                                                                                                                                                                                                                       \
0200                 b1 += *pb++;                                                                                                                                                                                                                   \
0201                 break;                                                                                                                                                                                                                         \
0202             case S_Horiz:                                                                                                                                                                                                                      \
0203                 if ((pa - run0) & 1) {                                                                                                                                                                                                         \
0204                     int done = 0;                                                                                                                                                                                                              \
0205                     while (!done) { /* black first */                                                                                                                                                                                          \
0206                         LOOKUP(13, BlackTable);                                                                                                                                                                                                \
0207                         switch (TabEnt->State) {                                                                                                                                                                                               \
0208                         case S_TermB:                                                                                                                                                                                                          \
0209                             SETVAL(TabEnt->Param);                                                                                                                                                                                             \
0210                             done = 1;                                                                                                                                                                                                          \
0211                             break;                                                                                                                                                                                                             \
0212                         case S_MakeUpB:                                                                                                                                                                                                        \
0213                         case S_MakeUp:                                                                                                                                                                                                         \
0214                             a0 += TabEnt->Param;                                                                                                                                                                                               \
0215                             RunLength += TabEnt->Param;                                                                                                                                                                                        \
0216                             break;                                                                                                                                                                                                             \
0217                         default:                                                                                                                                                                                                               \
0218                             unexpected("BlackTable", LineNum);                                                                                                                                                                                 \
0219                             SKIP_EOL;                                                                                                                                                                                                          \
0220                             break;                                                                                                                                                                                                             \
0221                         }                                                                                                                                                                                                                      \
0222                     }                                                                                                                                                                                                                          \
0223                     done = 0;                                                                                                                                                                                                                  \
0224                     while (!done) { /* then white */                                                                                                                                                                                           \
0225                         LOOKUP(12, WhiteTable);                                                                                                                                                                                                \
0226                         switch (TabEnt->State) {                                                                                                                                                                                               \
0227                         case S_TermW:                                                                                                                                                                                                          \
0228                             SETVAL(TabEnt->Param);                                                                                                                                                                                             \
0229                             done = 1;                                                                                                                                                                                                          \
0230                             break;                                                                                                                                                                                                             \
0231                         case S_MakeUpW:                                                                                                                                                                                                        \
0232                         case S_MakeUp:                                                                                                                                                                                                         \
0233                             a0 += TabEnt->Param;                                                                                                                                                                                               \
0234                             RunLength += TabEnt->Param;                                                                                                                                                                                        \
0235                             break;                                                                                                                                                                                                             \
0236                         default:                                                                                                                                                                                                               \
0237                             unexpected("WhiteTable", LineNum);                                                                                                                                                                                 \
0238                             SKIP_EOL;                                                                                                                                                                                                          \
0239                             break;                                                                                                                                                                                                             \
0240                         }                                                                                                                                                                                                                      \
0241                     }                                                                                                                                                                                                                          \
0242                 } else {                                                                                                                                                                                                                       \
0243                     int done = 0;                                                                                                                                                                                                              \
0244                     while (!done) { /* white first */                                                                                                                                                                                          \
0245                         LOOKUP(12, WhiteTable);                                                                                                                                                                                                \
0246                         switch (TabEnt->State) {                                                                                                                                                                                               \
0247                         case S_TermW:                                                                                                                                                                                                          \
0248                             SETVAL(TabEnt->Param);                                                                                                                                                                                             \
0249                             done = 1;                                                                                                                                                                                                          \
0250                             break;                                                                                                                                                                                                             \
0251                         case S_MakeUpW:                                                                                                                                                                                                        \
0252                         case S_MakeUp:                                                                                                                                                                                                         \
0253                             a0 += TabEnt->Param;                                                                                                                                                                                               \
0254                             RunLength += TabEnt->Param;                                                                                                                                                                                        \
0255                             break;                                                                                                                                                                                                             \
0256                         default:                                                                                                                                                                                                               \
0257                             unexpected("WhiteTable", LineNum);                                                                                                                                                                                 \
0258                             SKIP_EOL;                                                                                                                                                                                                          \
0259                             break;                                                                                                                                                                                                             \
0260                         }                                                                                                                                                                                                                      \
0261                     }                                                                                                                                                                                                                          \
0262                     done = 0;                                                                                                                                                                                                                  \
0263                     while (!done) { /* then black */                                                                                                                                                                                           \
0264                         LOOKUP(13, BlackTable);                                                                                                                                                                                                \
0265                         switch (TabEnt->State) {                                                                                                                                                                                               \
0266                         case S_TermB:                                                                                                                                                                                                          \
0267                             SETVAL(TabEnt->Param);                                                                                                                                                                                             \
0268                             done = 1;                                                                                                                                                                                                          \
0269                             break;                                                                                                                                                                                                             \
0270                         case S_MakeUpB:                                                                                                                                                                                                        \
0271                         case S_MakeUp:                                                                                                                                                                                                         \
0272                             a0 += TabEnt->Param;                                                                                                                                                                                               \
0273                             RunLength += TabEnt->Param;                                                                                                                                                                                        \
0274                             break;                                                                                                                                                                                                             \
0275                         default:                                                                                                                                                                                                               \
0276                             unexpected("BlackTable", LineNum);                                                                                                                                                                                 \
0277                             SKIP_EOL;                                                                                                                                                                                                          \
0278                             break;                                                                                                                                                                                                             \
0279                         }                                                                                                                                                                                                                      \
0280                     }                                                                                                                                                                                                                          \
0281                 }                                                                                                                                                                                                                              \
0282                 CHECK_b1;                                                                                                                                                                                                                      \
0283                 break;                                                                                                                                                                                                                         \
0284             case S_V0:                                                                                                                                                                                                                         \
0285                 CHECK_b1;                                                                                                                                                                                                                      \
0286                 SETVAL(b1 - a0);                                                                                                                                                                                                               \
0287                 b1 += *pb++;                                                                                                                                                                                                                   \
0288                 break;                                                                                                                                                                                                                         \
0289             case S_VR:                                                                                                                                                                                                                         \
0290                 CHECK_b1;                                                                                                                                                                                                                      \
0291                 SETVAL(b1 - a0 + TabEnt->Param);                                                                                                                                                                                               \
0292                 b1 += *pb++;                                                                                                                                                                                                                   \
0293                 break;                                                                                                                                                                                                                         \
0294             case S_VL:                                                                                                                                                                                                                         \
0295                 CHECK_b1;                                                                                                                                                                                                                      \
0296                 SETVAL(b1 - a0 - TabEnt->Param);                                                                                                                                                                                               \
0297                 b1 -= *--pb;                                                                                                                                                                                                                   \
0298                 break;                                                                                                                                                                                                                         \
0299             case S_Ext:                                                                                                                                                                                                                        \
0300                 *pa++ = lastx - a0;                                                                                                                                                                                                            \
0301                 if (verbose)                                                                                                                                                                                                                   \
0302                     qCDebug(FAX_LOG) << "Line " << LineNum << ": extension code\n";                                                                                                                                                            \
0303                 SKIP_EOL;                                                                                                                                                                                                                      \
0304                 break;                                                                                                                                                                                                                         \
0305             case S_EOL:                                                                                                                                                                                                                        \
0306                 *pa++ = lastx - a0;                                                                                                                                                                                                            \
0307                 NeedBits(4);                                                                                                                                                                                                                   \
0308                 if (GetBits(4) && verbose) /* already seen 7 zeros */                                                                                                                                                                          \
0309                     qCDebug(FAX_LOG) << "Line " << LineNum << ": Bad EOL\n";                                                                                                                                                                   \
0310                 ClrBits(4);                                                                                                                                                                                                                    \
0311                 EOLcnt = 1;                                                                                                                                                                                                                    \
0312                 goto eolab;                                                                                                                                                                                                                    \
0313                 break;                                                                                                                                                                                                                         \
0314             default:                                                                                                                                                                                                                           \
0315                 unexpected("MainTable", LineNum);                                                                                                                                                                                              \
0316                 SKIP_EOL;                                                                                                                                                                                                                      \
0317                 break;                                                                                                                                                                                                                         \
0318             }                                                                                                                                                                                                                                  \
0319         }                                                                                                                                                                                                                                      \
0320         if (RunLength) {                                                                                                                                                                                                                       \
0321             if (RunLength + a0 < lastx) {                                                                                                                                                                                                      \
0322                 /* expect a final V0 */                                                                                                                                                                                                        \
0323                 NeedBits(1);                                                                                                                                                                                                                   \
0324                 if (!GetBits(1)) {                                                                                                                                                                                                             \
0325                     unexpected("MainTable", LineNum);                                                                                                                                                                                          \
0326                     SKIP_EOL;                                                                                                                                                                                                                  \
0327                 }                                                                                                                                                                                                                              \
0328                 ClrBits(1);                                                                                                                                                                                                                    \
0329             }                                                                                                                                                                                                                                  \
0330             SETVAL(0);                                                                                                                                                                                                                         \
0331         }                                                                                                                                                                                                                                      \
0332         eol2lab;                                                                                                                                                                                                                               \
0333     } while (0)
0334 
0335 static void unexpected(const char *what, int LineNum)
0336 {
0337     if (verbose) {
0338         qCCritical(FAX_LOG) << "Line " << LineNum << ": Unexpected state in " << what;
0339     }
0340 }
0341 
0342 /* Expand tiff modified huffman data (g3-1d without EOLs) */
0343 void MHexpand(pagenode *pn, drawfunc df)
0344 {
0345     int a0;         /* reference element */
0346     int lastx;      /* copy line width to register */
0347     t32bits BitAcc; /* bit accumulator */
0348     int BitsAvail;  /* # valid bits in BitAcc */
0349     int RunLength;  /* Length of current run */
0350     t16bits *sp;    /* pointer into compressed data */
0351     pixnum *pa;     /* pointer into new line */
0352     int EOLcnt;     /* number of consecutive EOLs */
0353     int LineNum;    /* line number */
0354     pixnum *runs;   /* list of run lengths */
0355     struct tabent *TabEnt;
0356 
0357     sp = pn->data;
0358     BitAcc = 0;
0359     BitsAvail = 0;
0360     lastx = pn->size.width();
0361     runs = (pixnum *)malloc(lastx * sizeof(pixnum));
0362     for (LineNum = 0; LineNum < pn->rowsperstrip;) {
0363 #ifdef DEBUG_FAX
0364         printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
0365         printf("-------------------- %d\n", LineNum);
0366         fflush(stdout);
0367 #endif
0368         RunLength = 0;
0369         pa = runs;
0370         a0 = 0;
0371         EOLcnt = 0;
0372         if (BitsAvail & 7) { /* skip to byte boundary */
0373             ClrBits(BitsAvail & 7);
0374         }
0375         expand1d();
0376         if (RunLength) {
0377             SETVAL(0);
0378         }
0379         if (a0 != lastx) {
0380             if (verbose) {
0381                 qCWarning(FAX_LOG) << "Line " << LineNum << ": length is " << a0 << " (expected " << lastx << ")\n";
0382             }
0383             while (a0 > lastx) {
0384                 a0 -= *--pa;
0385             }
0386             if (a0 < lastx) {
0387                 if ((pa - runs) & 1) {
0388                     SETVAL(0);
0389                 }
0390                 SETVAL(lastx - a0);
0391             }
0392         }
0393         (*df)(runs, LineNum++, pn);
0394     }
0395     free(runs);
0396     (void)EOLcnt; // make gcc happy
0397 }
0398 
0399 /* Expand group-3 1-dimensional data */
0400 void g31expand(pagenode *pn, drawfunc df)
0401 {
0402     int a0;         /* reference element */
0403     int lastx;      /* copy line width to register */
0404     t32bits BitAcc; /* bit accumulator */
0405     int BitsAvail;  /* # valid bits in BitAcc */
0406     int RunLength;  /* Length of current run */
0407     t16bits *sp;    /* pointer into compressed data */
0408     pixnum *pa;     /* pointer into new line */
0409     int EOLcnt;     /* number of consecutive EOLs */
0410     int LineNum;    /* line number */
0411     pixnum *runs;   /* list of run lengths */
0412     struct tabent *TabEnt;
0413 
0414     sp = pn->data;
0415     BitAcc = 0;
0416     BitsAvail = 0;
0417     lastx = pn->size.width();
0418     runs = (pixnum *)malloc(lastx * sizeof(pixnum));
0419     EOLcnt = 0;
0420     for (LineNum = 0; LineNum < pn->rowsperstrip;) {
0421 #ifdef DEBUG_FAX
0422         fprintf(stderr, "\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
0423         fprintf(stderr, "-------------------- %d\n", LineNum);
0424         fflush(stderr);
0425 #endif
0426         if (EOLcnt == 0) {
0427             while (!EndOfData(pn)) {
0428                 /* skip over garbage after a coding error */
0429                 NeedBits(11);
0430                 if (GetBits(11) == 0) {
0431                     break;
0432                 }
0433                 ClrBits(1);
0434             }
0435         }
0436         for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
0437             /* we have seen 11 zeros, which implies EOL,
0438                skip possible fill bits too */
0439             while (true) {
0440                 NeedBits(8);
0441                 if (GetBits(8)) {
0442                     break;
0443                 }
0444                 ClrBits(8);
0445             }
0446             while (GetBits(1) == 0) {
0447                 ClrBits(1);
0448             }
0449             ClrBits(1); /* the eol flag */
0450             NeedBits(11);
0451             if (GetBits(11)) {
0452                 break;
0453             }
0454             ClrBits(11);
0455         }
0456         if (EOLcnt > 1 && EOLcnt != 6 && verbose) {
0457             qCCritical(FAX_LOG) << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n";
0458         }
0459         if (EOLcnt >= 6 || EndOfData(pn)) {
0460             free(runs);
0461             return;
0462         }
0463         RunLength = 0;
0464         pa = runs;
0465         a0 = 0;
0466         EOLcnt = 0;
0467         expand1d();
0468         if (RunLength) {
0469             SETVAL(0);
0470         }
0471         if (a0 != lastx) {
0472             if (verbose) {
0473                 qCWarning(FAX_LOG) << "Line " << LineNum << ": length is " << a0 << " (expected " << lastx << ")\n";
0474             }
0475             while (a0 > lastx) {
0476                 a0 -= *--pa;
0477             }
0478             if (a0 < lastx) {
0479                 if ((pa - runs) & 1) {
0480                     SETVAL(0);
0481                 }
0482                 SETVAL(lastx - a0);
0483             }
0484         }
0485         (*df)(runs, LineNum++, pn);
0486     }
0487     free(runs);
0488 }
0489 
0490 /* Expand group-3 2-dimensional data */
0491 void g32expand(pagenode *pn, drawfunc df)
0492 {
0493     int RunLength;                /* Length of current run */
0494     int a0;                       /* reference element */
0495     int b1;                       /* next change on previous line */
0496     int lastx = pn->size.width(); /* copy line width to register */
0497     pixnum *run0, *run1;          /* run length arrays */
0498     pixnum *thisrun, *pa, *pb;    /* pointers into runs */
0499     t16bits *sp;                  /* pointer into compressed data */
0500     t32bits BitAcc;               /* bit accumulator */
0501     int BitsAvail;                /* # valid bits in BitAcc */
0502     int EOLcnt;                   /* number of consecutive EOLs */
0503     int refline = 0;              /* 1D encoded reference line */
0504     int LineNum;                  /* line number */
0505     struct tabent *TabEnt;
0506 
0507     sp = pn->data;
0508     BitAcc = 0;
0509     BitsAvail = 0;
0510     /* allocate space for 2 runlength arrays */
0511     run0 = (pixnum *)malloc(2 * ((lastx + 5) & ~1) * sizeof(pixnum));
0512     run1 = run0 + ((lastx + 5) & ~1);
0513     run1[0] = lastx;
0514     run1[1] = 0;
0515     EOLcnt = 0;
0516     for (LineNum = 0; LineNum < pn->rowsperstrip;) {
0517 #ifdef DEBUG_FAX
0518         printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
0519         printf("-------------------- %d\n", LineNum);
0520         fflush(stdout);
0521 #endif
0522         if (EOLcnt == 0) {
0523             while (!EndOfData(pn)) {
0524                 /* skip over garbage after a coding error */
0525                 NeedBits(11);
0526                 if (GetBits(11) == 0) {
0527                     break;
0528                 }
0529                 ClrBits(1);
0530             }
0531         }
0532         for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
0533             /* we have seen 11 zeros, which implies EOL,
0534                skip possible fill bits too */
0535             while (true) {
0536                 NeedBits(8);
0537                 if (GetBits(8)) {
0538                     break;
0539                 }
0540                 ClrBits(8);
0541             }
0542             while (GetBits(1) == 0) {
0543                 ClrBits(1);
0544             }
0545             ClrBits(1); /* the eol flag */
0546             NeedBits(12);
0547             refline = GetBits(1); /* 1D / 2D flag */
0548             ClrBits(1);
0549             if (GetBits(11)) {
0550                 break;
0551             }
0552             ClrBits(11);
0553         }
0554         if (EOLcnt > 1 && EOLcnt != 6 && verbose) {
0555             qCCritical(FAX_LOG) << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n";
0556         }
0557         if (EOLcnt >= 6 || EndOfData(pn)) {
0558             free(run0);
0559             return;
0560         }
0561         if (LineNum == 0 && refline == 0 && verbose) {
0562             qCDebug(FAX_LOG) << "First line is 2-D encoded\n";
0563         }
0564         RunLength = 0;
0565         if (LineNum & 1) {
0566             pa = run1;
0567             pb = run0;
0568         } else {
0569             pa = run0;
0570             pb = run1;
0571         }
0572         thisrun = pa;
0573         EOLcnt = 0;
0574         a0 = 0;
0575         b1 = *pb++;
0576 
0577         if (refline) {
0578             expand1d();
0579         } else {
0580             expand2d(EOL2);
0581         }
0582         if (RunLength) {
0583             SETVAL(0);
0584         }
0585         if (a0 != lastx) {
0586             if (verbose) {
0587                 qCWarning(FAX_LOG) << "Line " << LineNum << ": length is " << a0 << " (expected " << lastx << ")\n";
0588             }
0589             while (a0 > lastx) {
0590                 a0 -= *--pa;
0591             }
0592             if (a0 < lastx) {
0593                 if ((pa - run0) & 1) {
0594                     SETVAL(0);
0595                 }
0596                 SETVAL(lastx - a0);
0597             }
0598         }
0599         SETVAL(0); /* imaginary change at end of line for reference */
0600         (*df)(thisrun, LineNum++, pn);
0601     }
0602     free(run0);
0603 }
0604 
0605 /* Redefine the "skip to eol" macro.  We cannot recover from coding
0606    errors in G4 data */
0607 #undef SKIP_EOL
0608 #undef eol2lab
0609 #define SKIP_EOL                                                                                                                                                                                                                               \
0610     do {                                                                                                                                                                                                                                       \
0611         if (verbose)                                                                                                                                                                                                                           \
0612             qCCritical(FAX_LOG) << "Line " << LineNum << ": G4 coding error\n";                                                                                                                                                                \
0613         free(run0);                                                                                                                                                                                                                            \
0614         return;                                                                                                                                                                                                                                \
0615     } while (0)
0616 #define eol2lab
0617 
0618 /* Expand group-4 data */
0619 void g4expand(pagenode *pn, drawfunc df)
0620 {
0621     int RunLength;                /* Length of current run */
0622     int a0;                       /* reference element */
0623     int b1;                       /* next change on previous line */
0624     int lastx = pn->size.width(); /* copy line width to register */
0625     pixnum *run0, *run1;          /* run length arrays */
0626     pixnum *thisrun, *pa, *pb;    /* pointers into runs */
0627     t16bits *sp;                  /* pointer into compressed data */
0628     t32bits BitAcc;               /* bit accumulator */
0629     int BitsAvail;                /* # valid bits in BitAcc */
0630     int LineNum;                  /* line number */
0631     int EOLcnt;
0632     struct tabent *TabEnt;
0633 
0634     sp = pn->data;
0635     BitAcc = 0;
0636     BitsAvail = 0;
0637     /* allocate space for 2 runlength arrays */
0638     run0 = (pixnum *)malloc(2 * ((lastx + 5) & ~1) * sizeof(pixnum));
0639     run1 = run0 + ((lastx + 5) & ~1);
0640     run1[0] = lastx; /* initial reference line */
0641     run1[1] = 0;
0642 
0643     for (LineNum = 0; LineNum < pn->rowsperstrip;) {
0644 #ifdef DEBUG_FAX
0645         printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
0646         printf("-------------------- %d\n", LineNum);
0647         fflush(stdout);
0648 #endif
0649         RunLength = 0;
0650         if (LineNum & 1) {
0651             pa = run1;
0652             pb = run0;
0653         } else {
0654             pa = run0;
0655             pb = run1;
0656         }
0657         thisrun = pa;
0658         a0 = 0;
0659         b1 = *pb++;
0660         expand2d(EOFB);
0661         if (a0 < lastx) {
0662             if ((pa - run0) & 1) {
0663                 SETVAL(0);
0664             }
0665             SETVAL(lastx - a0);
0666         }
0667         SETVAL(0); /* imaginary change at end of line for reference */
0668         (*df)(thisrun, LineNum++, pn);
0669         continue;
0670     EOFB:
0671         NeedBits(13);
0672         if (GetBits(13) != 0x1001 && verbose) {
0673             qCCritical(FAX_LOG) << "Bad RTC\n";
0674         }
0675         break;
0676     }
0677     free(run0);
0678     (void)EOLcnt; // make gcc happy
0679 }
0680 
0681 static const unsigned char zerotab[256] = {0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05, 0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04, 0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03, 0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
0682                                            0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, 0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02, 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
0683                                            0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
0684                                            0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01, 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
0685                                            0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
0686                                            0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
0687                                            0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
0688                                            0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00, 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00};
0689 
0690 #define check(v)                                                                                                                                                                                                                               \
0691     do {                                                                                                                                                                                                                                       \
0692         prezeros = zerotab[v];                                                                                                                                                                                                                 \
0693         postzeros = prezeros & 15;                                                                                                                                                                                                             \
0694         prezeros >>= 4;                                                                                                                                                                                                                        \
0695         if (prezeros == 8) {                                                                                                                                                                                                                   \
0696             zeros += 8;                                                                                                                                                                                                                        \
0697             break;                                                                                                                                                                                                                             \
0698         }                                                                                                                                                                                                                                      \
0699         if (zeros + prezeros < 11) {                                                                                                                                                                                                           \
0700             empty = 0;                                                                                                                                                                                                                         \
0701             zeros = postzeros;                                                                                                                                                                                                                 \
0702             break;                                                                                                                                                                                                                             \
0703         }                                                                                                                                                                                                                                      \
0704         zeros = postzeros;                                                                                                                                                                                                                     \
0705         if (empty)                                                                                                                                                                                                                             \
0706             EOLcnt++;                                                                                                                                                                                                                          \
0707         lines++;                                                                                                                                                                                                                               \
0708         empty = 1;                                                                                                                                                                                                                             \
0709     } while (false)
0710 
0711 /* count fax lines */
0712 int G3count(pagenode *pn, int twoD)
0713 {
0714     t16bits *p = pn->data;
0715     t16bits *end = p + pn->length / sizeof(*p);
0716     int lines = 0;  /* lines seen so far */
0717     int zeros = 0;  /* number of consecutive zero bits seen */
0718     int EOLcnt = 0; /* number of consecutive EOLs seen */
0719     int empty = 1;  /* empty line */
0720     int prezeros, postzeros;
0721 
0722     while (p < end && EOLcnt < 6) {
0723         t16bits bits = *p++;
0724         check(bits & 255);
0725         if (twoD && (prezeros + postzeros == 7)) {
0726             if (postzeros || ((bits & 0x100) == 0)) {
0727                 zeros--;
0728             }
0729         }
0730         check(bits >> 8);
0731         if (twoD && (prezeros + postzeros == 7)) {
0732             if (postzeros || ((p < end) && ((*p & 1) == 0))) {
0733                 zeros--;
0734             }
0735         }
0736     }
0737     return lines - EOLcnt; /* don't count trailing EOLs */
0738 }