001: /*
002: * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * -Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * -Redistribution in binary form must reproduct the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of Sun Microsystems, Inc. or the names of contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * This software is provided "AS IS," without a warranty of any kind. ALL
019: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
020: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
021: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
022: * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
023: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
024: * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
025: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
026: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
027: * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
028: * POSSIBILITY OF SUCH DAMAGES.
029: *
030: * You acknowledge that Software is not designed,licensed or intended for use in
031: * the design, construction, operation or maintenance of any nuclear facility.
032: *
033: * Adapted from the JAI codecs TIFFLZWDecoder.
034: */
035: package com.lowagie.text.pdf;
036:
037: import java.io.IOException;
038: import java.io.OutputStream;
039:
040: import com.lowagie.text.ExceptionConverter;
041:
042: /**
043: * A class for performing LZW decoding.
044: *
045: *
046: */
047: public class LZWDecoder {
048:
049: byte stringTable[][];
050: byte data[] = null;
051: OutputStream uncompData;
052: int tableIndex, bitsToGet = 9;
053: int bytePointer, bitPointer;
054: int nextData = 0;
055: int nextBits = 0;
056:
057: int andTable[] = { 511, 1023, 2047, 4095 };
058:
059: public LZWDecoder() {
060: }
061:
062: /**
063: * Method to decode LZW compressed data.
064: *
065: * @param data The compressed data.
066: * @param uncompData Array to return the uncompressed data in.
067: */
068: public void decode(byte data[], OutputStream uncompData) {
069:
070: if (data[0] == (byte) 0x00 && data[1] == (byte) 0x01) {
071: throw new RuntimeException("LZW flavour not supported.");
072: }
073:
074: initializeStringTable();
075:
076: this .data = data;
077: this .uncompData = uncompData;
078:
079: // Initialize pointers
080: bytePointer = 0;
081: bitPointer = 0;
082:
083: nextData = 0;
084: nextBits = 0;
085:
086: int code, oldCode = 0;
087: byte string[];
088:
089: while ((code = getNextCode()) != 257) {
090:
091: if (code == 256) {
092:
093: initializeStringTable();
094: code = getNextCode();
095:
096: if (code == 257) {
097: break;
098: }
099:
100: writeString(stringTable[code]);
101: oldCode = code;
102:
103: } else {
104:
105: if (code < tableIndex) {
106:
107: string = stringTable[code];
108:
109: writeString(string);
110: addStringToTable(stringTable[oldCode], string[0]);
111: oldCode = code;
112:
113: } else {
114:
115: string = stringTable[oldCode];
116: string = composeString(string, string[0]);
117: writeString(string);
118: addStringToTable(string);
119: oldCode = code;
120: }
121: }
122: }
123: }
124:
125: /**
126: * Initialize the string table.
127: */
128: public void initializeStringTable() {
129:
130: stringTable = new byte[8192][];
131:
132: for (int i = 0; i < 256; i++) {
133: stringTable[i] = new byte[1];
134: stringTable[i][0] = (byte) i;
135: }
136:
137: tableIndex = 258;
138: bitsToGet = 9;
139: }
140:
141: /**
142: * Write out the string just uncompressed.
143: */
144: public void writeString(byte string[]) {
145: try {
146: uncompData.write(string);
147: } catch (IOException e) {
148: throw new ExceptionConverter(e);
149: }
150: }
151:
152: /**
153: * Add a new string to the string table.
154: */
155: public void addStringToTable(byte oldString[], byte newString) {
156: int length = oldString.length;
157: byte string[] = new byte[length + 1];
158: System.arraycopy(oldString, 0, string, 0, length);
159: string[length] = newString;
160:
161: // Add this new String to the table
162: stringTable[tableIndex++] = string;
163:
164: if (tableIndex == 511) {
165: bitsToGet = 10;
166: } else if (tableIndex == 1023) {
167: bitsToGet = 11;
168: } else if (tableIndex == 2047) {
169: bitsToGet = 12;
170: }
171: }
172:
173: /**
174: * Add a new string to the string table.
175: */
176: public void addStringToTable(byte string[]) {
177:
178: // Add this new String to the table
179: stringTable[tableIndex++] = string;
180:
181: if (tableIndex == 511) {
182: bitsToGet = 10;
183: } else if (tableIndex == 1023) {
184: bitsToGet = 11;
185: } else if (tableIndex == 2047) {
186: bitsToGet = 12;
187: }
188: }
189:
190: /**
191: * Append <code>newString</code> to the end of <code>oldString</code>.
192: */
193: public byte[] composeString(byte oldString[], byte newString) {
194: int length = oldString.length;
195: byte string[] = new byte[length + 1];
196: System.arraycopy(oldString, 0, string, 0, length);
197: string[length] = newString;
198:
199: return string;
200: }
201:
202: // Returns the next 9, 10, 11 or 12 bits
203: public int getNextCode() {
204: // Attempt to get the next code. The exception is caught to make
205: // this robust to cases wherein the EndOfInformation code has been
206: // omitted from a strip. Examples of such cases have been observed
207: // in practice.
208: try {
209: nextData = (nextData << 8) | (data[bytePointer++] & 0xff);
210: nextBits += 8;
211:
212: if (nextBits < bitsToGet) {
213: nextData = (nextData << 8)
214: | (data[bytePointer++] & 0xff);
215: nextBits += 8;
216: }
217:
218: int code = (nextData >> (nextBits - bitsToGet))
219: & andTable[bitsToGet - 9];
220: nextBits -= bitsToGet;
221:
222: return code;
223: } catch (ArrayIndexOutOfBoundsException e) {
224: // Strip not terminated as expected: return EndOfInformation code.
225: return 257;
226: }
227: }
228: }
|