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