1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.pdfbox.filter; 18 19 import java.io.ByteArrayOutputStream; 20 import java.io.IOException; 21 22 import java.util.HashMap; 23 import java.util.Map; 24 25 /** 26 * This is the used for the LZWDecode filter. This represents the dictionary mappings 27 * between codes and their values. 28 * 29 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a> 30 * @version $Revision: 1.4 $ 31 */ 32 class LZWDictionary 33 { 34 private Map codeToData = new HashMap(); 35 private LZWNode root = new LZWNode(); 36 37 private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 38 private long nextCode = 258; 39 private int codeSize = 9; 40 41 /** 42 * constructor. 43 */ 44 public LZWDictionary() 45 { 46 for( long i=0; i<256; i++ ) 47 { 48 LZWNode node = new LZWNode(); 49 node.setCode( i ); 50 root.setNode( (byte)i, node ); 51 codeToData.put( new Long( i ), new byte[]{ (byte)i } ); 52 } 53 } 54 55 /** 56 * This will get the value for the code. It will return null if the code is not 57 * defined. 58 * 59 * @param code The key to the data. 60 * 61 * @return The data that is mapped to the code. 62 */ 63 public byte[] getData( long code ) 64 { 65 return (byte[])codeToData.get( new Long( code ) ); 66 } 67 68 /** 69 * This will take a visit from a byte[]. This will create new code entries as 70 * necessary. 71 * 72 * @param data The byte to get a visit from. 73 * 74 * @throws IOException If there is an error visiting this data. 75 */ 76 public void visit( byte[] data ) throws IOException 77 { 78 for( int i=0; i<data.length; i++ ) 79 { 80 visit( data[i] ); 81 } 82 } 83 84 /** 85 * This will take a visit from a byte. This will create new code entries as 86 * necessary. 87 * 88 * @param data The byte to get a visit from. 89 * 90 * @throws IOException If there is an error visiting this data. 91 */ 92 public void visit( byte data ) throws IOException 93 { 94 buffer.write( data ); 95 byte[] curBuffer = buffer.toByteArray(); 96 LZWNode previous = null; 97 LZWNode current = root; 98 boolean createNewCode = false; 99 for( int i=0; i<curBuffer.length && current != null; i++ ) 100 { 101 previous = current; 102 current = current.getNode( curBuffer[i] ); 103 if( current == null ) 104 { 105 createNewCode = true; 106 current = new LZWNode(); 107 previous.setNode( curBuffer[i], current ); 108 } 109 } 110 if( createNewCode ) 111 { 112 long code = nextCode++; 113 current.setCode( code ); 114 codeToData.put( new Long( code ), curBuffer ); 115 116 /** 117 System.out.print( "Adding " + code + "='" ); 118 for( int i=0; i<curBuffer.length; i++ ) 119 { 120 String hex = Integer.toHexString( ((curBuffer[i]+256)%256) ); 121 if( hex.length() <=1 ) 122 { 123 hex = "0" + hex; 124 } 125 if( i != curBuffer.length -1 ) 126 { 127 hex += " "; 128 } 129 System.out.print( hex.toUpperCase() ); 130 } 131 System.out.println( "'" ); 132 **/ 133 buffer.reset(); 134 buffer.write( data ); 135 resetCodeSize(); 136 } 137 } 138 139 /** 140 * This will get the next code that will be created. 141 * 142 * @return The next code to be created. 143 */ 144 public long getNextCode() 145 { 146 return nextCode; 147 } 148 149 /** 150 * This will get the size of the code in bits, 9, 10, or 11. 151 * 152 * @return The size of the code in bits. 153 */ 154 public int getCodeSize() 155 { 156 return codeSize; 157 } 158 159 /** 160 * This will determine the code size. 161 */ 162 private void resetCodeSize() 163 { 164 if( nextCode >= 2048 ) 165 { 166 codeSize = 12; 167 } 168 else if( nextCode >= 1024 ) 169 { 170 codeSize = 11; 171 } 172 else if( nextCode >= 512 ) 173 { 174 codeSize = 10; 175 } 176 else 177 { 178 codeSize = 9; 179 } 180 } 181 182 /** 183 * This will crear the internal buffer that the dictionary uses. 184 */ 185 public void clear() 186 { 187 buffer.reset(); 188 } 189 190 /** 191 * This will folow the path to the data node. 192 * 193 * @param data The path to the node. 194 * 195 * @return The node that resides at that path. 196 */ 197 public LZWNode getNode( byte[] data ) 198 { 199 return root.getNode( data ); 200 } 201 }