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 */ 25 package com.sun.imageio.plugins.tiff; 26 27 import java.io.IOException; 28 import javax.imageio.IIOException; 29 import javax.imageio.plugins.tiff.BaselineTIFFTagSet; 30 31 class TIFFLZWDecompressor extends TIFFDecompressor { 32 33 private static final int andTable[] = { 34 511, 35 1023, 36 2047, 37 4095 38 }; 39 40 private int predictor; 41 42 private byte[] srcData; 43 private byte[] dstData; 44 45 private int srcIndex; 46 private int dstIndex; 47 48 private byte stringTable[][]; 49 private int tableIndex, bitsToGet = 9; 50 51 private int nextData = 0; 52 private int nextBits = 0; 53 54 public TIFFLZWDecompressor(int predictor) throws IIOException { 55 super(); 56 57 if (predictor != BaselineTIFFTagSet.PREDICTOR_NONE && 58 predictor != 59 BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) { 60 throw new IIOException("Illegal value for Predictor in " + 61 "TIFF file"); 62 } 63 64 this.predictor = predictor; 65 } 66 67 public void decodeRaw(byte[] b, 68 int dstOffset, 69 int bitsPerPixel, 70 int scanlineStride) throws IOException { 71 72 // Check bitsPerSample. 73 if (predictor == 74 BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) { 75 int len = bitsPerSample.length; 76 for(int i = 0; i < len; i++) { 77 if(bitsPerSample[i] != 8) { 78 throw new IIOException 79 (bitsPerSample[i] + "-bit samples "+ 80 "are not supported for Horizontal "+ 81 "differencing Predictor"); 82 } 83 } 84 } 85 86 stream.seek(offset); 87 88 byte[] sdata = new byte[byteCount]; 89 stream.readFully(sdata); 90 91 int bytesPerRow = (srcWidth*bitsPerPixel + 7)/8; 92 byte[] buf; 93 int bufOffset; 94 if(bytesPerRow == scanlineStride) { 95 buf = b; 96 bufOffset = dstOffset; 97 } else { 98 buf = new byte[bytesPerRow*srcHeight]; 99 bufOffset = 0; 100 } 101 102 int numBytesDecoded = decode(sdata, 0, buf, bufOffset); 103 104 if(bytesPerRow != scanlineStride) { 105 int off = 0; 106 for (int y = 0; y < srcHeight; y++) { 107 System.arraycopy(buf, off, b, dstOffset, bytesPerRow); 108 off += bytesPerRow; 109 dstOffset += scanlineStride; 110 } 111 } 112 } 113 114 public int decode(byte[] sdata, int srcOffset, 115 byte[] ddata, int dstOffset) 116 throws IOException { 117 if (sdata[0] == (byte)0x00 && sdata[1] == (byte)0x01) { 118 throw new IIOException 119 ("TIFF 5.0-style LZW compression is not supported!"); 120 } 121 122 this.srcData = sdata; 123 this.dstData = ddata; 124 125 this.srcIndex = srcOffset; 126 this.dstIndex = dstOffset; 127 128 this.nextData = 0; 129 this.nextBits = 0; 130 131 initializeStringTable(); 132 133 int code, oldCode = 0; 134 byte[] string; 135 136 while ((code = getNextCode()) != 257) { 137 if (code == 256) { 138 initializeStringTable(); 139 code = getNextCode(); 140 if (code == 257) { 141 break; 142 } 143 144 writeString(stringTable[code]); 145 oldCode = code; 146 } else { 147 if (code < tableIndex) { 148 string = stringTable[code]; 149 150 writeString(string); 151 addStringToTable(stringTable[oldCode], string[0]); 152 oldCode = code; 153 } else { 154 string = stringTable[oldCode]; 155 string = composeString(string, string[0]); 156 writeString(string); 157 addStringToTable(string); 158 oldCode = code; 159 } 160 } 161 } 162 163 if (predictor == 164 BaselineTIFFTagSet.PREDICTOR_HORIZONTAL_DIFFERENCING) { 165 166 for (int j = 0; j < srcHeight; j++) { 167 168 int count = dstOffset + samplesPerPixel * (j * srcWidth + 1); 169 170 for (int i = samplesPerPixel; i < srcWidth * samplesPerPixel; i++) { 171 172 dstData[count] += dstData[count - samplesPerPixel]; 173 count++; 174 } 175 } 176 } 177 178 return dstIndex - dstOffset; 179 } 180 181 /** 182 * Initialize the string table. 183 */ 184 public void initializeStringTable() { 185 stringTable = new byte[4096][]; 186 187 for (int i = 0; i < 256; i++) { 188 stringTable[i] = new byte[1]; 189 stringTable[i][0] = (byte)i; 190 } 191 192 tableIndex = 258; 193 bitsToGet = 9; 194 } 195 196 /** 197 * Write out the string just uncompressed. 198 */ 199 public void writeString(byte string[]) { 200 if(dstIndex < dstData.length) { 201 int maxIndex = Math.min(string.length, 202 dstData.length - dstIndex); 203 204 for (int i=0; i < maxIndex; i++) { 205 dstData[dstIndex++] = string[i]; 206 } 207 } 208 } 209 210 /** 211 * Add a new string to the string table. 212 */ 213 public void addStringToTable(byte oldString[], byte newString) { 214 int length = oldString.length; 215 byte string[] = new byte[length + 1]; 216 System.arraycopy(oldString, 0, string, 0, length); 217 string[length] = newString; 218 219 // Add this new String to the table 220 stringTable[tableIndex++] = string; 221 222 if (tableIndex == 511) { 223 bitsToGet = 10; 224 } else if (tableIndex == 1023) { 225 bitsToGet = 11; 226 } else if (tableIndex == 2047) { 227 bitsToGet = 12; 228 } 229 } 230 231 /** 232 * Add a new string to the string table. 233 */ 234 public void addStringToTable(byte string[]) { 235 // Add this new String to the table 236 stringTable[tableIndex++] = string; 237 238 if (tableIndex == 511) { 239 bitsToGet = 10; 240 } else if (tableIndex == 1023) { 241 bitsToGet = 11; 242 } else if (tableIndex == 2047) { 243 bitsToGet = 12; 244 } 245 } 246 247 /** 248 * Append {@code newString} to the end of {@code oldString}. 249 */ 250 public byte[] composeString(byte oldString[], byte newString) { 251 int length = oldString.length; 252 byte string[] = new byte[length + 1]; 253 System.arraycopy(oldString, 0, string, 0, length); 254 string[length] = newString; 255 256 return string; 257 } 258 259 // Returns the next 9, 10, 11 or 12 bits 260 public int getNextCode() { 261 // Attempt to get the next code. The exception is caught to make 262 // this robust to cases wherein the EndOfInformation code has been 263 // omitted from a strip. Examples of such cases have been observed 264 // in practice. 265 266 try { 267 nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff); 268 nextBits += 8; 269 270 if (nextBits < bitsToGet) { 271 nextData = (nextData << 8) | (srcData[srcIndex++] & 0xff); 272 nextBits += 8; 273 } 274 275 int code = 276 (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet - 9]; 277 nextBits -= bitsToGet; 278 279 return code; 280 } catch (ArrayIndexOutOfBoundsException e) { 281 // Strip not terminated as expected: return EndOfInformation code. 282 return 257; 283 } 284 } 285 }