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