KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > internal > image > PngLzBlockReader


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.internal.image;
12
13 import java.io.*;
14
15 public class PngLzBlockReader {
16     boolean isLastBlock;
17     byte compressionType;
18     int uncompressedBytesRemaining;
19     PngDecodingDataStream stream;
20     PngHuffmanTables huffmanTables;
21     
22     byte[] window;
23     int windowIndex;
24     int copyIndex;
25     int copyBytesRemaining;
26     
27     static final int UNCOMPRESSED = 0;
28     static final int COMPRESSED_FIXED = 1;
29     static final int COMPRESSED_DYNAMIC = 2;
30
31     static final int END_OF_COMPRESSED_BLOCK = 256;
32     static final int FIRST_LENGTH_CODE = 257;
33     static final int LAST_LENGTH_CODE = 285;
34     static final int FIRST_DISTANCE_CODE = 1;
35     static final int LAST_DISTANCE_CODE = 29;
36     static final int FIRST_CODE_LENGTH_CODE = 4;
37     static final int LAST_CODE_LENGTH_CODE = 19;
38
39     static final int[] lengthBases = {
40         3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27,
41         31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
42     } ;
43     static final int[] extraLengthBits = {
44         0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
45         3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0,
46     };
47     static final int[] distanceBases = {
48         1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129,
49         193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097,
50         6145, 8193, 12289, 16385, 24577,
51     };
52     static final int[] extraDistanceBits = {
53         0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
54         8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
55     };
56
57
58 PngLzBlockReader(PngDecodingDataStream stream) {
59     this.stream = stream;
60     isLastBlock = false;
61 }
62
63 void setWindowSize(int windowSize) {
64     window = new byte[windowSize];
65 }
66
67 void readNextBlockHeader() throws IOException {
68     isLastBlock = stream.getNextIdatBit() != 0;
69     compressionType = (byte)(stream.getNextIdatBits(2) & 0xFF);
70     if (compressionType > 2) stream.error();
71     
72     if (compressionType == UNCOMPRESSED) {
73         byte b1 = stream.getNextIdatByte();
74         byte b2 = stream.getNextIdatByte();
75         byte b3 = stream.getNextIdatByte();
76         byte b4 = stream.getNextIdatByte();
77         if (b1 != ~b3 || b2 != ~b4) stream.error();
78         uncompressedBytesRemaining = (b1 & 0xFF) | ((b2 & 0xFF) << 8);
79     } else if (compressionType == COMPRESSED_DYNAMIC) {
80         huffmanTables = PngHuffmanTables.getDynamicTables(stream);
81     } else {
82         huffmanTables = PngHuffmanTables.getFixedTables();
83     }
84 }
85
86 byte getNextByte() throws IOException {
87     if (compressionType == UNCOMPRESSED) {
88         if (uncompressedBytesRemaining == 0) {
89             readNextBlockHeader();
90             return getNextByte();
91         }
92         uncompressedBytesRemaining--;
93         return stream.getNextIdatByte();
94     } else {
95         byte value = getNextCompressedByte();
96         if (value == END_OF_COMPRESSED_BLOCK) {
97             if (isLastBlock) stream.error();
98             readNextBlockHeader();
99             return getNextByte();
100         } else {
101             return value;
102         }
103     }
104 }
105
106 private void assertBlockAtEnd() throws IOException {
107     if (compressionType == UNCOMPRESSED) {
108         if (uncompressedBytesRemaining > 0) stream.error();
109     } else if (copyBytesRemaining > 0 ||
110         (huffmanTables.getNextLiteralValue(stream) != END_OF_COMPRESSED_BLOCK))
111     {
112         stream.error();
113     }
114 }
115 void assertCompressedDataAtEnd() throws IOException {
116     assertBlockAtEnd();
117     while (!isLastBlock) {
118         readNextBlockHeader();
119         assertBlockAtEnd();
120     }
121 }
122
123 private byte getNextCompressedByte() throws IOException {
124     if (copyBytesRemaining > 0) {
125         byte value = window[copyIndex];
126         window[windowIndex] = value;
127         copyBytesRemaining--;
128         
129         copyIndex++;
130         windowIndex++;
131         if (copyIndex == window.length) copyIndex = 0;
132         if (windowIndex == window.length) windowIndex = 0;
133
134         return value;
135     }
136     
137     int value = huffmanTables.getNextLiteralValue(stream);
138     if (value < END_OF_COMPRESSED_BLOCK) {
139         window[windowIndex] = (byte) (value & 0xFF);
140         windowIndex++;
141         if (windowIndex >= window.length) windowIndex = 0;
142         return (byte) (value & 0xFF);
143     } else if (value == END_OF_COMPRESSED_BLOCK) {
144         readNextBlockHeader();
145         return getNextByte();
146     } else if (value <= LAST_LENGTH_CODE) {
147         int extraBits = extraLengthBits[value - FIRST_LENGTH_CODE];
148         int length = lengthBases[value - FIRST_LENGTH_CODE];
149         if (extraBits > 0) {
150             length += stream.getNextIdatBits(extraBits);
151         }
152         
153         value = huffmanTables.getNextDistanceValue(stream);
154         if (value > LAST_DISTANCE_CODE) stream.error();
155         extraBits = extraDistanceBits[value];
156         int distance = distanceBases[value];
157         if (extraBits > 0) {
158             distance += stream.getNextIdatBits(extraBits);
159         }
160         
161         copyIndex = windowIndex - distance;
162         if (copyIndex < 0) copyIndex += window.length;
163
164         copyBytesRemaining = length;
165         return getNextCompressedByte();
166     } else {
167         stream.error();
168         return 0;
169     }
170 }
171     
172 }
173
Popular Tags