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