| /* |
| * Copyright (c) 1990-1997 Sam Leffler |
| * Copyright (c) 1991-1997 Silicon Graphics, Inc. |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and |
| * its documentation for any purpose is hereby granted without fee, provided |
| * that (i) the above copyright notices and this permission notice appear in |
| * all copies of the software and related documentation, and (ii) the names of |
| * Sam Leffler and Silicon Graphics may not be used in any advertising or |
| * publicity relating to the software without the specific, prior written |
| * permission of Sam Leffler and Silicon Graphics. |
| * |
| * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY |
| * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. |
| * |
| * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR |
| * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, |
| * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
| * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF |
| * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
| * OF THIS SOFTWARE. |
| */ |
| |
| #ifndef _FAX3_ |
| #define _FAX3_ |
| /* |
| * TIFF Library. |
| * |
| * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support. |
| * |
| * Decoder support is derived, with permission, from the code |
| * in Frank Cringle's viewfax program; |
| * Copyright (C) 1990, 1995 Frank D. Cringle. |
| */ |
| #include "tiff.h" |
| |
| /* |
| * To override the default routine used to image decoded |
| * spans one can use the pseudo tag TIFFTAG_FAXFILLFUNC. |
| * The routine must have the type signature given below; |
| * for example: |
| * |
| * fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx) |
| * |
| * where buf is place to set the bits, runs is the array of b&w run |
| * lengths (white then black), erun is the last run in the array, and |
| * lastx is the width of the row in pixels. Fill routines can assume |
| * the run array has room for at least lastx runs and can overwrite |
| * data in the run array as needed (e.g. to append zero runs to bring |
| * the count up to a nice multiple). |
| */ |
| typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32); |
| |
| /* |
| * The default run filler; made external for other decoders. |
| */ |
| #if defined(__cplusplus) |
| extern "C" { |
| #endif |
| extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32); |
| #if defined(__cplusplus) |
| } |
| #endif |
| |
| |
| /* finite state machine codes */ |
| #define S_Null 0 |
| #define S_Pass 1 |
| #define S_Horiz 2 |
| #define S_V0 3 |
| #define S_VR 4 |
| #define S_VL 5 |
| #define S_Ext 6 |
| #define S_TermW 7 |
| #define S_TermB 8 |
| #define S_MakeUpW 9 |
| #define S_MakeUpB 10 |
| #define S_MakeUp 11 |
| #define S_EOL 12 |
| |
| /* WARNING: do not change the layout of this structure as the HylaFAX software */ |
| /* really depends on it. See http://bugzilla.maptools.org/show_bug.cgi?id=2636 */ |
| typedef struct { /* state table entry */ |
| unsigned char State; /* see above */ |
| unsigned char Width; /* width of code in bits */ |
| uint32 Param; /* unsigned 32-bit run length in bits (holds on 16 bit actually, but cannot be changed. See above warning) */ |
| } TIFFFaxTabEnt; |
| |
| extern const TIFFFaxTabEnt TIFFFaxMainTable[]; |
| extern const TIFFFaxTabEnt TIFFFaxWhiteTable[]; |
| extern const TIFFFaxTabEnt TIFFFaxBlackTable[]; |
| |
| /* |
| * The following macros define the majority of the G3/G4 decoder |
| * algorithm using the state tables defined elsewhere. To build |
| * a decoder you need some setup code and some glue code. Note |
| * that you may also need/want to change the way the NeedBits* |
| * macros get input data if, for example, you know the data to be |
| * decoded is properly aligned and oriented (doing so before running |
| * the decoder can be a big performance win). |
| * |
| * Consult the decoder in the TIFF library for an idea of what you |
| * need to define and setup to make use of these definitions. |
| * |
| * NB: to enable a debugging version of these macros define FAX3_DEBUG |
| * before including this file. Trace output goes to stdout. |
| */ |
| |
| #ifndef EndOfData |
| #define EndOfData() (cp >= ep) |
| #endif |
| /* |
| * Need <=8 or <=16 bits of input data. Unlike viewfax we |
| * cannot use/assume a word-aligned, properly bit swizzled |
| * input data set because data may come from an arbitrarily |
| * aligned, read-only source such as a memory-mapped file. |
| * Note also that the viewfax decoder does not check for |
| * running off the end of the input data buffer. This is |
| * possible for G3-encoded data because it prescans the input |
| * data to count EOL markers, but can cause problems for G4 |
| * data. In any event, we don't prescan and must watch for |
| * running out of data since we can't permit the library to |
| * scan past the end of the input data buffer. |
| * |
| * Finally, note that we must handle remaindered data at the end |
| * of a strip specially. The coder asks for a fixed number of |
| * bits when scanning for the next code. This may be more bits |
| * than are actually present in the data stream. If we appear |
| * to run out of data but still have some number of valid bits |
| * remaining then we makeup the requested amount with zeros and |
| * return successfully. If the returned data is incorrect then |
| * we should be called again and get a premature EOF error; |
| * otherwise we should get the right answer. |
| */ |
| #ifndef NeedBits8 |
| #define NeedBits8(n,eoflab) do { \ |
| if (BitsAvail < (n)) { \ |
| if (EndOfData()) { \ |
| if (BitsAvail == 0) /* no valid bits */ \ |
| goto eoflab; \ |
| BitsAvail = (n); /* pad with zeros */ \ |
| } else { \ |
| BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \ |
| BitsAvail += 8; \ |
| } \ |
| } \ |
| } while (0) |
| #endif |
| #ifndef NeedBits16 |
| #define NeedBits16(n,eoflab) do { \ |
| if (BitsAvail < (n)) { \ |
| if (EndOfData()) { \ |
| if (BitsAvail == 0) /* no valid bits */ \ |
| goto eoflab; \ |
| BitsAvail = (n); /* pad with zeros */ \ |
| } else { \ |
| BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \ |
| if ((BitsAvail += 8) < (n)) { \ |
| if (EndOfData()) { \ |
| /* NB: we know BitsAvail is non-zero here */ \ |
| BitsAvail = (n); /* pad with zeros */ \ |
| } else { \ |
| BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \ |
| BitsAvail += 8; \ |
| } \ |
| } \ |
| } \ |
| } \ |
| } while (0) |
| #endif |
| #define GetBits(n) (BitAcc & ((1<<(n))-1)) |
| #define ClrBits(n) do { \ |
| BitsAvail -= (n); \ |
| BitAcc >>= (n); \ |
| } while (0) |
| |
| #ifdef FAX3_DEBUG |
| static const char* StateNames[] = { |
| "Null ", |
| "Pass ", |
| "Horiz ", |
| "V0 ", |
| "VR ", |
| "VL ", |
| "Ext ", |
| "TermW ", |
| "TermB ", |
| "MakeUpW", |
| "MakeUpB", |
| "MakeUp ", |
| "EOL ", |
| }; |
| #define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0') |
| #define LOOKUP8(wid,tab,eoflab) do { \ |
| int t; \ |
| NeedBits8(wid,eoflab); \ |
| TabEnt = tab + GetBits(wid); \ |
| printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ |
| StateNames[TabEnt->State], TabEnt->Param); \ |
| for (t = 0; t < TabEnt->Width; t++) \ |
| DEBUG_SHOW; \ |
| putchar('\n'); \ |
| fflush(stdout); \ |
| ClrBits(TabEnt->Width); \ |
| } while (0) |
| #define LOOKUP16(wid,tab,eoflab) do { \ |
| int t; \ |
| NeedBits16(wid,eoflab); \ |
| TabEnt = tab + GetBits(wid); \ |
| printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \ |
| StateNames[TabEnt->State], TabEnt->Param); \ |
| for (t = 0; t < TabEnt->Width; t++) \ |
| DEBUG_SHOW; \ |
| putchar('\n'); \ |
| fflush(stdout); \ |
| ClrBits(TabEnt->Width); \ |
| } while (0) |
| |
| #define SETVALUE(x) do { \ |
| *pa++ = RunLength + (x); \ |
| printf("SETVALUE: %d\t%d\n", RunLength + (x), a0); \ |
| a0 += x; \ |
| RunLength = 0; \ |
| } while (0) |
| #else |
| #define LOOKUP8(wid,tab,eoflab) do { \ |
| NeedBits8(wid,eoflab); \ |
| TabEnt = tab + GetBits(wid); \ |
| ClrBits(TabEnt->Width); \ |
| } while (0) |
| #define LOOKUP16(wid,tab,eoflab) do { \ |
| NeedBits16(wid,eoflab); \ |
| TabEnt = tab + GetBits(wid); \ |
| ClrBits(TabEnt->Width); \ |
| } while (0) |
| |
| /* |
| * Append a run to the run length array for the |
| * current row and reset decoding state. |
| */ |
| #define SETVALUE(x) do { \ |
| if (pa >= thisrun + sp->nruns) { \ |
| TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ |
| sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ |
| return (-1); \ |
| } \ |
| *pa++ = RunLength + (x); \ |
| a0 += (x); \ |
| RunLength = 0; \ |
| } while (0) |
| #endif |
| |
| /* |
| * Synchronize input decoding at the start of each |
| * row by scanning for an EOL (if appropriate) and |
| * skipping any trash data that might be present |
| * after a decoding error. Note that the decoding |
| * done elsewhere that recognizes an EOL only consumes |
| * 11 consecutive zero bits. This means that if EOLcnt |
| * is non-zero then we still need to scan for the final flag |
| * bit that is part of the EOL code. |
| */ |
| #define SYNC_EOL(eoflab) do { \ |
| if (EOLcnt == 0) { \ |
| for (;;) { \ |
| NeedBits16(11,eoflab); \ |
| if (GetBits(11) == 0) \ |
| break; \ |
| ClrBits(1); \ |
| } \ |
| } \ |
| for (;;) { \ |
| NeedBits8(8,eoflab); \ |
| if (GetBits(8)) \ |
| break; \ |
| ClrBits(8); \ |
| } \ |
| while (GetBits(1) == 0) \ |
| ClrBits(1); \ |
| ClrBits(1); /* EOL bit */ \ |
| EOLcnt = 0; /* reset EOL counter/flag */ \ |
| } while (0) |
| |
| /* |
| * Cleanup the array of runs after decoding a row. |
| * We adjust final runs to insure the user buffer is not |
| * overwritten and/or undecoded area is white filled. |
| */ |
| #define CLEANUP_RUNS() do { \ |
| if (RunLength) \ |
| SETVALUE(0); \ |
| if (a0 != lastx) { \ |
| badlength(a0, lastx); \ |
| while (a0 > lastx && pa > thisrun) \ |
| a0 -= *--pa; \ |
| if (a0 < lastx) { \ |
| if (a0 < 0) \ |
| a0 = 0; \ |
| if ((pa-thisrun)&1) \ |
| SETVALUE(0); \ |
| SETVALUE(lastx - a0); \ |
| } else if (a0 > lastx) { \ |
| SETVALUE(lastx); \ |
| SETVALUE(0); \ |
| } \ |
| } \ |
| } while (0) |
| |
| /* |
| * Decode a line of 1D-encoded data. |
| * |
| * The line expanders are written as macros so that they can be reused |
| * but still have direct access to the local variables of the "calling" |
| * function. |
| * |
| * Note that unlike the original version we have to explicitly test for |
| * a0 >= lastx after each black/white run is decoded. This is because |
| * the original code depended on the input data being zero-padded to |
| * insure the decoder recognized an EOL before running out of data. |
| */ |
| #define EXPAND1D(eoflab) do { \ |
| for (;;) { \ |
| for (;;) { \ |
| LOOKUP16(12, TIFFFaxWhiteTable, eof1d); \ |
| switch (TabEnt->State) { \ |
| case S_EOL: \ |
| EOLcnt = 1; \ |
| goto done1d; \ |
| case S_TermW: \ |
| SETVALUE(TabEnt->Param); \ |
| goto doneWhite1d; \ |
| case S_MakeUpW: \ |
| case S_MakeUp: \ |
| a0 += TabEnt->Param; \ |
| RunLength += TabEnt->Param; \ |
| break; \ |
| default: \ |
| unexpected("WhiteTable", a0); \ |
| goto done1d; \ |
| } \ |
| } \ |
| doneWhite1d: \ |
| if (a0 >= lastx) \ |
| goto done1d; \ |
| for (;;) { \ |
| LOOKUP16(13, TIFFFaxBlackTable, eof1d); \ |
| switch (TabEnt->State) { \ |
| case S_EOL: \ |
| EOLcnt = 1; \ |
| goto done1d; \ |
| case S_TermB: \ |
| SETVALUE(TabEnt->Param); \ |
| goto doneBlack1d; \ |
| case S_MakeUpB: \ |
| case S_MakeUp: \ |
| a0 += TabEnt->Param; \ |
| RunLength += TabEnt->Param; \ |
| break; \ |
| default: \ |
| unexpected("BlackTable", a0); \ |
| goto done1d; \ |
| } \ |
| } \ |
| doneBlack1d: \ |
| if (a0 >= lastx) \ |
| goto done1d; \ |
| if( *(pa-1) == 0 && *(pa-2) == 0 ) \ |
| pa -= 2; \ |
| } \ |
| eof1d: \ |
| prematureEOF(a0); \ |
| CLEANUP_RUNS(); \ |
| goto eoflab; \ |
| done1d: \ |
| CLEANUP_RUNS(); \ |
| } while (0) |
| |
| /* |
| * Update the value of b1 using the array |
| * of runs for the reference line. |
| */ |
| #define CHECK_b1 do { \ |
| if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \ |
| if( pb + 1 >= sp->refruns + sp->nruns) { \ |
| TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ |
| sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ |
| return (-1); \ |
| } \ |
| b1 += pb[0] + pb[1]; \ |
| pb += 2; \ |
| } \ |
| } while (0) |
| |
| /* |
| * Expand a row of 2D-encoded data. |
| */ |
| #define EXPAND2D(eoflab) do { \ |
| while (a0 < lastx) { \ |
| if (pa >= thisrun + sp->nruns) { \ |
| TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ |
| sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ |
| return (-1); \ |
| } \ |
| LOOKUP8(7, TIFFFaxMainTable, eof2d); \ |
| switch (TabEnt->State) { \ |
| case S_Pass: \ |
| CHECK_b1; \ |
| if( pb + 1 >= sp->refruns + sp->nruns) { \ |
| TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ |
| sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ |
| return (-1); \ |
| } \ |
| b1 += *pb++; \ |
| RunLength += b1 - a0; \ |
| a0 = b1; \ |
| b1 += *pb++; \ |
| break; \ |
| case S_Horiz: \ |
| if ((pa-thisrun)&1) { \ |
| for (;;) { /* black first */ \ |
| LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ |
| switch (TabEnt->State) { \ |
| case S_TermB: \ |
| SETVALUE(TabEnt->Param); \ |
| goto doneWhite2da; \ |
| case S_MakeUpB: \ |
| case S_MakeUp: \ |
| a0 += TabEnt->Param; \ |
| RunLength += TabEnt->Param; \ |
| break; \ |
| default: \ |
| goto badBlack2d; \ |
| } \ |
| } \ |
| doneWhite2da:; \ |
| for (;;) { /* then white */ \ |
| LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ |
| switch (TabEnt->State) { \ |
| case S_TermW: \ |
| SETVALUE(TabEnt->Param); \ |
| goto doneBlack2da; \ |
| case S_MakeUpW: \ |
| case S_MakeUp: \ |
| a0 += TabEnt->Param; \ |
| RunLength += TabEnt->Param; \ |
| break; \ |
| default: \ |
| goto badWhite2d; \ |
| } \ |
| } \ |
| doneBlack2da:; \ |
| } else { \ |
| for (;;) { /* white first */ \ |
| LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \ |
| switch (TabEnt->State) { \ |
| case S_TermW: \ |
| SETVALUE(TabEnt->Param); \ |
| goto doneWhite2db; \ |
| case S_MakeUpW: \ |
| case S_MakeUp: \ |
| a0 += TabEnt->Param; \ |
| RunLength += TabEnt->Param; \ |
| break; \ |
| default: \ |
| goto badWhite2d; \ |
| } \ |
| } \ |
| doneWhite2db:; \ |
| for (;;) { /* then black */ \ |
| LOOKUP16(13, TIFFFaxBlackTable, eof2d); \ |
| switch (TabEnt->State) { \ |
| case S_TermB: \ |
| SETVALUE(TabEnt->Param); \ |
| goto doneBlack2db; \ |
| case S_MakeUpB: \ |
| case S_MakeUp: \ |
| a0 += TabEnt->Param; \ |
| RunLength += TabEnt->Param; \ |
| break; \ |
| default: \ |
| goto badBlack2d; \ |
| } \ |
| } \ |
| doneBlack2db:; \ |
| } \ |
| CHECK_b1; \ |
| break; \ |
| case S_V0: \ |
| CHECK_b1; \ |
| SETVALUE(b1 - a0); \ |
| if( pb >= sp->refruns + sp->nruns) { \ |
| TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ |
| sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ |
| return (-1); \ |
| } \ |
| b1 += *pb++; \ |
| break; \ |
| case S_VR: \ |
| CHECK_b1; \ |
| SETVALUE(b1 - a0 + TabEnt->Param); \ |
| if( pb >= sp->refruns + sp->nruns) { \ |
| TIFFErrorExt(tif->tif_clientdata, module, "Buffer overflow at line %u of %s %u", \ |
| sp->line, isTiled(tif) ? "tile" : "strip", isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip); \ |
| return (-1); \ |
| } \ |
| b1 += *pb++; \ |
| break; \ |
| case S_VL: \ |
| CHECK_b1; \ |
| if (b1 < (int) (a0 + TabEnt->Param)) { \ |
| unexpected("VL", a0); \ |
| goto eol2d; \ |
| } \ |
| SETVALUE(b1 - a0 - TabEnt->Param); \ |
| b1 -= *--pb; \ |
| break; \ |
| case S_Ext: \ |
| *pa++ = lastx - a0; \ |
| extension(a0); \ |
| goto eol2d; \ |
| case S_EOL: \ |
| *pa++ = lastx - a0; \ |
| NeedBits8(4,eof2d); \ |
| if (GetBits(4)) \ |
| unexpected("EOL", a0); \ |
| ClrBits(4); \ |
| EOLcnt = 1; \ |
| goto eol2d; \ |
| default: \ |
| badMain2d: \ |
| unexpected("MainTable", a0); \ |
| goto eol2d; \ |
| badBlack2d: \ |
| unexpected("BlackTable", a0); \ |
| goto eol2d; \ |
| badWhite2d: \ |
| unexpected("WhiteTable", a0); \ |
| goto eol2d; \ |
| eof2d: \ |
| prematureEOF(a0); \ |
| CLEANUP_RUNS(); \ |
| goto eoflab; \ |
| } \ |
| } \ |
| if (RunLength) { \ |
| if (RunLength + a0 < lastx) { \ |
| /* expect a final V0 */ \ |
| NeedBits8(1,eof2d); \ |
| if (!GetBits(1)) \ |
| goto badMain2d; \ |
| ClrBits(1); \ |
| } \ |
| SETVALUE(0); \ |
| } \ |
| eol2d: \ |
| CLEANUP_RUNS(); \ |
| } while (0) |
| #endif /* _FAX3_ */ |
| /* vim: set ts=8 sts=4 sw=4 noet: */ |
| /* |
| * Local Variables: |
| * mode: c |
| * c-basic-offset: 8 |
| * fill-column: 78 |
| * End: |
| */ |