1 /*
2  * Copyright (c) 2005, 2018, 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  */
25 package com.sun.imageio.plugins.tiff;
26 
27 import java.io.IOException;
28 import javax.imageio.IIOException;
29 
30 class TIFFLZWUtil {
TIFFLZWUtil()31     public TIFFLZWUtil() {
32     }
33 
34     byte[] srcData;
35     int srcIndex;
36 
37     byte[] dstData;
38     int dstIndex = 0;
39 
40     byte[][] stringTable;
41     int tableIndex, bitsToGet = 9;
42 
43     int nextData = 0;
44     int nextBits = 0;
45 
46     private static final int[] andTable = {
47         511,
48         1023,
49         2047,
50         4095
51     };
52 
decode(byte[] data, int predictor, int samplesPerPixel, int width, int height)53     public byte[] decode(byte[] data, int predictor, int samplesPerPixel,
54                          int width, int height) throws IOException {
55         if (data[0] == (byte)0x00 && data[1] == (byte)0x01) {
56             throw new IIOException("TIFF 5.0-style LZW compression is not supported!");
57         }
58 
59         this.srcData = data;
60         this.srcIndex = 0;
61         this.nextData = 0;
62         this.nextBits = 0;
63 
64         this.dstData = new byte[8192];
65         this.dstIndex = 0;
66 
67         initializeStringTable();
68 
69         int code, oldCode = 0;
70         byte[] string;
71 
72         while ((code = getNextCode()) != 257) {
73             if (code == 256) {
74                 initializeStringTable();
75                 code = getNextCode();
76                 if (code == 257) {
77                     break;
78                 }
79 
80                 writeString(stringTable[code]);
81                 oldCode = code;
82             } else {
83                 if (code < tableIndex) {
84                     string = stringTable[code];
85 
86                     writeString(string);
87                     addStringToTable(stringTable[oldCode], string[0]);
88                     oldCode = code;
89                 } else {
90                     string = stringTable[oldCode];
91                     string = composeString(string, string[0]);
92                     writeString(string);
93                     addStringToTable(string);
94                     oldCode = code;
95                 }
96             }
97         }
98 
99         if (predictor == 2) {
100 
101             int count;
102             for (int j = 0; j < height; j++) {
103 
104                 count = samplesPerPixel * (j * width + 1);
105 
106                 for (int i = samplesPerPixel; i < width * samplesPerPixel; i++) {
107 
108                     dstData[count] += dstData[count - samplesPerPixel];
109                     count++;
110                 }
111             }
112         }
113 
114         byte[] newDstData = new byte[dstIndex];
115         System.arraycopy(dstData, 0, newDstData, 0, dstIndex);
116         return newDstData;
117     }
118 
119     /**
120      * Initialize the string table.
121      */
initializeStringTable()122     public void initializeStringTable() {
123         stringTable = new byte[4096][];
124 
125         for (int i = 0; i < 256; i++) {
126             stringTable[i] = new byte[1];
127             stringTable[i][0] = (byte)i;
128         }
129 
130         tableIndex = 258;
131         bitsToGet = 9;
132     }
133 
ensureCapacity(int bytesToAdd)134     private void ensureCapacity(int bytesToAdd) {
135         if (dstIndex + bytesToAdd > dstData.length) {
136             byte[] newDstData = new byte[Math.max((int)(dstData.length*1.2f),
137                                                   dstIndex + bytesToAdd)];
138             System.arraycopy(dstData, 0, newDstData, 0, dstData.length);
139             dstData = newDstData;
140         }
141     }
142 
143     /**
144      * Write out the string just uncompressed.
145      */
writeString(byte[] string)146     public void writeString(byte[] string) {
147         ensureCapacity(string.length);
148         for (int i = 0; i < string.length; i++) {
149             dstData[dstIndex++] = string[i];
150         }
151     }
152 
153     /**
154      * Add a new string to the string table.
155      */
addStringToTable(byte[] oldString, byte newString)156     public void addStringToTable(byte[] oldString, byte newString) {
157         int length = oldString.length;
158         byte[] string = new byte[length + 1];
159         System.arraycopy(oldString, 0, string, 0, length);
160         string[length] = newString;
161 
162         // Add this new String to the table
163         stringTable[tableIndex++] = string;
164 
165         if (tableIndex == 511) {
166             bitsToGet = 10;
167         } else if (tableIndex == 1023) {
168             bitsToGet = 11;
169         } else if (tableIndex == 2047) {
170             bitsToGet = 12;
171         }
172     }
173 
174     /**
175      * Add a new string to the string table.
176      */
addStringToTable(byte[] string)177     public void addStringToTable(byte[] string) {
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} to the end of {@code oldString}.
192      */
composeString(byte[] oldString, byte newString)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
getNextCode()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 
209         try {
210             nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
211             nextBits += 8;
212 
213             if (nextBits < bitsToGet) {
214                 nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff);
215                 nextBits += 8;
216             }
217 
218             int code =
219                 (nextData >> (nextBits - bitsToGet)) & 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 }
229