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}