001/* 002 * $RCSfile: LZWStringTable.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:23 $ 043 * $State: Exp $ 044 */ 045 046package com.github.jaiimageio.impl.common; 047 048import java.io.PrintStream; 049 050/** 051 * General purpose LZW String Table. 052 * Extracted from GIFEncoder by Adam Doppelt 053 * Comments added by Robin Luiten 054 * <code>expandCode</code> added by Robin Luiten 055 * The strLen_ table to give quick access to the lenght of an expanded 056 * code for use by the <code>expandCode</code> method added by Robin. 057 **/ 058public class LZWStringTable 059{ 060 /** codesize + Reserved Codes */ 061 private final static int RES_CODES = 2; 062 063 private final static short HASH_FREE = (short)0xFFFF; 064 private final static short NEXT_FIRST = (short)0xFFFF; 065 066 private final static int MAXBITS = 12; 067 private final static int MAXSTR = (1 << MAXBITS); 068 069 private final static short HASHSIZE = 9973; 070 private final static short HASHSTEP = 2039; 071 072 byte[] strChr_; // after predecessor character 073 short[] strNxt_; // predecessor string 074 short[] strHsh_; // hash table to find predecessor + char pairs 075 short numStrings_; // next code if adding new prestring + char 076 077 /** 078 * each entry corresponds to a code and contains the length of data 079 * that the code expands to when decoded. 080 **/ 081 int[] strLen_; 082 083 /** 084 * Constructor allocate memory for string store data 085 **/ 086 public LZWStringTable() 087 { 088 strChr_ = new byte[MAXSTR]; 089 strNxt_ = new short[MAXSTR]; 090 strLen_ = new int[MAXSTR]; 091 strHsh_ = new short[HASHSIZE]; 092 } 093 094 /** 095 * @param index value of -1 indicates no predecessor [used in initialisation] 096 * @param b the byte [character] to add to the string store which follows 097 * the predecessor string specified the index. 098 * @return 0xFFFF if no space in table left for addition of predecesor 099 * index and byte b. Else return the code allocated for combination index + b. 100 **/ 101 public int AddCharString(short index, byte b) 102 { 103 int hshidx; 104 105 if (numStrings_ >= MAXSTR) // if used up all codes 106 { 107 return 0xFFFF; 108 } 109 110 hshidx = Hash(index, b); 111 while (strHsh_[hshidx] != HASH_FREE) 112 hshidx = (hshidx + HASHSTEP) % HASHSIZE; 113 114 strHsh_[hshidx] = numStrings_; 115 strChr_[numStrings_] = b; 116 if (index == HASH_FREE) 117 { 118 strNxt_[numStrings_] = NEXT_FIRST; 119 strLen_[numStrings_] = 1; 120 } 121 else 122 { 123 strNxt_[numStrings_] = index; 124 strLen_[numStrings_] = strLen_[index] + 1; 125 } 126 127 return numStrings_++; // return the code and inc for next code 128 } 129 130 /** 131 * @param index index to prefix string 132 * @param b the character that follws the index prefix 133 * @return b if param index is HASH_FREE. Else return the code 134 * for this prefix and byte successor 135 **/ 136 public short FindCharString(short index, byte b) 137 { 138 int hshidx, nxtidx; 139 140 if (index == HASH_FREE) 141 return (short)(b & 0xFF); // Rob fixed used to sign extend 142 143 hshidx = Hash(index, b); 144 while ((nxtidx = strHsh_[hshidx]) != HASH_FREE) // search 145 { 146 if (strNxt_[nxtidx] == index && strChr_[nxtidx] == b) 147 return (short)nxtidx; 148 hshidx = (hshidx + HASHSTEP) % HASHSIZE; 149 } 150 151 return (short)0xFFFF; 152 } 153 154 /** 155 * @param codesize the size of code to be preallocated for the 156 * string store. 157 **/ 158 public void ClearTable(int codesize) 159 { 160 numStrings_ = 0; 161 162 for (int q = 0; q < HASHSIZE; q++) 163 strHsh_[q] = HASH_FREE; 164 165 int w = (1 << codesize) + RES_CODES; 166 for (int q = 0; q < w; q++) 167 AddCharString((short)0xFFFF, (byte)q); // init with no prefix 168 } 169 170 static public int Hash(short index, byte lastbyte) 171 { 172 return ((int)((short)(lastbyte << 8) ^ index) & 0xFFFF) % HASHSIZE; 173 } 174 175 /** 176 * If expanded data doesnt fit into array only what will fit is written 177 * to buf and the return value indicates how much of the expanded code has 178 * been written to the buf. The next call to expandCode() should be with 179 * the same code and have the skip parameter set the negated value of the 180 * previous return. Succesive negative return values should be negated and 181 * added together for next skip parameter value with same code. 182 * 183 * @param buf buffer to place expanded data into 184 * @param offset offset to place expanded data 185 * @param code the code to expand to the byte array it represents. 186 * PRECONDITION This code must allready be in the LZSS 187 * @param skipHead is the number of bytes at the start of the expanded code to 188 * be skipped before data is written to buf. It is possible that skipHead is 189 * equal to codeLen. 190 * @return the length of data expanded into buf. If the expanded code is longer 191 * than space left in buf then the value returned is a negative number which when 192 * negated is equal to the number of bytes that were used of the code being expanded. 193 * This negative value also indicates the buffer is full. 194 **/ 195 public int expandCode(byte[] buf, int offset, short code, int skipHead) 196 { 197 if (offset == -2) 198 { 199 if (skipHead == 1) skipHead = 0; 200 } 201 if (code == (short)0xFFFF || // just in case 202 skipHead == strLen_[code]) // DONE no more unpacked 203 return 0; 204 205 int expandLen; // how much data we are actually expanding 206 int codeLen = strLen_[code] - skipHead; // length of expanded code left 207 int bufSpace = buf.length - offset; // how much space left 208 if (bufSpace > codeLen) 209 expandLen = codeLen; // only got this many to unpack 210 else 211 expandLen = bufSpace; 212 213 int skipTail = codeLen - expandLen; // only > 0 if codeLen > bufSpace [left overs] 214 215 int idx = offset + expandLen; // initialise to exclusive end address of buffer area 216 217 // NOTE: data unpacks in reverse direction and we are placing the 218 // unpacked data directly into the array in the correct location. 219 while ((idx > offset) && (code != (short)0xFFFF)) 220 { 221 if (--skipTail < 0) // skip required of expanded data 222 { 223 buf[--idx] = strChr_[code]; 224 } 225 code = strNxt_[code]; // to predecessor code 226 } 227 228 if (codeLen > expandLen) 229 return -expandLen; // indicate what part of codeLen used 230 else 231 return expandLen; // indicate length of dat unpacked 232 } 233 234 public void dump(PrintStream out) 235 { 236 int i; 237 for (i = 258; i < numStrings_; ++i) 238 out.println( " strNxt_[" + i + "] = " + strNxt_[i] 239 + " strChr_ " + Integer.toHexString(strChr_[i] & 0xFF) 240 + " strLen_ " + Integer.toHexString(strLen_[i])); 241 } 242}