1/* PDFlib GmbH cvsid: $Id: tif_packbits.c 14574 2005-10-29 16:27:43Z bonefish $ */ 2 3/* 4 * Copyright (c) 1988-1997 Sam Leffler 5 * Copyright (c) 1991-1997 Silicon Graphics, Inc. 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and 8 * its documentation for any purpose is hereby granted without fee, provided 9 * that (i) the above copyright notices and this permission notice appear in 10 * all copies of the software and related documentation, and (ii) the names of 11 * Sam Leffler and Silicon Graphics may not be used in any advertising or 12 * publicity relating to the software without the specific, prior written 13 * permission of Sam Leffler and Silicon Graphics. 14 * 15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 18 * 19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR 20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, 21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 24 * OF THIS SOFTWARE. 25 */ 26 27#include "tiffiop.h" 28#ifdef PACKBITS_SUPPORT 29/* 30 * TIFF Library. 31 * 32 * PackBits Compression Algorithm Support 33 */ 34#include <assert.h> 35#include <stdio.h> 36 37#ifdef PDFLIB_TIFFWRITE_SUPPORT 38static int 39PackBitsPreEncode(TIFF* tif, tsample_t s) 40{ 41 (void) s; 42 /* 43 * Calculate the scanline/tile-width size in bytes. 44 */ 45 if (isTiled(tif)) 46 tif->tif_data = (tidata_t) TIFFTileRowSize(tif); 47 else 48 tif->tif_data = (tidata_t) TIFFScanlineSize(tif); 49 return (1); 50} 51#endif /* PDFLIB_TIFFWRITE_SUPPORT */ 52 53/* 54 * NB: tidata is the type representing *(tidata_t); 55 * if tidata_t is made signed then this type must 56 * be adjusted accordingly. 57 */ 58typedef unsigned char tidata; 59 60/* 61 * Encode a run of pixels. 62 */ 63#ifdef PDFLIB_TIFFWRITE_SUPPORT 64static int 65PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s) 66{ 67 tif_char* bp = (tif_char*) buf; 68 tidata_t op, ep, lastliteral; 69 long n, slop; 70 int b; 71 enum { BASE, LITERAL, RUN, LITERAL_RUN } state; 72 73 (void) s; 74 op = tif->tif_rawcp; 75 ep = tif->tif_rawdata + tif->tif_rawdatasize; 76 state = BASE; 77 lastliteral = 0; 78 while (cc > 0) { 79 /* 80 * Find the longest string of identical bytes. 81 */ 82 b = *bp++, cc--, n = 1; 83 for (; cc > 0 && b == *bp; cc--, bp++) 84 n++; 85 again: 86 if (op + 2 >= ep) { /* insure space for new data */ 87 /* 88 * Be careful about writing the last 89 * literal. Must write up to that point 90 * and then copy the remainder to the 91 * front of the buffer. 92 */ 93 if (state == LITERAL || state == LITERAL_RUN) { 94 slop = op - lastliteral; 95 tif->tif_rawcc += lastliteral - tif->tif_rawcp; 96 if (!TIFFFlushData1(tif)) 97 return (-1); 98 op = tif->tif_rawcp; 99 while (slop-- > 0) 100 *op++ = *lastliteral++; 101 lastliteral = tif->tif_rawcp; 102 } else { 103 tif->tif_rawcc += op - tif->tif_rawcp; 104 if (!TIFFFlushData1(tif)) 105 return (-1); 106 op = tif->tif_rawcp; 107 } 108 } 109 switch (state) { 110 case BASE: /* initial state, set run/literal */ 111 if (n > 1) { 112 state = RUN; 113 if (n > 128) { 114 *op++ = (tidata) -127; 115 *op++ = b; 116 n -= 128; 117 goto again; 118 } 119 *op++ = (tidataval_t)(-(n-1)); 120 *op++ = b; 121 } else { 122 lastliteral = op; 123 *op++ = 0; 124 *op++ = b; 125 state = LITERAL; 126 } 127 break; 128 case LITERAL: /* last object was literal string */ 129 if (n > 1) { 130 state = LITERAL_RUN; 131 if (n > 128) { 132 *op++ = (tidata) -127; 133 *op++ = b; 134 n -= 128; 135 goto again; 136 } 137 *op++ = (tidataval_t)(-(n-1)); /* encode run */ 138 *op++ = b; 139 } else { /* extend literal */ 140 if (++(*lastliteral) == 127) 141 state = BASE; 142 *op++ = b; 143 } 144 break; 145 case RUN: /* last object was run */ 146 if (n > 1) { 147 if (n > 128) { 148 *op++ = (tidata) -127; 149 *op++ = b; 150 n -= 128; 151 goto again; 152 } 153 *op++ = (tidataval_t)(-(n-1)); 154 *op++ = b; 155 } else { 156 lastliteral = op; 157 *op++ = 0; 158 *op++ = b; 159 state = LITERAL; 160 } 161 break; 162 case LITERAL_RUN: /* literal followed by a run */ 163 /* 164 * Check to see if previous run should 165 * be converted to a literal, in which 166 * case we convert literal-run-literal 167 * to a single literal. 168 */ 169 if (n == 1 && op[-2] == (tidata) -1 && 170 *lastliteral < 126) { 171 state = (((*lastliteral) += 2) == 127 ? 172 BASE : LITERAL); 173 op[-2] = op[-1]; /* replicate */ 174 } else 175 state = RUN; 176 goto again; 177 } 178 } 179 tif->tif_rawcc += op - tif->tif_rawcp; 180 tif->tif_rawcp = op; 181 return (1); 182} 183#endif /* PDFLIB_TIFFWRITE_SUPPORT */ 184 185/* 186 * Encode a rectangular chunk of pixels. We break it up 187 * into row-sized pieces to insure that encoded runs do 188 * not span rows. Otherwise, there can be problems with 189 * the decoder if data is read, for example, by scanlines 190 * when it was encoded by strips. 191 */ 192#ifdef PDFLIB_TIFFWRITE_SUPPORT 193static int 194PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s) 195{ 196 tsize_t rowsize = (tsize_t) tif->tif_data; 197 198 assert(rowsize > 0); 199 200#ifdef YCBCR_SUPPORT 201 /* 202 * YCBCR data isn't really separable into rows, so we 203 * might as well encode the whole tile/strip as one chunk. 204 */ 205 if( tif->tif_dir.td_photometric == PHOTOMETRIC_YCBCR ) 206 rowsize = (tsize_t) tif->tif_data; 207#endif 208 209 while ((long)cc > 0) { 210 int chunk = rowsize; 211 212 if( cc < chunk ) 213 chunk = cc; 214 215 if (PackBitsEncode(tif, bp, chunk, s) < 0) 216 return (-1); 217 bp += chunk; 218 cc -= chunk; 219 } 220 return (1); 221} 222#endif /* PDFLIB_TIFFWRITE_SUPPORT */ 223 224static int 225PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s) 226{ 227 char *bp; 228 tsize_t cc; 229 long n; 230 int b; 231 232 (void) s; 233 bp = (char*) tif->tif_rawcp; 234 cc = tif->tif_rawcc; 235 while (cc > 0 && (long)occ > 0) { 236 n = (long) *bp++, cc--; 237 /* 238 * Watch out for compilers that 239 * don't sign extend chars... 240 */ 241 if (n >= 128) 242 n -= 256; 243 if (n < 0) { /* replicate next byte -n+1 times */ 244 if (n == -128) /* nop */ 245 continue; 246 n = -n + 1; 247 if( occ < n ) 248 { 249 TIFFWarning(tif->tif_name, 250 "PackBitsDecode: discarding %d bytes " 251 "to avoid buffer overrun", 252 n - occ); 253 n = occ; 254 } 255 occ -= n; 256 b = *bp++, cc--; 257 while (n-- > 0) 258 *op++ = b; 259 } else { /* copy next n+1 bytes literally */ 260 if (occ < n + 1) 261 { 262 TIFFWarning(tif->tif_name, 263 "PackBitsDecode: discarding %d bytes " 264 "to avoid buffer overrun", 265 n - occ + 1); 266 n = occ - 1; 267 } 268 _TIFFmemcpy(op, bp, ++n); 269 op += n; occ -= n; 270 bp += n; cc -= n; 271 } 272 } 273 tif->tif_rawcp = (tidata_t) bp; 274 tif->tif_rawcc = cc; 275 if (occ > 0) { 276 TIFFError(tif->tif_name, 277 "PackBitsDecode: Not enough data for scanline %ld", 278 (long) tif->tif_row); 279 return (0); 280 } 281 return (1); 282} 283 284int 285TIFFInitPackBits(TIFF* tif, int scheme) 286{ 287 (void) scheme; 288 tif->tif_decoderow = PackBitsDecode; 289 tif->tif_decodestrip = PackBitsDecode; 290 tif->tif_decodetile = PackBitsDecode; 291#ifdef PDFLIB_TIFFWRITE_SUPPORT 292 tif->tif_preencode = PackBitsPreEncode; 293 tif->tif_encoderow = PackBitsEncode; 294 tif->tif_encodestrip = PackBitsEncodeChunk; 295 tif->tif_encodetile = PackBitsEncodeChunk; 296#endif /* PDFLIB_TIFFWRITE_SUPPORT */ 297 return (1); 298} 299#endif /* PACKBITS_SUPPORT */ 300