Mercurial > projects > dwt-mac
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 } |