1 /*
2 * Copyright 2003-2008 by Paulo Soares.
3 *
4 * This code was originally released in 2001 by SUN (see class
5 * com.sun.media.imageioimpl.plugins.tiff.TIFFLZWDecompressor.java)
6 * using the BSD license in a specific wording. In a mail dating from
7 * January 23, 2008, Brian Burkhalter (@sun.com) gave us permission
8 * to use the code under the following version of the BSD license:
9 *
10 * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * - Redistribution of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * - Redistribution in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in
21 * the documentation and/or other materials provided with the
22 * distribution.
23 *
24 * Neither the name of Sun Microsystems, Inc. or the names of
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * This software is provided "AS IS," without a warranty of any
29 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
30 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
31 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
32 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
33 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
34 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
35 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
36 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
37 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
38 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
39 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGES.
41 *
42 * You acknowledge that this software is not designed or intended for
43 * use in the design, construction, operation or maintenance of any
44 * nuclear facility.
45 */
46 package com.lowagie.text.pdf.codec;
47
48 /**
49 * A class for performing LZW decoding.
50 *
51 *
52 */
53 public class TIFFLZWDecoder {
54
55 byte stringTable[][];
56 byte data[] = null, uncompData[];
57 int tableIndex, bitsToGet = 9;
58 int bytePointer, bitPointer;
59 int dstIndex;
60 int w, h;
61 int predictor, samplesPerPixel;
62 int nextData = 0;
63 int nextBits = 0;
64
65 int andTable[] = {
66 511,
67 1023,
68 2047,
69 4095
70 };
71
72 public TIFFLZWDecoder(int w, int predictor, int samplesPerPixel) {
73 this.w = w;
74 this.predictor = predictor;
75 this.samplesPerPixel = samplesPerPixel;
76 }
77
78 /**
79 * Method to decode LZW compressed data.
80 *
81 * @param data The compressed data.
82 * @param uncompData Array to return the uncompressed data in.
83 * @param h The number of rows the compressed data contains.
84 */
85 public byte[] decode(byte data[], byte uncompData[], int h) {
86
87 if(data[0] == (byte)0x00 && data[1] == (byte)0x01) {
88 throw new UnsupportedOperationException("TIFF 5.0-style LZW codes are not supported.");
89 }
90
91 initializeStringTable();
92
93 this.data = data;
94 this.h = h;
95 this.uncompData = uncompData;
96
97 // Initialize pointers
98 bytePointer = 0;
99 bitPointer = 0;
100 dstIndex = 0;
101
102
103 nextData = 0;
104 nextBits = 0;
105
106 int code, oldCode = 0;
107 byte string[];
108
109 while ( ((code = getNextCode()) != 257) &&
110 dstIndex < uncompData.length) {
111
112 if (code == 256) {
113
114 initializeStringTable();
115 code = getNextCode();
116
117 if (code == 257) {
118 break;
119 }
120
121 writeString(stringTable[code]);
122 oldCode = code;
123
124 } else {
125
126 if (code < tableIndex) {
127
128 string = stringTable[code];
129
130 writeString(string);
131 addStringToTable(stringTable[oldCode], string[0]);
132 oldCode = code;
133
134 } else {
135
136 string = stringTable[oldCode];
137 string = composeString(string, string[0]);
138 writeString(string);
139 addStringToTable(string);
140 oldCode = code;
141 }
142
143 }
144
145 }
146
147 // Horizontal Differencing Predictor
148 if (predictor == 2) {
149
150 int count;
151 for (int j = 0; j < h; j++) {
152
153 count = samplesPerPixel * (j * w + 1);
154
155 for (int i = samplesPerPixel; i < w * samplesPerPixel; i++) {
156
157 uncompData[count] += uncompData[count - samplesPerPixel];
158 count++;
159 }
160 }
161 }
162
163 return uncompData;
164 }
165
166
167 /**
168 * Initialize the string table.
169 */
170 public void initializeStringTable() {
171
172 stringTable = new byte[4096][];
173
174 for (int i=0; i<256; i++) {
175 stringTable[i] = new byte[1];
176 stringTable[i][0] = (byte)i;
177 }
178
179 tableIndex = 258;
180 bitsToGet = 9;
181 }
182
183 /**
184 * Write out the string just uncompressed.
185 */
186 public void writeString(byte string[]) {
187 // Fix for broken tiff files
188 int max = uncompData.length - dstIndex;
189 if (string.length < max)
190 max = string.length;
191 System.arraycopy(string, 0, uncompData, dstIndex, max);
192 dstIndex += max;
193 }
194
195 /**
196 * Add a new string to the string table.
197 */
198 public void addStringToTable(byte oldString[], byte newString) {
199 int length = oldString.length;
200 byte string[] = new byte[length + 1];
201 System.arraycopy(oldString, 0, string, 0, length);
202 string[length] = newString;
203
204 // Add this new String to the table
205 stringTable[tableIndex++] = string;
206
207 if (tableIndex == 511) {
208 bitsToGet = 10;
209 } else if (tableIndex == 1023) {
210 bitsToGet = 11;
211 } else if (tableIndex == 2047) {
212 bitsToGet = 12;
213 }
214 }
215
216 /**
217 * Add a new string to the string table.
218 */
219 public void addStringToTable(byte string[]) {
220
221 // Add this new String to the table
222 stringTable[tableIndex++] = string;
223
224 if (tableIndex == 511) {
225 bitsToGet = 10;
226 } else if (tableIndex == 1023) {
227 bitsToGet = 11;
228 } else if (tableIndex == 2047) {
229 bitsToGet = 12;
230 }
231 }
232
233 /**
234 * Append <code>newString</code> to the end of <code>oldString</code>.
235 */
236 public byte[] composeString(byte oldString[], byte newString) {
237 int length = oldString.length;
238 byte string[] = new byte[length + 1];
239 System.arraycopy(oldString, 0, string, 0, length);
240 string[length] = newString;
241
242 return string;
243 }
244
245 // Returns the next 9, 10, 11 or 12 bits
246 public int getNextCode() {
247 // Attempt to get the next code. The exception is caught to make
248 // this robust to cases wherein the EndOfInformation code has been
249 // omitted from a strip. Examples of such cases have been observed
250 // in practice.
251 try {
252 nextData = (nextData << 8) | (data[bytePointer++] & 0xff);
253 nextBits += 8;
254
255 if (nextBits < bitsToGet) {
256 nextData = (nextData << 8) | (data[bytePointer++] & 0xff);
257 nextBits += 8;
258 }
259
260 int code =
261 (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet-9];
262 nextBits -= bitsToGet;
263
264 return code;
265 } catch(ArrayIndexOutOfBoundsException e) {
266 // Strip not terminated as expected: return EndOfInformation code.
267 return 257;
268 }
269 }
270 }