001: /**
002: * Copyright (c) 2003, www.pdfbox.org
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions are met:
007: *
008: * 1. Redistributions of source code must retain the above copyright notice,
009: * this list of conditions and the following disclaimer.
010: * 2. Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: * 3. Neither the name of pdfbox; nor the names of its
014: * contributors may be used to endorse or promote products derived from this
015: * software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
021: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: *
028: * http://www.pdfbox.org
029: *
030: */package org.pdfbox.filter;
031:
032: import java.io.ByteArrayOutputStream;
033: import java.io.IOException;
034:
035: import java.util.HashMap;
036: import java.util.Map;
037:
038: /**
039: * This is the used for the LZWDecode filter. This represents the dictionary mappings
040: * between codes and their values.
041: *
042: * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
043: * @version $Revision: 1.4 $
044: */
045: class LZWDictionary {
046: private Map codeToData = new HashMap();
047: private LZWNode root = new LZWNode();
048:
049: private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
050: private long nextCode = 258;
051: private int codeSize = 9;
052:
053: /**
054: * constructor.
055: */
056: public LZWDictionary() {
057: for (long i = 0; i < 256; i++) {
058: LZWNode node = new LZWNode();
059: node.setCode(i);
060: root.setNode((byte) i, node);
061: codeToData.put(new Long(i), new byte[] { (byte) i });
062: }
063: }
064:
065: /**
066: * This will get the value for the code. It will return null if the code is not
067: * defined.
068: *
069: * @param code The key to the data.
070: *
071: * @return The data that is mapped to the code.
072: */
073: public byte[] getData(long code) {
074: return (byte[]) codeToData.get(new Long(code));
075: }
076:
077: /**
078: * This will take a visit from a byte[]. This will create new code entries as
079: * necessary.
080: *
081: * @param data The byte to get a visit from.
082: *
083: * @throws IOException If there is an error visiting this data.
084: */
085: public void visit(byte[] data) throws IOException {
086: for (int i = 0; i < data.length; i++) {
087: visit(data[i]);
088: }
089: }
090:
091: /**
092: * This will take a visit from a byte. This will create new code entries as
093: * necessary.
094: *
095: * @param data The byte to get a visit from.
096: *
097: * @throws IOException If there is an error visiting this data.
098: */
099: public void visit(byte data) throws IOException {
100: buffer.write(data);
101: byte[] curBuffer = buffer.toByteArray();
102: LZWNode previous = null;
103: LZWNode current = root;
104: boolean createNewCode = false;
105: for (int i = 0; i < curBuffer.length && current != null; i++) {
106: previous = current;
107: current = current.getNode(curBuffer[i]);
108: if (current == null) {
109: createNewCode = true;
110: current = new LZWNode();
111: previous.setNode(curBuffer[i], current);
112: }
113: }
114: if (createNewCode) {
115: long code = nextCode++;
116: current.setCode(code);
117: codeToData.put(new Long(code), curBuffer);
118:
119: /**
120: System.out.print( "Adding " + code + "='" );
121: for( int i=0; i<curBuffer.length; i++ )
122: {
123: String hex = Integer.toHexString( ((curBuffer[i]+256)%256) );
124: if( hex.length() <=1 )
125: {
126: hex = "0" + hex;
127: }
128: if( i != curBuffer.length -1 )
129: {
130: hex += " ";
131: }
132: System.out.print( hex.toUpperCase() );
133: }
134: System.out.println( "'" );
135: **/
136: buffer.reset();
137: buffer.write(data);
138: resetCodeSize();
139: }
140: }
141:
142: /**
143: * This will get the next code that will be created.
144: *
145: * @return The next code to be created.
146: */
147: public long getNextCode() {
148: return nextCode;
149: }
150:
151: /**
152: * This will get the size of the code in bits, 9, 10, or 11.
153: *
154: * @return The size of the code in bits.
155: */
156: public int getCodeSize() {
157: return codeSize;
158: }
159:
160: /**
161: * This will determine the code size.
162: */
163: private void resetCodeSize() {
164: if (nextCode >= 2048) {
165: codeSize = 12;
166: } else if (nextCode >= 1024) {
167: codeSize = 11;
168: } else if (nextCode >= 512) {
169: codeSize = 10;
170: } else {
171: codeSize = 9;
172: }
173: }
174:
175: /**
176: * This will crear the internal buffer that the dictionary uses.
177: */
178: public void clear() {
179: buffer.reset();
180: }
181:
182: /**
183: * This will folow the path to the data node.
184: *
185: * @param data The path to the node.
186: *
187: * @return The node that resides at that path.
188: */
189: public LZWNode getNode(byte[] data) {
190: return root.getNode(data);
191: }
192: }
|