LCOV - code coverage report
Current view: top level - frmts/gtiff/libtiff - tif_packbits.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 120 155 77.4 %
Date: 2026-02-21 16:21:44 Functions: 8 8 100.0 %

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

Generated by: LCOV version 1.14