Home | History | Annotate | Download | only in libtiff
      1 /* $Id: tif_packbits.c,v 1.20 2010-03-10 18:56:49 bfriesen Exp $ */
      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 <stdio.h>
     35 
     36 static int
     37 PackBitsPreEncode(TIFF* tif, uint16 s)
     38 {
     39     (void) s;
     40 
     41     if (!(tif->tif_data = (uint8*)_TIFFmalloc(sizeof(tmsize_t))))
     42         return (0);
     43     /*
     44      * Calculate the scanline/tile-width size in bytes.
     45      */
     46     if (isTiled(tif))
     47         *(tmsize_t*)tif->tif_data = TIFFTileRowSize(tif);
     48     else
     49         *(tmsize_t*)tif->tif_data = TIFFScanlineSize(tif);
     50     return (1);
     51 }
     52 
     53 static int
     54 PackBitsPostEncode(TIFF* tif)
     55 {
     56         if (tif->tif_data)
     57             _TIFFfree(tif->tif_data);
     58     return (1);
     59 }
     60 
     61 /*
     62  * Encode a run of pixels.
     63  */
     64 static int
     65 PackBitsEncode(TIFF* tif, uint8* buf, tmsize_t cc, uint16 s)
     66 {
     67     unsigned char* bp = (unsigned char*) buf;
     68     uint8* op;
     69     uint8* ep;
     70     uint8* lastliteral;
     71     long n, slop;
     72     int b;
     73     enum { BASE, LITERAL, RUN, LITERAL_RUN } state;
     74 
     75     (void) s;
     76     op = tif->tif_rawcp;
     77     ep = tif->tif_rawdata + tif->tif_rawdatasize;
     78     state = BASE;
     79     lastliteral = 0;
     80     while (cc > 0) {
     81         /*
     82          * Find the longest string of identical bytes.
     83          */
     84         b = *bp++, cc--, n = 1;
     85         for (; cc > 0 && b == *bp; cc--, bp++)
     86             n++;
     87     again:
     88         if (op + 2 >= ep) {		/* insure space for new data */
     89             /*
     90              * Be careful about writing the last
     91              * literal.  Must write up to that point
     92              * and then copy the remainder to the
     93              * front of the buffer.
     94              */
     95             if (state == LITERAL || state == LITERAL_RUN) {
     96                 slop = (long)(op - lastliteral);
     97                 tif->tif_rawcc += (tmsize_t)(lastliteral - tif->tif_rawcp);
     98                 if (!TIFFFlushData1(tif))
     99                     return (-1);
    100                 op = tif->tif_rawcp;
    101                 while (slop-- > 0)
    102                     *op++ = *lastliteral++;
    103                 lastliteral = tif->tif_rawcp;
    104             } else {
    105                 tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
    106                 if (!TIFFFlushData1(tif))
    107                     return (-1);
    108                 op = tif->tif_rawcp;
    109             }
    110         }
    111         switch (state) {
    112         case BASE:		/* initial state, set run/literal */
    113             if (n > 1) {
    114                 state = RUN;
    115                 if (n > 128) {
    116                     *op++ = (uint8) -127;
    117                     *op++ = (uint8) b;
    118                     n -= 128;
    119                     goto again;
    120                 }
    121                 *op++ = (uint8)(-(n-1));
    122                 *op++ = (uint8) b;
    123             } else {
    124                 lastliteral = op;
    125                 *op++ = 0;
    126                 *op++ = (uint8) b;
    127                 state = LITERAL;
    128             }
    129             break;
    130         case LITERAL:		/* last object was literal string */
    131             if (n > 1) {
    132                 state = LITERAL_RUN;
    133                 if (n > 128) {
    134                     *op++ = (uint8) -127;
    135                     *op++ = (uint8) b;
    136                     n -= 128;
    137                     goto again;
    138                 }
    139                 *op++ = (uint8)(-(n-1));	/* encode run */
    140                 *op++ = (uint8) b;
    141             } else {			/* extend literal */
    142                 if (++(*lastliteral) == 127)
    143                     state = BASE;
    144                 *op++ = (uint8) b;
    145             }
    146             break;
    147         case RUN:		/* last object was run */
    148             if (n > 1) {
    149                 if (n > 128) {
    150                     *op++ = (uint8) -127;
    151                     *op++ = (uint8) b;
    152                     n -= 128;
    153                     goto again;
    154                 }
    155                 *op++ = (uint8)(-(n-1));
    156                 *op++ = (uint8) b;
    157             } else {
    158                 lastliteral = op;
    159                 *op++ = 0;
    160                 *op++ = (uint8) b;
    161                 state = LITERAL;
    162             }
    163             break;
    164         case LITERAL_RUN:	/* literal followed by a run */
    165             /*
    166              * Check to see if previous run should
    167              * be converted to a literal, in which
    168              * case we convert literal-run-literal
    169              * to a single literal.
    170              */
    171             if (n == 1 && op[-2] == (uint8) -1 &&
    172                 *lastliteral < 126) {
    173                 state = (((*lastliteral) += 2) == 127 ?
    174                     BASE : LITERAL);
    175                 op[-2] = op[-1];	/* replicate */
    176             } else
    177                 state = RUN;
    178             goto again;
    179         }
    180     }
    181     tif->tif_rawcc += (tmsize_t)(op - tif->tif_rawcp);
    182     tif->tif_rawcp = op;
    183     return (1);
    184 }
    185 
    186 /*
    187  * Encode a rectangular chunk of pixels.  We break it up
    188  * into row-sized pieces to insure that encoded runs do
    189  * not span rows.  Otherwise, there can be problems with
    190  * the decoder if data is read, for example, by scanlines
    191  * when it was encoded by strips.
    192  */
    193 static int
    194 PackBitsEncodeChunk(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
    195 {
    196     tmsize_t rowsize = *(tmsize_t*)tif->tif_data;
    197 
    198     while (cc > 0) {
    199         tmsize_t chunk = rowsize;
    200 
    201         if( cc < chunk )
    202             chunk = cc;
    203 
    204         if (PackBitsEncode(tif, bp, chunk, s) < 0)
    205             return (-1);
    206         bp += chunk;
    207         cc -= chunk;
    208     }
    209     return (1);
    210 }
    211 
    212 static int
    213 PackBitsDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
    214 {
    215     static const char module[] = "PackBitsDecode";
    216     char *bp;
    217     tmsize_t cc;
    218     long n;
    219     int b;
    220 
    221     (void) s;
    222     bp = (char*) tif->tif_rawcp;
    223     cc = tif->tif_rawcc;
    224     while (cc > 0 && occ > 0) {
    225         n = (long) *bp++, cc--;
    226         /*
    227          * Watch out for compilers that
    228          * don't sign extend chars...
    229          */
    230         if (n >= 128)
    231             n -= 256;
    232         if (n < 0) {		/* replicate next byte -n+1 times */
    233             if (n == -128)	/* nop */
    234                 continue;
    235             n = -n + 1;
    236             if( occ < (tmsize_t)n )
    237             {
    238                 TIFFWarningExt(tif->tif_clientdata, module,
    239                     "Discarding %lu bytes to avoid buffer overrun",
    240                     (unsigned long) ((tmsize_t)n - occ));
    241                 n = (long)occ;
    242             }
    243             occ -= n;
    244             b = *bp++, cc--;      /* TODO: may be reading past input buffer here when input data is corrupt or ends prematurely */
    245             while (n-- > 0)
    246                 *op++ = (uint8) b;
    247         } else {		/* copy next n+1 bytes literally */
    248             if (occ < (tmsize_t)(n + 1))
    249             {
    250                 TIFFWarningExt(tif->tif_clientdata, module,
    251                     "Discarding %lu bytes to avoid buffer overrun",
    252                     (unsigned long) ((tmsize_t)n - occ + 1));
    253                 n = (long)occ - 1;
    254             }
    255             _TIFFmemcpy(op, bp, ++n);  /* TODO: may be reading past input buffer here when input data is corrupt or ends prematurely */
    256             op += n; occ -= n;
    257             bp += n; cc -= n;
    258         }
    259     }
    260     tif->tif_rawcp = (uint8*) bp;
    261     tif->tif_rawcc = cc;
    262     if (occ > 0) {
    263         TIFFErrorExt(tif->tif_clientdata, module,
    264             "Not enough data for scanline %lu",
    265             (unsigned long) tif->tif_row);
    266         return (0);
    267     }
    268     return (1);
    269 }
    270 
    271 int
    272 TIFFInitPackBits(TIFF* tif, int scheme)
    273 {
    274     (void) scheme;
    275     tif->tif_decoderow = PackBitsDecode;
    276     tif->tif_decodestrip = PackBitsDecode;
    277     tif->tif_decodetile = PackBitsDecode;
    278     tif->tif_preencode = PackBitsPreEncode;
    279     tif->tif_postencode = PackBitsPostEncode;
    280     tif->tif_encoderow = PackBitsEncode;
    281     tif->tif_encodestrip = PackBitsEncodeChunk;
    282     tif->tif_encodetile = PackBitsEncodeChunk;
    283     return (1);
    284 }
    285 #endif /* PACKBITS_SUPPORT */
    286 
    287 /* vim: set ts=8 sts=8 sw=8 noet: */
    288 /*
    289  * Local Variables:
    290  * mode: c
    291  * c-basic-offset: 8
    292  * fill-column: 78
    293  * End:
    294  */
    295