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