comparison dwt/internal/image/PngLzBlockReader.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 1a8b3cb347e0
comparison
equal deleted inserted replaced
-1:000000000000 0:380af2bdd8e5
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 module dwt.internal.image;
12
13 import java.io.IOException;
14
15 public class PngLzBlockReader {
16 bool 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() !is 0;
69 compressionType = (byte)(stream.getNextIdatBits(2) & 0xFF);
70 if (compressionType > 2) stream.error();
71
72 if (compressionType is UNCOMPRESSED) {
73 byte b1 = stream.getNextIdatByte();
74 byte b2 = stream.getNextIdatByte();
75 byte b3 = stream.getNextIdatByte();
76 byte b4 = stream.getNextIdatByte();
77 if (b1 !is ~b3 || b2 !is ~b4) stream.error();
78 uncompressedBytesRemaining = (b1 & 0xFF) | ((b2 & 0xFF) << 8);
79 } else if (compressionType is COMPRESSED_DYNAMIC) {
80 huffmanTables = PngHuffmanTables.getDynamicTables(stream);
81 } else {
82 huffmanTables = PngHuffmanTables.getFixedTables();
83 }
84 }
85
86 byte getNextByte() throws IOException {
87 if (compressionType is UNCOMPRESSED) {
88 if (uncompressedBytesRemaining is 0) {
89 readNextBlockHeader();
90 return getNextByte();
91 }
92 uncompressedBytesRemaining--;
93 return stream.getNextIdatByte();
94 } else {
95 byte value = getNextCompressedByte();
96 if (value is 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 is UNCOMPRESSED) {
108 if (uncompressedBytesRemaining > 0) stream.error();
109 } else if (copyBytesRemaining > 0 ||
110 (huffmanTables.getNextLiteralValue(stream) !is 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 is window.length) copyIndex = 0;
132 if (windowIndex is 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 is 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 }