1/*
2 * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package com.sun.imageio.plugins.tiff;
26
27import java.io.IOException;
28import javax.imageio.IIOException;
29import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
30
31class TIFFLZWDecompressor extends TIFFDecompressor {
32
33    private static final int CLEAR_CODE = 256;
34    private static final int EOI_CODE   = 257;
35    private static final int FIRST_CODE = 258;
36
37    private static final int andTable[] = {
38        511,
39        1023,
40        2047,
41        4095
42    };
43
44    private int predictor;
45
46    // whether to reverse the bits in each byte of the input data, i.e.,
47    // convert right-to-left fill order (lsb) to left-to-right (msb).
48    private boolean flipBits;
49
50    private byte[] srcData;
51    private byte[] dstData;
52
53    private int srcIndex;
54    private int dstIndex;
55
56    private byte stringTable[][];
57    private int tableIndex, bitsToGet = 9;
58
59    private int nextData = 0;
60    private int nextBits = 0;
61
62    public TIFFLZWDecompressor(int predictor, int fillOrder)
63        throws IIOException {
64        super();
65
66        if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE &&
67            predictor !=
68            BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
69            throw new IIOException("Illegal value for Predictor in " +
70                                   "TIFF file");
71        }
72
73        this.predictor = predictor;
74
75        flipBits = fillOrder == BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT;
76    }
77
78    public void decodeRaw(byte[] b,
79                          int dstOffset,
80                          int bitsPerPixel,
81                          int scanlineStride) throws IOException {
82
83        // Check bitsPerSample.
84        if (predictor ==
85            BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
86            int len = bitsPerSample.length;
87            for(int i = 0; i < len; i++) {
88                if(bitsPerSample[i] != 8) {
89                    throw new IIOException
90                        (bitsPerSample[i] + "-bit samples "+
91                         "are not supported for Horizontal "+
92                         "differencing Predictor");
93                }
94            }
95        }
96
97        stream.seek(offset);
98
99        byte[] sdata = new byte[byteCount];
100        stream.readFully(sdata);
101
102        if (flipBits) {
103            for (int i = 0; i < byteCount; i++) {
104                sdata[i] = TIFFFaxDecompressor.flipTable[sdata[i] & 0xff];
105            }
106        }
107
108        int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8;
109        byte[] buf;
110        int bufOffset;
111        if(bytesPerRow == scanlineStride) {
112            buf = b;
113            bufOffset = dstOffset;
114        } else {
115            buf = new byte[bytesPerRow*srcHeight];
116            bufOffset = 0;
117        }
118
119        int numBytesDecoded = decode(sdata, 0, buf, bufOffset);
120
121        if(bytesPerRow != scanlineStride) {
122            int off = 0;
123            for (int y = 0; y < srcHeight; y++) {
124                System.arraycopy(buf, off, b, dstOffset, bytesPerRow);
125                off += bytesPerRow;
126                dstOffset += scanlineStride;
127            }
128        }
129    }
130
131    public int decode(byte[] sdata, int srcOffset,
132                      byte[] ddata, int dstOffset)
133        throws IOException {
134        if (sdata[0] == (byte)0x00 && sdata[1] == (byte)0x01) {
135            throw new IIOException
136                ("TIFF 5.0-style LZW compression is not supported!");
137        }
138
139        this.srcData = sdata;
140        this.dstData = ddata;
141
142        this.srcIndex = srcOffset;
143        this.dstIndex = dstOffset;
144
145        this.nextData = 0;
146        this.nextBits = 0;
147
148        initializeStringTable();
149
150        int code, oldCode = 0;
151        byte[] string;
152
153        while ((code = getNextCode()) != EOI_CODE) {
154            if (code == CLEAR_CODE) {
155                initializeStringTable();
156                code = getNextCode();
157                if (code == EOI_CODE) {
158                    break;
159                }
160
161                writeString(stringTable[code]);
162                oldCode = code;
163            } else {
164                if (code < tableIndex) {
165                    string = stringTable[code];
166
167                    writeString(string);
168                    addStringToTable(stringTable[oldCode], string[0]);
169                    oldCode = code;
170                } else {
171                    string = stringTable[oldCode];
172                    string = composeString(string, string[0]);
173                    writeString(string);
174                    addStringToTable(string);
175                    oldCode = code;
176                }
177            }
178        }
179
180        if (predictor ==
181            BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) {
182            int step = planar || samplesPerPixel == 1 ? 1 : samplesPerPixel;
183
184            int samplesPerRow = step * srcWidth;
185
186            int off = dstOffset + step;
187            for (int j = 0; j < srcHeight; j++) {
188                int count = off;
189                for (int i = step; i < samplesPerRow; i++) {
190                    dstData[count] += dstData[count - step];
191                    count++;
192                }
193                off += samplesPerRow;
194            }
195        }
196
197        return dstIndex - dstOffset;
198    }
199
200    /**
201     * Initialize the string table.
202     */
203    public void initializeStringTable() {
204        stringTable = new byte[4096][];
205
206        for (int i = 0; i < CLEAR_CODE; i++) {
207            stringTable[i] = new byte[1];
208            stringTable[i][0] = (byte)i;
209        }
210
211        tableIndex = FIRST_CODE;
212        bitsToGet = 9;
213    }
214
215    /**
216     * Write out the string just uncompressed.
217     */
218    public void writeString(byte string[]) {
219        if(dstIndex < dstData.length) {
220            int maxIndex = Math.min(string.length,
221                                    dstData.length - dstIndex);
222
223            for (int i=0; i < maxIndex; i++) {
224                dstData[dstIndex++] = string[i];
225            }
226        }
227    }
228
229    /**
230     * Add a new string to the string table.
231     */
232    public void addStringToTable(byte oldString[], byte newString) {
233        int length = oldString.length;
234        byte string[] = new byte[length + 1];
235        System.arraycopy(oldString, 0, string, 0, length);
236        string[length] = newString;
237
238        // Add this new String to the table
239        stringTable[tableIndex++] = string;
240
241        if (tableIndex == 511) {
242            bitsToGet = 10;
243        } else if (tableIndex == 1023) {
244            bitsToGet = 11;
245        } else if (tableIndex == 2047) {
246            bitsToGet = 12;
247        }
248    }
249
250    /**
251     * Add a new string to the string table.
252     */
253    public void addStringToTable(byte string[]) {
254        // Add this new String to the table
255        stringTable[tableIndex++] = string;
256
257        if (tableIndex == 511) {
258            bitsToGet = 10;
259        } else if (tableIndex == 1023) {
260            bitsToGet = 11;
261        } else if (tableIndex == 2047) {
262            bitsToGet = 12;
263        }
264    }
265
266    /**
267     * Append {@code newString} to the end of {@code oldString}.
268     */
269    public byte[] composeString(byte oldString[], byte newString) {
270        int length = oldString.length;
271        byte string[] = new byte[length + 1];
272        System.arraycopy(oldString, 0, string, 0, length);
273        string[length] = newString;
274
275        return string;
276    }
277
278    // Returns the next 9, 10, 11 or 12 bits
279    public int getNextCode() {
280        // Attempt to get the next code. The exception is caught to make
281        // this robust to cases wherein the EndOfInformation code has been
282        // omitted from a strip. Examples of such cases have been observed
283        // in practice.
284
285        try {
286            nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
287            nextBits += 8;
288
289            if (nextBits < bitsToGet) {
290                nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
291                nextBits += 8;
292            }
293
294            int code =
295                (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet - 9];
296            nextBits -= bitsToGet;
297
298            return code;
299        } catch (ArrayIndexOutOfBoundsException e) {
300            // Strip not terminated as expected: return EndOfInformation code.
301            return EOI_CODE;
302        }
303    }
304}
305