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