diff options
Diffstat (limited to 'graphics/sam2p/pts_lzw.c')
-rw-r--r-- | graphics/sam2p/pts_lzw.c | 1490 |
1 files changed, 1490 insertions, 0 deletions
diff --git a/graphics/sam2p/pts_lzw.c b/graphics/sam2p/pts_lzw.c new file mode 100644 index 0000000000..4d6b9439b0 --- /dev/null +++ b/graphics/sam2p/pts_lzw.c @@ -0,0 +1,1490 @@ +#define DUMMY \ +set -ex; \ +g++ -DNDEBUG=1 -O3 -ansi -pedantic \ + -Wall -W -Wstrict-prototypes -Wtraditional -Wnested-externs -Winline \ + -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wmissing-prototypes \ + -Wmissing-declarations pts_lzw.c -c; \ +exit +/* pts_lzw.c -- a real, effective implementation of PostScript + * LanguageLevel2 and PDF /LZWEncode and /LZWDecode filters (same as the LZW + * compression used in TIFF raster image files) + * + * based on tif_lzw.c in libtiff-v3.4beta037 by Sam Leffler and Silicon Graphics. + * by pts@fazekas.hu at Sun Dec 30 15:04:19 CET 2001 + * encoding and decoding works at Sun Dec 30 17:05:23 CET 2001 + * modified for sam2p at Mon Mar 4 00:21:59 CET 2002 + * + * Note that the LZW compression (but not uncompression) is patented by + * Unisys (patent number #4,558,302), so use this program at your own legal + * risk! + * + * Predictors and PostScript LanguageLevel3 filter options are not supported. + * + * Test: linux-2.2.8.tar.gz + * -- uncompressed: 58 388 480 bytes + * -- LZWEncode (lzw_codec.c): 26 518 397 bytes (uncompression OK) + * -- FlateEncode (almost gzip): 13 808 890 bytes (uncompression: zcat) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* Imp: check #ifdef _WINDOWS */ +/* Dat: a strip is an interval of rows. Each strip -- probably except for the + * last -- has a same number of rows. Strips are useful for TIFF writers + * to better organize data in memory or disk. + */ + +#ifdef __GNUC__ +#ifndef __clang__ +#pragma implementation +#endif +#endif + +#if _MSC_VER > 1000 +# undef __PROTOTYPES__ +# define __PROTOTYPES__ 1 +# pragma warning(disable: 4127) /* conditional expression is constant */ +# pragma warning(disable: 4244) /* =' : conversion from 'int ' to 'unsigned char ', possible loss of data */ +#endif + + +/* Original: /d1/sam/tiff/libtiff/RCS/tif_lzw.c,v 1.73 1997/08/29 21:45:54 sam Exp */ + +/* + * Copyright (c) 1988-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. + */ + +/**** pts ****/ +#if OBJDEP +# warning PROVIDES: pts_lzw +#endif +#define LZW_SUPPORT 1 +#if 0 /* conflicts with some system defs */ +typedef unsigned short u_short; +typedef unsigned char u_char; +typedef unsigned long u_long; +#endif +#define TO_RDONLY 1 +#define _TIFFmalloc malloc +#define _TIFFfree free +#define _TIFFmemset memset +#include <stdlib.h> +#include <string.h> + +/* + * ``Library-private'' definitions. + */ + +/* + * TIFF I/O Library Definitions. + */ +/* + * Tag Image File Format (TIFF) + * + * Based on Rev 6.0 from: + * Developer's Desk + * Aldus Corporation + * 411 First Ave. South + * Suite 200 + * Seattle, WA 98104 + * 206-622-5500 + */ +#define TIFF_VERSION 42 + +/* + * NB: In the comments below, + * - items marked with a + are obsoleted by revision 5.0, + * - items marked with a ! are introduced in revision 6.0. + * - items marked with a % are introduced post revision 6.0. + * - items marked with a $ are obsoleted by revision 6.0. + */ + +/* --- */ + +/* + * This define can be used in code that requires + * compilation-related definitions specific to a + * version or versions of the library. Runtime + * version checking should be done based on the + * string returned by TIFFGetVersion. + */ +#define TIFFLIB_VERSION 19970127 /* January 27, 1997 */ + +/* + * The following typedefs define the intrinsic size of + * data types used in the *exported* interfaces. These + * definitions depend on the proper definition of types + * in tiff.h. Note also that the varargs interface used + * to pass tag types and values uses the types defined in + * tiff.h directly. + * + * NB: ttag_t is unsigned int and not unsigned short because + * ANSI C requires that the type before the ellipsis be a + * promoted type (i.e. one of int, unsigned int, pointer, + * or double) and because we defined pseudo-tags that are + * outside the range of legal Aldus-assigned tags. + * NB: tsize_t is int32 and not uint32 because some functions + * return -1. + * NB: toff_t is not off_t for many reasons; TIFFs max out at + * 32-bit file offsets being the most important + */ + +#ifndef NULL +#define NULL 0 +#endif + +typedef struct pts_lzw_state TIFF; +#include "pts_lzw.h" + +/**** pts ****/ +static int TIFFInitLZW(TIFF*); +static void TIFFError(char const*a, char const*b); +#if 0 /**** pts ****/ +static void TIFFWarning(char const*a, char const*b, int c); +void TIFFWarning(char const*a, char const*b, int c) { + fprintf(stderr, "Warning: %s: ", a); + fprintf(stderr, b, c); + fprintf(stderr, "\n"); +} +#endif +static int TIFFAppendTo(TIFF*, tidataval_t*, tsize_t); /* tif_write.h */ +#if 0 +static void TIFFReverseBits(unsigned char *, unsigned long); +#endif + +#ifdef LZW_SUPPORT +/* + * TIFF Library. + * Rev 5.0 Lempel-Ziv & Welch Compression Support + * + * This code is derived from the compress program whose code is + * derived from software contributed to Berkeley by James A. Woods, + * derived from original work by Spencer Thomas and Joseph Orost. + * + * The original Berkeley copyright notice appears below in its entirety. + */ + +#include <assert.h> +/* #include <stdio.h> */ + +/* + * Internal version of TIFFFlushData that can be + * called by ``encodestrip routines'' w/o concern + * for infinite recursion. + */ +static int +TIFFFlushData1(TIFF* tif) +{ + if (tif->tif_rawcc > 0) { +#if 0 + if (tif->tif_revbits_p) + TIFFReverseBits((unsigned char *)tif->tif_rawdata, + tif->tif_rawcc); +#endif + if (!TIFFAppendTo(tif, + /* isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip, */ + tif->tif_rawdata, tif->tif_rawcc)) + return (0); + tif->tif_rawcc = 0; + tif->tif_rawcp = tif->tif_rawdata; + } + return (1); +} + + + +/* + * NB: The 5.0 spec describes a different algorithm than Aldus + * implements. Specifically, Aldus does code length transitions + * one code earlier than should be done (for real LZW). + * Earlier versions of this library implemented the correct + * LZW algorithm, but emitted codes in a bit order opposite + * to the TIFF spec. Thus, to maintain compatibility w/ Aldus + * we interpret MSB-LSB ordered codes to be images written w/ + * old versions of this library, but otherwise adhere to the + * Aldus "off by one" algorithm. + * + * Future revisions to the TIFF spec are expected to "clarify this issue". + */ +#define LZW_COMPAT /* include backwards compatibility code */ +/* + * Each strip of data is supposed to be terminated by a CODE_EOI. + * If the following #define is included, the decoder will also + * check for end-of-strip w/o seeing this code. This makes the + * library more robust, but also slower. + */ +#define LZW_CHECKEOS /* include checks for strips w/o EOI code */ +#undef LZW_CHECKEOS /**** pts ****/ + +#define MAXCODE(n) ((1L<<(n))-1) +/* + * The TIFF spec specifies that encoded bit + * strings range from 9 to 12 bits. + */ +#define BITS_MIN 9 /* start with 9 bits */ +#define BITS_MAX 12 /* max of 12 bit strings */ +/* predefined codes */ +#define CODE_CLEAR 256 /* code to clear string table */ +#define CODE_EOI 257 /* end-of-information code */ +#define CODE_FIRST 258 /* first free code entry */ +#define CODE_MAX MAXCODE(BITS_MAX) +#define HSIZE 9001L /* 91% occupancy */ +#define HSHIFT (13-8) +#ifdef LZW_COMPAT +/* NB: +1024 is for compatibility with old files */ +#define CSIZE (MAXCODE(BITS_MAX)+1024L) +#else +#define CSIZE (MAXCODE(BITS_MAX)+1L) +#endif + +/* + * State block for each open TIFF file using LZW + * compression/decompression. Note that the predictor + * state block must be first in this data structure. + */ +typedef struct { +#if 0 /****pts****/ + TIFFPredictorState predict; /* predictor super class */ +#endif + + unsigned short nbits; /* # of bits/code */ + unsigned short maxcode; /* maximum code for lzw_nbits */ + unsigned short free_ent; /* next free entry in hash table */ + long nextdata; /* next bits of i/o */ + long nextbits; /* # of valid bits in lzw_nextdata */ +} LZWBaseState; + +#define lzw_nbits base.nbits +#define lzw_maxcode base.maxcode +#define lzw_free_ent base.free_ent +#define lzw_nextdata base.nextdata +#define lzw_nextbits base.nextbits + +/* + * Decoding-specific state. + */ +typedef struct code_ent { + struct code_ent *next; + unsigned short length; /* string len, including this token */ + unsigned char value; /* data value */ + unsigned char firstchar; /* first token of string */ +} code_t; + +typedef int (*decodeFunc)(TIFF*, tidataval_t*, tsize_t); + +typedef struct { + LZWBaseState base; + long dec_nbitsmask; /* lzw_nbits 1 bits, right adjusted */ + long dec_restart; /* restart count */ +#ifdef LZW_CHECKEOS + long dec_bitsleft; /* available bits in raw data */ +#endif + decodeFunc dec_decode; /* regular or backwards compatible */ + code_t* dec_codep; /* current recognized code */ + code_t* dec_oldcodep; /* previously recognized code */ + code_t* dec_free_entp; /* next free entry */ + code_t* dec_maxcodep; /* max available entry */ + code_t* dec_codetab; /* kept separate for small machines */ +} LZWDecodeState; + +/* + * Encoding-specific state. + */ +typedef unsigned short hcode_t; /* codes fit in 16 bits */ +typedef struct { + long hash; + hcode_t code; +} hash_t; + +typedef struct { + LZWBaseState base; + int enc_oldcode; /* last code encountered */ + long enc_checkpoint; /* point at which to clear table */ +#define CHECK_GAP 10000 /* enc_ratio check interval */ + long enc_ratio; /* current compression ratio */ + long enc_incount; /* (input) data bytes encoded */ + long enc_outcount; /* encoded (output) bytes */ + tidataval_t* enc_rawlimit; /* bound on tif_rawdata buffer */ + hash_t* enc_hashtab; /* kept separate for small machines */ +} LZWEncodeState; + +#define LZWState(tif) ((LZWBaseState*) (void*) (tif)->tif_data) +#define DecoderState(tif) ((LZWDecodeState*)(void*) LZWState(tif)) +#define EncoderState(tif) ((LZWEncodeState*)(void*) LZWState(tif)) +/* ^^^ Dat: (void*) -> suppress gcc warning from -Wcast-align */ + +static void cl_hash(LZWEncodeState*); + +#if 0 /**** pts ****/ /* LZW decoder is not needed */ + +static int LZWDecode(TIFF*, tidataval_t*, tsize_t); +#ifdef LZW_COMPAT +static int LZWDecodeCompat(TIFF*, tidataval_t*, tsize_t); +#endif + +/* + * LZW Decoder. + */ + +#ifdef LZW_CHECKEOS +/* + * This check shouldn't be necessary because each + * strip is suppose to be terminated with CODE_EOI. + */ +#define NextCode(_tif, _sp, _bp, _code, _get) { \ + if ((_sp)->dec_bitsleft < nbits) { \ + TIFFWarning(_tif->tif_name, \ + "LZWDecode: Strip %d not terminated with EOI code", \ + /*_tif->tif_curstrip*/ 0); \ + _code = CODE_EOI; \ + } else { \ + _get(_sp,_bp,_code); \ + (_sp)->dec_bitsleft -= nbits; \ + } \ +} +#else +#define NextCode(tif, sp, bp, code, get) get(sp, bp, code) +#endif + +static int +LZWSetupDecode(TIFF* tif) +{ + LZWDecodeState* sp = DecoderState(tif); + static const char module[] = " LZWSetupDecode"; + int code; + + assert(sp != NULL); + if (sp->dec_codetab == NULL) { + sp->dec_codetab = (code_t*)_TIFFmalloc(CSIZE*sizeof (code_t)); + if (sp->dec_codetab == NULL) { + TIFFError(module, "No space for LZW code table"); + return (0); + } + /* + * Pre-load the table. + */ + for (code = 255; code >= 0; code--) { + sp->dec_codetab[code].value = code; + sp->dec_codetab[code].firstchar = code; + sp->dec_codetab[code].length = 1; + sp->dec_codetab[code].next = NULL; + } + } + return (1); +} + +/* + * Setup state for decoding a strip. + */ +static int +LZWPreDecode(TIFF* tif) +{ + LZWDecodeState *sp = DecoderState(tif); + + assert(sp != NULL); + /* + * Check for old bit-reversed codes. + */ + if (tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) { +#ifdef LZW_COMPAT + if (!sp->dec_decode) { + TIFFWarning(tif->tif_name, + "Old-style LZW codes, convert file %d", 0); +#if 0 /**** pts ****/ + /* + * Override default decoding methods with + * ones that deal with the old coding. + * Otherwise the predictor versions set + * above will call the compatibility routines + * through the dec_decode method. + */ + tif->tif_decoderow = LZWDecodeCompat; + tif->tif_decodestrip = LZWDecodeCompat; + tif->tif_decodetile = LZWDecodeCompat; + /* + * If doing horizontal differencing, must + * re-setup the predictor logic since we + * switched the basic decoder methods... + */ + (*tif->tif_setupdecode)(tif); +#endif + LZWSetupDecode(tif); + sp->dec_decode = LZWDecodeCompat; + } + sp->lzw_maxcode = MAXCODE(BITS_MIN); +#else /* !LZW_COMPAT */ + if (!sp->dec_decode) { + TIFFError(tif->tif_name, + "Old-style LZW codes not supported"); + sp->dec_decode = LZWDecode; + } + return (0); +#endif/* !LZW_COMPAT */ + } else { + sp->lzw_maxcode = MAXCODE(BITS_MIN)-1; + sp->dec_decode = LZWDecode; + } + sp->lzw_nbits = BITS_MIN; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + + sp->dec_restart = 0; + sp->dec_nbitsmask = MAXCODE(BITS_MIN); +#ifdef LZW_CHECKEOS + sp->dec_bitsleft = tif->tif_rawcc << 3; +#endif + sp->dec_free_entp = sp->dec_codetab + CODE_FIRST; + /* + * Zero entries that are not yet filled in. We do + * this to guard against bogus input data that causes + * us to index into undefined entries. If you can + * come up with a way to safely bounds-check input codes + * while decoding then you can remove this operation. + */ + _TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof (code_t)); + sp->dec_oldcodep = &sp->dec_codetab[-1]; + sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask-1]; + return (1); +} + +/* + * Decode a "hunk of data". + */ +#define GetNextCode(sp, bp, code) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata = (nextdata<<8) | *(bp)++; \ + nextbits += 8; \ + } \ + code = (hcode_t)((nextdata >> (nextbits-nbits)) & nbitsmask); \ + nextbits -= nbits; \ +} + +static void +codeLoop(TIFF* tif) +{ + TIFFError(tif->tif_name, + "LZWDecode: Bogus encoding, loop in the code table; scanline %d" + /*,tif->tif_row*/); +} + +static int +LZWDecode(TIFF* tif, tidataval_t* op0, tsize_t occ0) +{ + LZWDecodeState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + unsigned char *bp; + hcode_t code; + int len; + long nbits, nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + assert(sp != NULL); + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ && codep); + if (codep) { + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + } + return occ0-occ; + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue, occ -= residue; + tp = op; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = t; + } while (--residue && codep); + sp->dec_restart = 0; + } + + bp = (unsigned char *)tif->tif_rawcp; /* reading from here */ + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0 && bp<tif->tif_rawend /**** pts ****/) { + NextCode(tif, sp, bp, code, GetNextCode); + #if 0 + if (bp>tif->tif_rawend) fprintf(stderr, "over %d\n", tif->tif_rawend-bp); + assert(bp<=tif->tif_rawend); + #endif + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + free_entp = sp->dec_codetab + CODE_FIRST; + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask-1; + +#if 1 /**** pts ****/ + NextCode(tif, sp, bp, code, GetNextCode); + if (code == CODE_EOI) + break; + *op++ = code, occ--; + oldcodep = sp->dec_codetab + code; /* ! */ +#endif + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + assert(&sp->dec_codetab[0] <= free_entp && free_entp < &sp->dec_codetab[CSIZE]); + free_entp->next = oldcodep; + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask-1; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep && codep->length > occ); + if (codep) { + sp->dec_restart = occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ && codep); + if (codep) { + codeLoop(tif); + return -1; + } + } + break; + } + len = codep->length; + tp = op + len; + do { + int t; + --tp; + t = codep->value; + codep = codep->next; + *tp = t; + } while (codep && tp > op); + if (codep) { + codeLoop(tif); + return -1; + /* break; */ + } + op += len, occ -= len; + } else + *op++ = code, occ--; + } + + tif->tif_rawcp = (tidataval_t*) bp; + sp->lzw_nbits = (unsigned short) nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + +#if 0 /**** pts ****/ + if (occ > 0) { + TIFFError(tif->tif_name, + "LZWDecode: Not enough data at scanline %d (short %d bytes)" + /*,tif->tif_row, occ*/); + return (0); + } +#endif + return occ0-occ; +} + +#ifdef LZW_COMPAT +/* + * Decode a "hunk of data" for old images. + */ +#define GetNextCodeCompat(sp, bp, code) { \ + nextdata |= (unsigned long) *(bp)++ << nextbits; \ + nextbits += 8; \ + if (nextbits < nbits) { \ + nextdata |= (unsigned long) *(bp)++ << nextbits; \ + nextbits += 8; \ + } \ + code = (hcode_t)(nextdata & nbitsmask); \ + nextdata >>= nbits; \ + nextbits -= nbits; \ +} + +static int +LZWDecodeCompat(TIFF* tif, tidataval_t* op0, tsize_t occ0) +{ + LZWDecodeState *sp = DecoderState(tif); + char *op = (char*) op0; + long occ = (long) occ0; + char *tp; + unsigned char *bp; + int code, nbits; + long nextbits, nextdata, nbitsmask; + code_t *codep, *free_entp, *maxcodep, *oldcodep; + + assert(0); + assert(sp != NULL); + /* + * Restart interrupted output operation. + */ + if (sp->dec_restart) { + long residue; + + codep = sp->dec_codep; + residue = codep->length - sp->dec_restart; + if (residue > occ) { + /* + * Residue from previous decode is sufficient + * to satisfy decode request. Skip to the + * start of the decoded string, place decoded + * values in the output buffer, and return. + */ + sp->dec_restart += occ; + do { + codep = codep->next; + } while (--residue > occ); + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + return occ0-occ; + } + /* + * Residue satisfies only part of the decode request. + */ + op += residue, occ -= residue; + tp = op; + do { + *--tp = codep->value; + codep = codep->next; + } while (--residue); + sp->dec_restart = 0; + } + + bp = (unsigned char *)tif->tif_rawcp; + nbits = sp->lzw_nbits; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + nbitsmask = sp->dec_nbitsmask; + oldcodep = sp->dec_oldcodep; + free_entp = sp->dec_free_entp; + maxcodep = sp->dec_maxcodep; + + while (occ > 0 && bp<tif->tif_rawend) { + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + if (code == CODE_CLEAR) { + free_entp = sp->dec_codetab + CODE_FIRST; + nbits = BITS_MIN; + nbitsmask = MAXCODE(BITS_MIN); + maxcodep = sp->dec_codetab + nbitsmask; + NextCode(tif, sp, bp, code, GetNextCodeCompat); + if (code == CODE_EOI) + break; + *op++ = code, occ--; + oldcodep = sp->dec_codetab + code; + continue; + } + codep = sp->dec_codetab + code; + + /* + * Add the new entry to the code table. + */ + assert(&sp->dec_codetab[0] <= free_entp && free_entp < &sp->dec_codetab[CSIZE]); + free_entp->next = oldcodep; + free_entp->firstchar = free_entp->next->firstchar; + free_entp->length = free_entp->next->length+1; + free_entp->value = (codep < free_entp) ? + codep->firstchar : free_entp->firstchar; + if (++free_entp > maxcodep) { + if (++nbits > BITS_MAX) /* should not happen */ + nbits = BITS_MAX; + nbitsmask = MAXCODE(nbits); + maxcodep = sp->dec_codetab + nbitsmask; + } + oldcodep = codep; + if (code >= 256) { + /* + * Code maps to a string, copy string + * value to output (written in reverse). + */ + if (codep->length > occ) { + /* + * String is too long for decode buffer, + * locate portion that will fit, copy to + * the decode buffer, and setup restart + * logic for the next decoding call. + */ + sp->dec_codep = codep; + do { + codep = codep->next; + } while (codep->length > occ); + sp->dec_restart = occ; + tp = op + occ; + do { + *--tp = codep->value; + codep = codep->next; + } while (--occ); + break; + } + op += codep->length, occ -= codep->length; + tp = op; + do { + *--tp = codep->value; + } while (0!=(codep = codep->next)); + } else + *op++ = code, occ--; + } + + tif->tif_rawcp = (tidataval_t*) bp; + sp->lzw_nbits = nbits; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->dec_nbitsmask = nbitsmask; + sp->dec_oldcodep = oldcodep; + sp->dec_free_entp = free_entp; + sp->dec_maxcodep = maxcodep; + +#if 0 /**** pts ****/ + if (occ > 0) { + TIFFError(tif->tif_name, + "LZWDecodeCompat: Not enough data at scanline %d (short %d bytes)" + /*,tif->tif_row, occ*/); + return (0); + } +#endif + return occ0-occ; +} +#endif /* LZW_COMPAT */ + +#endif /**** pts ****/ + +/* --- */ + +/* + * LZW Encoding. + */ + +static int +LZWSetupEncode(TIFF* tif) +{ + LZWEncodeState* sp = EncoderState(tif); + static const char module[] = "LZWSetupEncode"; + + assert(sp != NULL); + sp->enc_hashtab = (hash_t*) _TIFFmalloc(HSIZE*sizeof (hash_t)); + if (sp->enc_hashtab == NULL) { + TIFFError(module, "No space for LZW hash table"); + return (0); + } + return (1); +} + +/* + * Reset encoding state at the start of a strip. + */ +static int +LZWPreEncode(TIFF* tif) +{ + LZWEncodeState *sp = EncoderState(tif); + + assert(sp != NULL); + sp->lzw_nbits = BITS_MIN; + sp->lzw_maxcode = MAXCODE(BITS_MIN); + sp->lzw_free_ent = CODE_FIRST; + sp->lzw_nextbits = 0; + sp->lzw_nextdata = 0; + sp->enc_checkpoint = CHECK_GAP; + sp->enc_ratio = 0; + sp->enc_incount = 0; + sp->enc_outcount = 0; + /* + * The 4 here insures there is space for 2 max-sized + * codes in LZWEncode and LZWPostDecode. + */ + sp->enc_rawlimit = tif->tif_rawdata + tif->tif_rawdatasize-1 - 4; + cl_hash(sp); /* clear hash table */ + sp->enc_oldcode = (hcode_t) -1; /* generates CODE_CLEAR in LZWEncode */ + return (1); +} + +#define CALCRATIO(sp, rat) { \ + if (incount > 0x007fffff) { /* NB: shift will overflow */\ + rat = outcount >> 8; \ + rat = (rat == 0 ? 0x7fffffff : incount/rat); \ + } else \ + rat = (incount<<8) / outcount; \ +} +#define PutNextCode(op, c) { \ + nextdata = (nextdata << nbits) | c; \ + nextbits += nbits; \ + *op++ = (unsigned char)(nextdata >> (nextbits-8)); \ + nextbits -= 8; \ + if (nextbits >= 8) { \ + *op++ = (unsigned char)(nextdata >> (nextbits-8)); \ + nextbits -= 8; \ + } \ + outcount += nbits; \ +} + +/* + * Encode a chunk of pixels. + * + * Uses an open addressing double hashing (no chaining) on the + * prefix code/next character combination. We do a variant of + * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's + * relatively-prime secondary probe. Here, the modular division + * first probe is gives way to a faster exclusive-or manipulation. + * Also do block compression with an adaptive reset, whereby the + * code table is cleared when the compression ratio decreases, + * but after the table fills. The variable-length output codes + * are re-sized at this point, and a CODE_CLEAR is generated + * for the decoder. + */ +static int +LZWEncode(TIFF* tif, tidataval_t* bp, tsize_t cc) +{ + register LZWEncodeState *sp = EncoderState(tif); + register long fcode; + register hash_t *hp; + register int h, c; + hcode_t ent; + long disp; + long incount, outcount, checkpoint; + long nextdata, nextbits; + int free_ent, maxcode, nbits; + tidataval_t* op, *limit; + + if (sp == NULL) + return (0); + /* + * Load local state. + */ + incount = sp->enc_incount; + outcount = sp->enc_outcount; + checkpoint = sp->enc_checkpoint; + nextdata = sp->lzw_nextdata; + nextbits = sp->lzw_nextbits; + free_ent = sp->lzw_free_ent; + maxcode = sp->lzw_maxcode; + nbits = sp->lzw_nbits; + op = tif->tif_rawcp; + limit = sp->enc_rawlimit; + ent = sp->enc_oldcode; + + if (ent == (hcode_t) -1 && cc > 0) { + /* + * NB: This is safe because it can only happen + * at the start of a strip where we know there + * is space in the data buffer. + */ + PutNextCode(op, CODE_CLEAR); + ent = *bp++; cc--; incount++; + } + while (cc > 0) { + c = *bp++; cc--; incount++; + fcode = ((long)c << BITS_MAX) + ent; + h = (c << HSHIFT) ^ ent; /* xor hashing */ +#ifdef _WINDOWS /* ?? */ + /* + * Check hash index for an overflow. + */ + if (h >= HSIZE) + h -= HSIZE; +#endif + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + continue; + } + if (hp->hash >= 0) { + /* + * Primary hash failed, check secondary hash. + */ + disp = HSIZE - h; + if (h == 0) + disp = 1; + do { + /* + * Avoid pointer arithmetic 'cuz of + * wraparound problems with segments. + */ + if ((h -= disp) < 0) + h += HSIZE; + hp = &sp->enc_hashtab[h]; + if (hp->hash == fcode) { + ent = hp->code; + goto hit; + } + } while (hp->hash >= 0); + } + /* + * New entry, emit code and add to table. + */ + /* + * Verify there is space in the buffer for the code + * and any potential Clear code that might be emitted + * below. The value of limit is setup so that there + * are at least 4 bytes free--room for 2 codes. + */ + if (op > limit) { + tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); + TIFFFlushData1(tif); + op = tif->tif_rawdata; + } + PutNextCode(op, ent); + ent = c; + hp->code = free_ent++; + hp->hash = fcode; + if (free_ent == CODE_MAX-1) { + /* table is full, emit clear code and reset */ + cl_hash(sp); + sp->enc_ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else { + /* + * If the next entry is going to be too big for + * the code size, then increase it, if possible. + */ + if (free_ent > maxcode) { + nbits++; + assert(nbits <= BITS_MAX); + maxcode = (int) MAXCODE(nbits); + } else if (incount >= checkpoint) { + long rat; + /* + * Check compression ratio and, if things seem + * to be slipping, clear the hash table and + * reset state. The compression ratio is a + * 24+8-bit fractional number. + */ + checkpoint = incount+CHECK_GAP; + CALCRATIO(sp, rat); + if (rat <= sp->enc_ratio) { + cl_hash(sp); + sp->enc_ratio = 0; + incount = 0; + outcount = 0; + free_ent = CODE_FIRST; + PutNextCode(op, CODE_CLEAR); + nbits = BITS_MIN; + maxcode = MAXCODE(BITS_MIN); + } else + sp->enc_ratio = rat; + } + } + hit: + ; + } + + /* + * Restore global state. + */ + sp->enc_incount = incount; + sp->enc_outcount = outcount; + sp->enc_checkpoint = checkpoint; + sp->enc_oldcode = ent; + sp->lzw_nextdata = nextdata; + sp->lzw_nextbits = nextbits; + sp->lzw_free_ent = free_ent; + sp->lzw_maxcode = maxcode; + sp->lzw_nbits = nbits; + tif->tif_rawcp = op; + return (1); +} + +/* + * Finish off an encoded strip by flushing the last + * string and tacking on an End Of Information code. + */ +static int +LZWPostEncode(TIFF* tif) +{ + register LZWEncodeState *sp = EncoderState(tif); + tidataval_t* op = tif->tif_rawcp; + long nextbits = sp->lzw_nextbits; + long nextdata = sp->lzw_nextdata; + long outcount = sp->enc_outcount; + int nbits = sp->lzw_nbits; + + if (op > sp->enc_rawlimit) { + /* fprintf(stderr, "Yupp!\n"); */ + tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); + TIFFFlushData1(tif); + op = tif->tif_rawdata; + } + if (sp->enc_oldcode != (hcode_t) -1) { + /* fprintf(stderr, "EIK\n"); */ + PutNextCode(op, sp->enc_oldcode); + sp->enc_oldcode = (hcode_t) -1; + } + PutNextCode(op, CODE_EOI); + if (nextbits > 0) + *op++ = (unsigned char)(nextdata << (8-nextbits)); + tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata); + return (1); +} + +/* + * Reset encoding hash table. + */ +static void +cl_hash(LZWEncodeState* sp) +{ + register hash_t *hp = &sp->enc_hashtab[HSIZE-1]; + register long i = HSIZE-8; + + do { + i -= 8; + hp[-7].hash = -1; + hp[-6].hash = -1; + hp[-5].hash = -1; + hp[-4].hash = -1; + hp[-3].hash = -1; + hp[-2].hash = -1; + hp[-1].hash = -1; + hp[ 0].hash = -1; + hp -= 8; + } while (i >= 0); + for (i += 8; i > 0; i--, hp--) + hp->hash = -1; +} + +static void +LZWCleanup(TIFF* tif) +{ + if (tif->tif_data) { + if (tif->tif_reading_p) { + if (DecoderState(tif)->dec_codetab) + _TIFFfree(DecoderState(tif)->dec_codetab); + } else { + if (EncoderState(tif)->enc_hashtab) + _TIFFfree(EncoderState(tif)->enc_hashtab); + } + _TIFFfree(tif->tif_data); + tif->tif_data = NULL; + } + _TIFFfree(tif->tif_rawdata); +} + +static int +TIFFInitLZW(TIFF* tif) +{ + /* assert(scheme == COMPRESSION_LZW); */ + /* + * Allocate state block so tag methods have storage to record values. + */ + if (tif->tif_reading_p) { + tif->tif_data = (tidataval_t*) _TIFFmalloc(sizeof (LZWDecodeState)); + if (tif->tif_data == NULL) + goto bad; + DecoderState(tif)->dec_codetab = NULL; + DecoderState(tif)->dec_decode = NULL; + } else { + tif->tif_data = (tidataval_t*) _TIFFmalloc(sizeof (LZWEncodeState)); + if (tif->tif_data == NULL) + goto bad; + EncoderState(tif)->enc_hashtab = NULL; + } +#if 0 /**** pts ****/ + /* + * Install codec methods. + */ + tif->tif_setupdecode = LZWSetupDecode; + tif->tif_predecode = LZWPreDecode; + tif->tif_decoderow = LZWDecode; + tif->tif_decodestrip = LZWDecode; + tif->tif_decodetile = LZWDecode; + tif->tif_setupencode = LZWSetupEncode; + tif->tif_preencode = LZWPreEncode; + tif->tif_postencode = LZWPostEncode; + tif->tif_encoderow = LZWEncode; + tif->tif_encodestrip = LZWEncode; + tif->tif_encodetile = LZWEncode; + tif->tif_cleanup = LZWCleanup; +#endif +#if 0 /**** pts ****/ + /* + * Setup predictor setup. + */ + (void) TIFFPredictorInit(tif); +#endif + return (1); +bad: + TIFFError("TIFFInitLZW", "No space for LZW state block"); + return (0); +} + +/* + * Copyright (c) 1985, 1986 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * James A. Woods, derived from original work by Spencer Thomas + * and Joseph Orost. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +#endif /* LZW_SUPPORT */ + +#if 0 +#ifdef __cplusplus +extern "C" +#else +extern +#endif +FILE *fdopen (int fildes, const char *mode); /* POSIX, but not ANSI */ +#else +#undef _POSIX_SOURCE +#define _POSIX_SOURCE 1 +#undef _POSIX_C_SOURCE /* Sat Jun 1 14:25:53 CEST 2002 */ +#define _POSIX_C_SOURCE 2 +#include <stdio.h> +#endif + +#if 0 /**** pts: never needed, because output FillOrder is always 1 */ +void +TIFFReverseBits(register unsigned char* cp, register unsigned long n) +{ + char *TIFFBitRevTable=...; /**** pts ****/ + for (; n > 8; n -= 8) { + cp[0] = TIFFBitRevTable[cp[0]]; + cp[1] = TIFFBitRevTable[cp[1]]; + cp[2] = TIFFBitRevTable[cp[2]]; + cp[3] = TIFFBitRevTable[cp[3]]; + cp[4] = TIFFBitRevTable[cp[4]]; + cp[5] = TIFFBitRevTable[cp[5]]; + cp[6] = TIFFBitRevTable[cp[6]]; + cp[7] = TIFFBitRevTable[cp[7]]; + cp += 8; + } + while (n-- > 0) + *cp = TIFFBitRevTable[*cp], cp++; +} +#endif + +static void TIFFError(char const*a, char const*b) { + fprintf(stderr, "%s: %s\n", a, b); +} +static int TIFFAppendTo(TIFF*tif, tidataval_t* data, tsize_t cc) { + (void)tif; + (void)data; + (void)cc; + /* fwrite(data, 1, cc, (FILE*)tif->tif_sout); + if (ferror((FILE*)tif->tif_sout)) return 0; */ + if (-1==tif->tif_writer((char*)data, cc, tif->tif_sout)) return 0; +#if 0 /**** pts ****/ /* tif_write.h */ + (void)strip; + TIFFDirectory *td = &tif->tif_dir; + static const char module[] = "TIFFAppendToStrip"; + + if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) { + /* + * No current offset, set the current strip. + */ + if (td->td_stripoffset[strip] != 0) { + if (!SeekOK(tif, td->td_stripoffset[strip])) { + TIFFError(module, + "%s: Seek error at scanline %lu", + tif->tif_name, (unsigned long) tif->tif_row); + return (0); + } + } else + td->td_stripoffset[strip] = + TIFFSeekFile(tif, (toff_t) 0, SEEK_END); + tif->tif_curoff = td->td_stripoffset[strip]; + } + if (!WriteOK(tif, data, cc)) { + TIFFError(module, "%s: Write error at scanline %lu", + tif->tif_name, (unsigned long) tif->tif_row); + return (0); + } + tif->tif_curoff += cc; + td->td_stripbytecount[strip] += cc; +#endif + return (1); +} + +#if 0 +static tidataval_t readbuf[4096]; +unsigned int readlen; +static char *inname; +typedef int (*filter_t)(FILE *sin, FILE*sout); +/** /LZWEncode filter, STDIN -> STDOUT */ +static int lzw_encode(FILE *sin, FILE *sout) { + TIFF tif; + tif.tif_sout=sout; + tif.tif_reading_p=0; +#if 0 + tif.tif_revbits_p=0; +#endif + tif.tif_name=inname; + tif.tif_rawdata=(tidataval_t*)_TIFFmalloc(tif.tif_rawdatasize=4096); /* Imp: check */ + tif.tif_rawcp=tif.tif_rawdata; + tif.tif_rawcc=0; + if (TIFFInitLZW(&tif) && + LZWSetupEncode(&tif) && + LZWPreEncode(&tif) /* for each strip */) { + while ((readlen=fread(readbuf, 1, sizeof(readbuf), sin))!=0) { + if (!LZWEncode(&tif, readbuf, readlen)) goto err; + /* fprintf(stderr, "readlen=%d\n", readlen); */ + } + if (!LZWPostEncode(&tif)) goto err; /* for each strip */ + LZWCleanup(&tif); + if (!TIFFFlushData1(&tif)) { _TIFFfree(tif.tif_rawdata); fflush(sout); return 0; } + fflush(sout); + } else { err: + fflush(sout); + LZWCleanup(&tif); + _TIFFfree(tif.tif_rawdata); + return 0; + } + return 1; +} +/** /LZWEncode filter, STDIN -> STDOUT */ +static int lzw_decode(FILE *sin, FILE *sout) { + TIFF tif; + /* tidataval_t *rawend0; */ + /* char *xbuf; */ + int got; + unsigned int left; + tif.tif_reading_p=1; +#if 0 + tif.tif_revbits_p=0; +#endif + tif.tif_name=inname; + tif.tif_rawdata=(tidataval_t*)_TIFFmalloc(tif.tif_rawdatasize=4096); /* Imp: check */ + tif.tif_rawcc=0; + left=0; + if (TIFFInitLZW(&tif) && + LZWSetupDecode(&tif) && + LZWPreDecode(&tif) /* for each strip */) { + /* vvv Dat: fread returns >=0 ! */ + while ((readlen=left+fread(tif.tif_rawdata+left, 1, tif.tif_rawdatasize-left, sin))!=0) { + #if DEBUGMSG + fprintf(stderr, "readlen+=%d\n", readlen); + #endif + while (readlen<=3) { + if ((got=fread(tif.tif_rawdata+readlen, 1, tif.tif_rawdatasize-readlen, sin))==0) { + tif.tif_rawend=tif.tif_rawdata+readlen; + goto star; + } + readlen+=got; + } + tif.tif_rawend=tif.tif_rawdata+readlen-3; + star: + tif.tif_rawcp=tif.tif_rawdata; + #if DEBUGMSG + fprintf(stderr, "readlen:=%d\n", readlen); + #endif + while (1) { + if (-1==(got=(DecoderState(&tif)->dec_decode)(&tif, readbuf, sizeof(readbuf)))) goto err; + #if DEBUGMSG + fprintf(stderr, "OK, written: %d %d\n", got, tif.tif_rawend-tif.tif_rawcp); + #endif + if (0==got) break; + fwrite(readbuf, 1, got, sout); + } + left=tif.tif_rawdata+readlen-tif.tif_rawcp; + got=left; + #if DEBUGMSG + fprintf(stderr, "left=%d\n", left); fflush(stderr); + #endif + while (got--!=0) { tif.tif_rawdata[got]=tif.tif_rawcp[got]; } + } +#if 0 + if (!LZWPostDecode(&tif)) { LZWCleanup(&tif); return 0; } /* for each strip */ +#endif + LZWCleanup(&tif); + fflush(sout); + } else { err: + fflush(sout); + LZWCleanup(&tif); + _TIFFfree(tif.tif_rawdata); + return 0; + } + return 1; +} +#endif + +static int feeder(char *readbuf, unsigned readlen, TIFF *tif) { + /*(void)LZWPreDecode;*/ /* Imp: better avoid gcc warning... */ + if (readlen!=0) { + if (!LZWEncode(tif, (tidataval_t*)readbuf, readlen)) { e1: + LZWCleanup(tif); e2: + _TIFFfree(tif->tif_rawdata); + return 0; + } + } else { + if (!LZWPostEncode(tif)) goto e1; + if (!TIFFFlushData1(tif)) goto e2; + LZWCleanup(tif); + } + return 1; +} + +/** /LZWEncode filter, STDIN -> STDOUT */ +int pts_lzw_init(TIFF *tif) { + /* tif_sout and tif_writer are already filled */ + tif->tif_feeder=feeder; + tif->tif_reading_p=0; +#if 0 + tif->tif_revbits_p=0; +#endif + tif->tif_name="//.filter";/*inname;*/ + tif->tif_rawdata=(tidataval_t*)_TIFFmalloc(tif->tif_rawdatasize=4096); /* Imp: check */ + tif->tif_rawcp=tif->tif_rawdata; + tif->tif_rawcc=0; + if (TIFFInitLZW(tif) && + LZWSetupEncode(tif) && + LZWPreEncode(tif) /* for each strip */) { + return 1; + } + LZWCleanup(tif); + _TIFFfree(tif->tif_rawdata); + return 0; +} + + +#if 0 +/**** pts ****/ +int main(int argc, char **argv) { + filter_t filter; + FILE *sin, *sout; + inname="STDIN"; + + if (argc>=2 && argc<=4 && argv[1][0]=='e') { + filter=lzw_encode; + } else if (argc>=2 && argc<=4 && argv[1][0]=='d') { + filter=lzw_decode; + } else { + fprintf(stderr, + "This is PotterSoftware LZW codec v0.1, (C) pts@fazekas.hu in Late Dec 2001\n" + "THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY! USE AT YOUR OWN RISK!\n" + "This program is free software, covered by the GNU GPL.\n" + " Derived from code Copyright (c) 1988-1997 Sam Leffler\n" + " Derived from code Copyright (c) 1991-1997 Silicon Graphics, Inc.\n\n" + "Usage: %s encode|decode [INFILE] [OUTFILE]\n\n" + "Unspecified file names mean STDIN or STDOUT.\n" + "Encoding is /LZWEncode compression, decoding is /LZWDecode uncompression.\n\n" + "Note that the LZW compression (but not uncompression) is patented by\n" + "Unisys (patent number #4,558,302), so use this program at your own legal\n" + "risk!\n" + ,argv[0]); + return 2; + } + if (argc>=3) sin= fopen(inname=argv[2],"rb"); + else sin= fdopen(0, "rb"); + if (sin==0) { + fprintf(stderr, "%s: error opening infile\n", argv[0]); + return 3; + } + if (argc>=4) sout=fopen(inname=argv[3],"wb"); + else sout=fdopen(1, "wb"); + if (sout==0) { + fprintf(stderr, "%s: error opening outfile\n", argv[0]); + return 4; + } + return !filter(sin, sout); + /* fclose(sout); fclose(sin); */ +} +#endif |