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