001/* 002 * Copyright 2002-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; 047import java.io.IOException; 048import java.io.OutputStream; 049import com.itextpdf.text.error_messages.MessageLocalization; 050 051import com.itextpdf.text.ExceptionConverter; 052/** 053 * A class for performing LZW decoding. 054 * 055 * 056 */ 057public class LZWDecoder { 058 059 byte stringTable[][]; 060 byte data[] = null; 061 OutputStream uncompData; 062 int tableIndex, bitsToGet = 9; 063 int bytePointer, bitPointer; 064 int nextData = 0; 065 int nextBits = 0; 066 067 int andTable[] = { 068 511, 069 1023, 070 2047, 071 4095 072 }; 073 074 public LZWDecoder() { 075 } 076 077 /** 078 * Method to decode LZW compressed data. 079 * 080 * @param data The compressed data. 081 * @param uncompData Array to return the uncompressed data in. 082 */ 083 public void decode(byte data[], OutputStream uncompData) { 084 085 if(data[0] == (byte)0x00 && data[1] == (byte)0x01) { 086 throw new RuntimeException(MessageLocalization.getComposedMessage("lzw.flavour.not.supported")); 087 } 088 089 initializeStringTable(); 090 091 this.data = data; 092 this.uncompData = uncompData; 093 094 // Initialize pointers 095 bytePointer = 0; 096 bitPointer = 0; 097 098 nextData = 0; 099 nextBits = 0; 100 101 int code, oldCode = 0; 102 byte string[]; 103 104 while ((code = getNextCode()) != 257) { 105 106 if (code == 256) { 107 108 initializeStringTable(); 109 code = getNextCode(); 110 111 if (code == 257) { 112 break; 113 } 114 115 writeString(stringTable[code]); 116 oldCode = code; 117 118 } else { 119 120 if (code < tableIndex) { 121 122 string = stringTable[code]; 123 124 writeString(string); 125 addStringToTable(stringTable[oldCode], string[0]); 126 oldCode = code; 127 128 } else { 129 130 string = stringTable[oldCode]; 131 string = composeString(string, string[0]); 132 writeString(string); 133 addStringToTable(string); 134 oldCode = code; 135 } 136 } 137 } 138 } 139 140 141 /** 142 * Initialize the string table. 143 */ 144 public void initializeStringTable() { 145 146 stringTable = new byte[8192][]; 147 148 for (int i=0; i<256; i++) { 149 stringTable[i] = new byte[1]; 150 stringTable[i][0] = (byte)i; 151 } 152 153 tableIndex = 258; 154 bitsToGet = 9; 155 } 156 157 /** 158 * Write out the string just uncompressed. 159 */ 160 public void writeString(byte string[]) { 161 try { 162 uncompData.write(string); 163 } 164 catch (IOException e) { 165 throw new ExceptionConverter(e); 166 } 167 } 168 169 /** 170 * Add a new string to the string table. 171 */ 172 public void addStringToTable(byte oldString[], byte newString) { 173 int length = oldString.length; 174 byte string[] = new byte[length + 1]; 175 System.arraycopy(oldString, 0, string, 0, length); 176 string[length] = newString; 177 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 * Add a new string to the string table. 192 */ 193 public void addStringToTable(byte string[]) { 194 195 // Add this new String to the table 196 stringTable[tableIndex++] = string; 197 198 if (tableIndex == 511) { 199 bitsToGet = 10; 200 } else if (tableIndex == 1023) { 201 bitsToGet = 11; 202 } else if (tableIndex == 2047) { 203 bitsToGet = 12; 204 } 205 } 206 207 /** 208 * Append <code>newString</code> to the end of <code>oldString</code>. 209 */ 210 public byte[] composeString(byte oldString[], byte newString) { 211 int length = oldString.length; 212 byte string[] = new byte[length + 1]; 213 System.arraycopy(oldString, 0, string, 0, length); 214 string[length] = newString; 215 216 return string; 217 } 218 219 // Returns the next 9, 10, 11 or 12 bits 220 public int getNextCode() { 221 // Attempt to get the next code. The exception is caught to make 222 // this robust to cases wherein the EndOfInformation code has been 223 // omitted from a strip. Examples of such cases have been observed 224 // in practice. 225 try { 226 nextData = (nextData << 8) | (data[bytePointer++] & 0xff); 227 nextBits += 8; 228 229 if (nextBits < bitsToGet) { 230 nextData = (nextData << 8) | (data[bytePointer++] & 0xff); 231 nextBits += 8; 232 } 233 234 int code = 235 (nextData >> (nextBits - bitsToGet)) & andTable[bitsToGet-9]; 236 nextBits -= bitsToGet; 237 238 return code; 239 } catch(ArrayIndexOutOfBoundsException e) { 240 // Strip not terminated as expected: return EndOfInformation code. 241 return 257; 242 } 243 } 244}