root/dwt/internal/image/PngLzBlockReader.d

Revision 2:57151e2793a2, 5.6 kB (checked in by Frank Benoit <benoit@tionex.de>, 1 year ago)

More common modules from dwt-linux

Line 
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 dwt.internal.image.PngLzBlockReader;
14
15 import dwt.internal.image.PngDecodingDataStream;
16 import dwt.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 }
Note: See TracBrowser for help on using the browser.