Mercurial > projects > dwt-mac
comparison dwt/internal/image/PngDeflater.d @ 34:5123b17c98ef
Ported dwt.events.*, dwt.graphics.GC, Region, dwt.internal.image.*
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sun, 14 Sep 2008 01:45:57 +0200 |
parents | e831403a80a9 |
children |
comparison
equal
deleted
inserted
replaced
33:965ac0a77267 | 34:5123b17c98ef |
---|---|
1 /******************************************************************************* | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2006 IBM Corporation and others. | 2 * Copyright (c) 2000, 2008 IBM Corporation and others. |
3 * All rights reserved. This program and the accompanying materials | 3 * All rights reserved. This program and the accompanying materials |
4 * are made available under the terms of the Eclipse Public License v1.0 | 4 * are made available under the terms of the Eclipse Public License v1.0 |
5 * which accompanies this distribution, and is available at | 5 * which accompanies this distribution, and is available at |
6 * http://www.eclipse.org/legal/epl-v10.html | 6 * http://www.eclipse.org/legal/epl-v10.html |
7 * | 7 * |
8 * Contributors: | 8 * Contributors: |
9 * IBM Corporation - initial API and implementation | 9 * IBM Corporation - initial API and implementation |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
10 *******************************************************************************/ | 12 *******************************************************************************/ |
11 module dwt.internal.image; | 13 module dwt.internal.image.PngDeflater; |
12 | 14 |
13 import java.io.ByteArrayOutputStream; | 15 import dwt.dwthelper.ByteArrayOutputStream; |
14 | 16 |
15 public class PngDeflater { | 17 public class PngDeflater { |
16 | 18 |
17 static final int BASE = 65521; | 19 static const int BASE = 65521; |
18 static final int WINDOW = 32768; | 20 static const int WINDOW = 32768; |
19 static final int MIN_LENGTH = 3; | 21 static const int MIN_LENGTH = 3; |
20 static final int MAX_MATCHES = 32; | 22 static const int MAX_MATCHES = 32; |
21 static final int HASH = 8209; | 23 static const int HASH = 8209; |
22 | 24 |
23 byte[] in; | 25 byte[] istr; |
24 int inLength; | 26 int inLength; |
25 | 27 |
26 ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024); | 28 ByteArrayOutputStream bytes; |
27 | 29 |
28 int adler32 = 1; | 30 int adler32 = 1; |
29 | 31 |
30 int buffer, bitCount; | 32 int buffer, bitCount; |
31 | 33 |
32 Link[] hashtable = new Link[HASH]; | 34 Link[HASH] hashtable;// = new Link[HASH]; |
33 Link[] window = new Link[WINDOW]; | 35 Link[WINDOW] window;// = new Link[WINDOW]; |
34 int nextWindow; | 36 int nextWindow; |
35 | 37 |
36 static class Link { | 38 public this(){ |
39 bytes = new ByteArrayOutputStream(1024); | |
40 } | |
41 | |
42 class Link { | |
37 | 43 |
38 int hash, value; | 44 int hash, value; |
39 Link previous, next; | 45 Link previous, next; |
40 | 46 |
41 this() { | 47 this() { |
42 | 48 |
43 this.hash = 0; | 49 this.hash = 0; |
44 this.value = 0; | 50 this.value = 0; |
45 this.previous = null; | 51 this.previous = null; |
46 this.next = null; | 52 this.next = null; |
47 | 53 |
48 } | 54 } |
49 | 55 |
50 } | 56 } |
51 | 57 |
52 static class Match { | 58 static class Match { |
53 | 59 |
54 int length, distance; | 60 int length, distance; |
55 | 61 |
56 this(int length, int distance) { | 62 this(int length, int distance) { |
57 | 63 |
58 this.length = length; | 64 this.length = length; |
59 this.distance = distance; | 65 this.distance = distance; |
60 | 66 |
61 } | 67 } |
62 | 68 |
63 } | 69 } |
64 | 70 |
65 static final short mirrorBytes[] = { | 71 static const short mirrorBytes[] = [ cast(short) |
66 | 72 |
67 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, | 73 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, |
68 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, | 74 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, |
69 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, | 75 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, |
70 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, | 76 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, |
95 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, | 101 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, |
96 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, | 102 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, |
97 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, | 103 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, |
98 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, | 104 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, |
99 | 105 |
100 }; | 106 ]; |
101 | 107 |
102 static class Code { | 108 static class Code { |
103 | 109 |
104 int code, extraBits, min, max; | 110 int code, extraBits, min, max; |
105 | 111 |
106 this(int code, int extraBits, int min, int max) { | 112 this(int code, int extraBits, int min, int max) { |
107 | 113 |
108 this.code = code; | 114 this.code = code; |
109 this.extraBits = extraBits; | 115 this.extraBits = extraBits; |
110 this.min = min; | 116 this.min = min; |
111 this.max = max; | 117 this.max = max; |
112 | 118 |
113 } | 119 } |
114 | 120 |
115 } | 121 } |
116 | 122 |
117 static final Code lengthCodes[] = { | 123 static const Code lengthCodes[]; |
118 | 124 static const Code distanceCodes[]; |
119 new Code(257, 0, 3, 3), | 125 |
120 new Code(258, 0, 4, 4), | 126 static this() { |
121 new Code(259, 0, 5, 5), | 127 lengthCodes = [ |
122 new Code(260, 0, 6, 6), | 128 new Code(257, 0, 3, 3), |
123 new Code(261, 0, 7, 7), | 129 new Code(258, 0, 4, 4), |
124 new Code(262, 0, 8, 8), | 130 new Code(259, 0, 5, 5), |
125 new Code(263, 0, 9, 9), | 131 new Code(260, 0, 6, 6), |
126 new Code(264, 0, 10, 10), | 132 new Code(261, 0, 7, 7), |
127 new Code(265, 1, 11, 12), | 133 new Code(262, 0, 8, 8), |
128 new Code(266, 1, 13, 14), | 134 new Code(263, 0, 9, 9), |
129 new Code(267, 1, 15, 16), | 135 new Code(264, 0, 10, 10), |
130 new Code(268, 1, 17, 18), | 136 new Code(265, 1, 11, 12), |
131 new Code(269, 2, 19, 22), | 137 new Code(266, 1, 13, 14), |
132 new Code(270, 2, 23, 26), | 138 new Code(267, 1, 15, 16), |
133 new Code(271, 2, 27, 30), | 139 new Code(268, 1, 17, 18), |
134 new Code(272, 2, 31, 34), | 140 new Code(269, 2, 19, 22), |
135 new Code(273, 3, 35, 42), | 141 new Code(270, 2, 23, 26), |
136 new Code(274, 3, 43, 50), | 142 new Code(271, 2, 27, 30), |
137 new Code(275, 3, 51, 58), | 143 new Code(272, 2, 31, 34), |
138 new Code(276, 3, 59, 66), | 144 new Code(273, 3, 35, 42), |
139 new Code(277, 4, 67, 82), | 145 new Code(274, 3, 43, 50), |
140 new Code(278, 4, 83, 98), | 146 new Code(275, 3, 51, 58), |
141 new Code(279, 4, 99, 114), | 147 new Code(276, 3, 59, 66), |
142 new Code(280, 4, 115, 130), | 148 new Code(277, 4, 67, 82), |
143 new Code(281, 5, 131, 162), | 149 new Code(278, 4, 83, 98), |
144 new Code(282, 5, 163, 194), | 150 new Code(279, 4, 99, 114), |
145 new Code(283, 5, 195, 226), | 151 new Code(280, 4, 115, 130), |
146 new Code(284, 5, 227, 257), | 152 new Code(281, 5, 131, 162), |
147 new Code(285, 0, 258, 258) | 153 new Code(282, 5, 163, 194), |
148 | 154 new Code(283, 5, 195, 226), |
149 }; | 155 new Code(284, 5, 227, 257), |
150 | 156 new Code(285, 0, 258, 258)]; |
151 static final Code distanceCodes[] = { | 157 |
152 | 158 distanceCodes = [ |
153 new Code(0, 0, 1, 1), | 159 new Code(0, 0, 1, 1), |
154 new Code(1, 0, 2, 2), | 160 new Code(1, 0, 2, 2), |
155 new Code(2, 0, 3, 3), | 161 new Code(2, 0, 3, 3), |
156 new Code(3, 0, 4, 4), | 162 new Code(3, 0, 4, 4), |
157 new Code(4, 1, 5, 6), | 163 new Code(4, 1, 5, 6), |
158 new Code(5, 1, 7, 8), | 164 new Code(5, 1, 7, 8), |
159 new Code(6, 2, 9, 12), | 165 new Code(6, 2, 9, 12), |
160 new Code(7, 2, 13, 16), | 166 new Code(7, 2, 13, 16), |
161 new Code(8, 3, 17, 24), | 167 new Code(8, 3, 17, 24), |
162 new Code(9, 3, 25, 32), | 168 new Code(9, 3, 25, 32), |
163 new Code(10, 4, 33, 48), | 169 new Code(10, 4, 33, 48), |
164 new Code(11, 4, 49, 64), | 170 new Code(11, 4, 49, 64), |
165 new Code(12, 5, 65, 96), | 171 new Code(12, 5, 65, 96), |
166 new Code(13, 5, 97, 128), | 172 new Code(13, 5, 97, 128), |
167 new Code(14, 6, 129, 192), | 173 new Code(14, 6, 129, 192), |
168 new Code(15, 6, 193, 256), | 174 new Code(15, 6, 193, 256), |
169 new Code(16, 7, 257, 384), | 175 new Code(16, 7, 257, 384), |
170 new Code(17, 7, 385, 512), | 176 new Code(17, 7, 385, 512), |
171 new Code(18, 8, 513, 768), | 177 new Code(18, 8, 513, 768), |
172 new Code(19, 8, 769, 1024), | 178 new Code(19, 8, 769, 1024), |
173 new Code(20, 9, 1025, 1536), | 179 new Code(20, 9, 1025, 1536), |
174 new Code(21, 9, 1537, 2048), | 180 new Code(21, 9, 1537, 2048), |
175 new Code(22, 10, 2049, 3072), | 181 new Code(22, 10, 2049, 3072), |
176 new Code(23, 10, 3073, 4096), | 182 new Code(23, 10, 3073, 4096), |
177 new Code(24, 11, 4097, 6144), | 183 new Code(24, 11, 4097, 6144), |
178 new Code(25, 11, 6145, 8192), | 184 new Code(25, 11, 6145, 8192), |
179 new Code(26, 12, 8193, 12288), | 185 new Code(26, 12, 8193, 12288), |
180 new Code(27, 12, 12289, 16384), | 186 new Code(27, 12, 12289, 16384), |
181 new Code(28, 13, 16385, 24576), | 187 new Code(28, 13, 16385, 24576), |
182 new Code(29, 13, 24577, 32768) | 188 new Code(29, 13, 24577, 32768)]; |
183 | 189 } |
184 }; | |
185 | 190 |
186 void writeShortLSB(ByteArrayOutputStream baos, int theShort) { | 191 void writeShortLSB(ByteArrayOutputStream baos, int theShort) { |
187 | 192 |
188 byte byte1 = cast(byte) (theShort & 0xff); | 193 byte byte1 = cast(byte) (theShort & 0xff); |
189 byte byte2 = cast(byte) ((theShort >> 8) & 0xff); | 194 byte byte2 = cast(byte) ((theShort >> 8) & 0xff); |
190 byte[] temp = {byte1, byte2}; | 195 byte[] temp = [byte1, byte2]; |
191 baos.write(temp, 0, 2); | 196 baos.write(temp, 0, 2); |
192 | 197 |
193 } | 198 } |
194 | 199 |
195 void writeInt(ByteArrayOutputStream baos, int theInt) { | 200 void writeInt(ByteArrayOutputStream baos, int theInt) { |
196 | 201 |
197 byte byte1 = cast(byte) ((theInt >> 24) & 0xff); | 202 byte byte1 = cast(byte) ((theInt >> 24) & 0xff); |
198 byte byte2 = cast(byte) ((theInt >> 16) & 0xff); | 203 byte byte2 = cast(byte) ((theInt >> 16) & 0xff); |
199 byte byte3 = cast(byte) ((theInt >> 8) & 0xff); | 204 byte byte3 = cast(byte) ((theInt >> 8) & 0xff); |
200 byte byte4 = cast(byte) (theInt & 0xff); | 205 byte byte4 = cast(byte) (theInt & 0xff); |
201 byte[] temp = {byte1, byte2, byte3, byte4}; | 206 byte[] temp = [byte1, byte2, byte3, byte4]; |
202 baos.write(temp, 0, 4); | 207 baos.write(temp, 0, 4); |
203 | 208 |
204 } | 209 } |
205 | 210 |
206 void updateAdler(byte value) { | 211 void updateAdler(byte value) { |
249 } | 254 } |
250 | 255 |
251 void outputLiteral(byte literal) { | 256 void outputLiteral(byte literal) { |
252 | 257 |
253 int i = literal & 0xff; | 258 int i = literal & 0xff; |
254 | 259 |
255 if (i <= 143) { | 260 if (i <= 143) { |
256 // 0 through 143 are 8 bits long starting at 00110000 | 261 // 0 through 143 are 8 bits long starting at 00110000 |
257 writeBits(mirrorBytes[0x30 + i], 8); | 262 writeBits(mirrorBytes[0x30 + i], 8); |
258 } | 263 } |
259 else { | 264 else { |
264 } | 269 } |
265 | 270 |
266 Code findCode(int value, Code[] codes) { | 271 Code findCode(int value, Code[] codes) { |
267 | 272 |
268 int i, j, k; | 273 int i, j, k; |
269 | 274 |
270 i = -1; | 275 i = -1; |
271 j = codes.length; | 276 j = codes.length; |
272 while (true) { | 277 while (true) { |
273 k = (j + i) / 2; | 278 k = (j + i) / 2; |
274 if (value < codes[k].min) { | 279 if (value < codes[k].min) { |
286 | 291 |
287 void outputMatch(int length, int distance) { | 292 void outputMatch(int length, int distance) { |
288 | 293 |
289 Code d, l; | 294 Code d, l; |
290 int thisLength; | 295 int thisLength; |
291 | 296 |
292 while (length > 0) { | 297 while (length > 0) { |
293 | 298 |
294 // we can transmit matches of lengths 3 through 258 inclusive | 299 // we can transmit matches of lengths 3 through 258 inclusive |
295 // so if length exceeds 258, we must transmit in several steps, | 300 // so if length exceeds 258, we must transmit in several steps, |
296 // with 258 or less in each step | 301 // with 258 or less in each step |
297 | 302 |
298 if (length > 260) { | 303 if (length > 260) { |
299 thisLength = 258; | 304 thisLength = 258; |
300 } | 305 } |
301 else if (length <= 258) { | 306 else if (length <= 258) { |
302 thisLength = length; | 307 thisLength = length; |
303 } | 308 } |
304 else { | 309 else { |
305 thisLength = length - 3; | 310 thisLength = length - 3; |
306 } | 311 } |
307 | 312 |
308 length = length - thisLength; | 313 length = length - thisLength; |
309 | 314 |
310 // find length code | 315 // find length code |
311 l = findCode(thisLength, lengthCodes); | 316 l = findCode(thisLength, lengthCodes); |
312 | 317 |
313 // transmit the length code | 318 // transmit the length code |
314 // 256 through 279 are 7 bits long starting at 0000000 | 319 // 256 through 279 are 7 bits long starting at 0000000 |
315 // 280 through 287 are 8 bits long starting at 11000000 | 320 // 280 through 287 are 8 bits long starting at 11000000 |
316 if (l.code <= 279) { | 321 if (l.code <= 279) { |
317 writeBits(mirrorBytes[(l.code - 256) * 2], 7); | 322 writeBits(mirrorBytes[(l.code - 256) * 2], 7); |
318 } | 323 } |
319 else { | 324 else { |
320 writeBits(mirrorBytes[0xc0 - 280 + l.code], 8); | 325 writeBits(mirrorBytes[0xc0 - 280 + l.code], 8); |
321 } | 326 } |
322 | 327 |
323 // transmit the extra bits | 328 // transmit the extra bits |
324 if (l.extraBits !is 0) { | 329 if (l.extraBits !is 0) { |
325 writeBits(thisLength - l.min, l.extraBits); | 330 writeBits(thisLength - l.min, l.extraBits); |
326 } | 331 } |
327 | 332 |
328 // find distance code | 333 // find distance code |
329 d = findCode(distance, distanceCodes); | 334 d = findCode(distance, distanceCodes); |
330 | 335 |
331 // transmit the distance code | 336 // transmit the distance code |
332 // 5 bits long starting at 00000 | 337 // 5 bits long starting at 00000 |
333 writeBits(mirrorBytes[d.code * 8], 5); | 338 writeBits(mirrorBytes[d.code * 8], 5); |
334 | 339 |
335 // transmit the extra bits | 340 // transmit the extra bits |
336 if (d.extraBits !is 0) { | 341 if (d.extraBits !is 0) { |
337 writeBits(distance - d.min, d.extraBits); | 342 writeBits(distance - d.min, d.extraBits); |
338 } | 343 } |
339 | 344 |
340 } | 345 } |
341 | 346 |
342 } | 347 } |
343 | 348 |
344 Match findLongestMatch(int position, Link firstPosition) { | 349 Match findLongestMatch(int position, Link firstPosition) { |
345 | 350 |
346 Link link = firstPosition; | 351 Link link = firstPosition; |
347 int numberOfMatches = 0; | 352 int numberOfMatches = 0; |
348 Match bestMatch = new Match(-1, -1); | 353 Match bestMatch = new Match(-1, -1); |
349 | 354 |
350 while (true) { | 355 while (true) { |
351 | 356 |
352 int matchPosition = link.value; | 357 int matchPosition = link.value; |
353 | 358 |
354 if (position - matchPosition < WINDOW && matchPosition !is 0) { | 359 if (position - matchPosition < WINDOW && matchPosition !is 0) { |
355 | 360 |
356 int i; | 361 int i; |
357 | 362 |
358 for (i = 1; position + i < inLength; i++) { | 363 for (i = 1; position + i < inLength; i++) { |
359 if (in[position + i] !is in[matchPosition + i]) { | 364 if (istr[position + i] !is istr[matchPosition + i]) { |
360 break; | 365 break; |
361 } | 366 } |
362 } | 367 } |
363 | 368 |
364 if (i >= MIN_LENGTH) { | 369 if (i >= MIN_LENGTH) { |
365 | 370 |
366 if (i > bestMatch.length) { | 371 if (i > bestMatch.length) { |
367 bestMatch.length = i; | 372 bestMatch.length = i; |
368 bestMatch.distance = position - matchPosition; | 373 bestMatch.distance = position - matchPosition; |
369 } | 374 } |
370 | 375 |
371 numberOfMatches = numberOfMatches + 1; | 376 numberOfMatches = numberOfMatches + 1; |
372 | 377 |
373 if (numberOfMatches is MAX_MATCHES) { | 378 if (numberOfMatches is MAX_MATCHES) { |
374 break; | 379 break; |
375 } | 380 } |
376 | 381 |
377 } | 382 } |
378 | 383 |
379 } | 384 } |
380 | 385 |
381 link = link.next; | 386 link = link.next; |
382 if (link is null) { | 387 if (link is null) { |
383 break; | 388 break; |
384 } | 389 } |
385 | 390 |
386 } | 391 } |
387 | 392 |
388 if (bestMatch.length < MIN_LENGTH || bestMatch.distance < 1 || bestMatch.distance > WINDOW) { | 393 if (bestMatch.length < MIN_LENGTH || bestMatch.distance < 1 || bestMatch.distance > WINDOW) { |
389 return null; | 394 return null; |
390 } | 395 } |
391 | 396 |
392 return bestMatch; | 397 return bestMatch; |
393 | 398 |
394 } | 399 } |
395 | 400 |
396 void updateHashtable(int to, int from) { | 401 void updateHashtable(int to, int from) { |
397 | 402 |
398 byte[] data = new byte[3]; | 403 byte[] data = new byte[3]; |
399 int hash; | 404 int hashval; |
400 Link temp; | 405 Link temp; |
401 | 406 |
402 for (int i = to; i < from; i++) { | 407 for (int i = to; i < from; i++) { |
403 | 408 |
404 if (i + MIN_LENGTH > inLength) { | 409 if (i + MIN_LENGTH > inLength) { |
405 break; | 410 break; |
406 } | 411 } |
407 | 412 |
408 data[0] = in[i]; | 413 data[0] = istr[i]; |
409 data[1] = in[i + 1]; | 414 data[1] = istr[i + 1]; |
410 data[2] = in[i + 2]; | 415 data[2] = istr[i + 2]; |
411 | 416 |
412 hash = hash(data); | 417 hashval = hash(data); |
413 | 418 |
414 if (window[nextWindow].previous !is null) { | 419 if (window[nextWindow].previous !is null) { |
415 window[nextWindow].previous.next = null; | 420 window[nextWindow].previous.next = null; |
416 } | 421 } |
417 else if (window[nextWindow].hash !is 0) { | 422 else if (window[nextWindow].hash !is 0) { |
418 hashtable[window[nextWindow].hash].next = null; | 423 hashtable[window[nextWindow].hash].next = null; |
419 } | 424 } |
420 | 425 |
421 window[nextWindow].hash = hash; | 426 window[nextWindow].hash = hashval; |
422 window[nextWindow].value = i; | 427 window[nextWindow].value = i; |
423 window[nextWindow].previous = null; | 428 window[nextWindow].previous = null; |
424 temp = window[nextWindow].next = hashtable[hash].next; | 429 temp = window[nextWindow].next = hashtable[hashval].next; |
425 hashtable[hash].next = window[nextWindow]; | 430 hashtable[hashval].next = window[nextWindow]; |
426 if (temp !is null) { | 431 if (temp !is null) { |
427 temp.previous = window[nextWindow]; | 432 temp.previous = window[nextWindow]; |
428 } | 433 } |
429 | 434 |
430 nextWindow = nextWindow + 1; | 435 nextWindow = nextWindow + 1; |
431 if (nextWindow is WINDOW) { | 436 if (nextWindow is WINDOW) { |
432 nextWindow = 0; | 437 nextWindow = 0; |
433 } | 438 } |
434 | 439 |
435 } | 440 } |
436 | 441 |
437 } | 442 } |
438 | 443 |
439 void compress() { | 444 void compress() { |
440 | 445 |
441 int position, newPosition; | 446 int position, newPosition; |
442 byte[] data = new byte[3]; | 447 byte[] data = new byte[3]; |
443 int hash; | 448 int hashval; |
444 for (int i = 0; i < HASH; i++) { | 449 for (int i = 0; i < HASH; i++) { |
445 hashtable[i] = new Link(); | 450 hashtable[i] = new Link(); |
446 } | 451 } |
447 for (int i = 0; i < WINDOW; i++) { | 452 for (int i = 0; i < WINDOW; i++) { |
448 window[i] = new Link(); | 453 window[i] = new Link(); |
450 nextWindow = 0; | 455 nextWindow = 0; |
451 Link firstPosition; | 456 Link firstPosition; |
452 Match match; | 457 Match match; |
453 int deferredPosition = -1; | 458 int deferredPosition = -1; |
454 Match deferredMatch = null; | 459 Match deferredMatch = null; |
455 | 460 |
456 writeBits(0x01, 1); // BFINAL = 0x01 (final block) | 461 writeBits(0x01, 1); // BFINAL = 0x01 (final block) |
457 writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes) | 462 writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes) |
458 | 463 |
459 // just output first byte so we never match at zero | 464 // just output first byte so we never match at zero |
460 outputLiteral(in[0]); | 465 outputLiteral(istr[0]); |
461 position = 1; | 466 position = 1; |
462 | 467 |
463 while (position < inLength) { | 468 while (position < inLength) { |
464 | 469 |
465 if (inLength - position < MIN_LENGTH) { | 470 if (inLength - position < MIN_LENGTH) { |
466 outputLiteral(in[position]); | 471 outputLiteral(istr[position]); |
467 position = position + 1; | 472 position = position + 1; |
468 continue; | 473 continue; |
469 } | 474 } |
470 | 475 |
471 data[0] = in[position]; | 476 data[0] = istr[position]; |
472 data[1] = in[position + 1]; | 477 data[1] = istr[position + 1]; |
473 data[2] = in[position + 2]; | 478 data[2] = istr[position + 2]; |
474 | 479 |
475 hash = hash(data); | 480 hashval = hash(data); |
476 firstPosition = hashtable[hash]; | 481 firstPosition = hashtable[hashval]; |
477 | 482 |
478 match = findLongestMatch(position, firstPosition); | 483 match = findLongestMatch(position, firstPosition); |
479 | 484 |
480 updateHashtable(position, position + 1); | 485 updateHashtable(position, position + 1); |
481 | 486 |
482 if (match !is null) { | 487 if (match !is null) { |
483 | 488 |
484 if (deferredMatch !is null) { | 489 if (deferredMatch !is null) { |
485 if (match.length > deferredMatch.length + 1) { | 490 if (match.length > deferredMatch.length + 1) { |
486 // output literal at deferredPosition | 491 // output literal at deferredPosition |
487 outputLiteral(in[deferredPosition]); | 492 outputLiteral(istr[deferredPosition]); |
488 // defer this match | 493 // defer this match |
489 deferredPosition = position; | 494 deferredPosition = position; |
490 deferredMatch = match; | 495 deferredMatch = match; |
491 position = position + 1; | 496 position = position + 1; |
492 } | 497 } |
504 // defer this match | 509 // defer this match |
505 deferredPosition = position; | 510 deferredPosition = position; |
506 deferredMatch = match; | 511 deferredMatch = match; |
507 position = position + 1; | 512 position = position + 1; |
508 } | 513 } |
509 | 514 |
510 } | 515 } |
511 | 516 |
512 else { | 517 else { |
513 | 518 |
514 // no match found | 519 // no match found |
515 if (deferredMatch !is null) { | 520 if (deferredMatch !is null) { |
516 outputMatch(deferredMatch.length, deferredMatch.distance); | 521 outputMatch(deferredMatch.length, deferredMatch.distance); |
517 newPosition = deferredPosition + deferredMatch.length; | 522 newPosition = deferredPosition + deferredMatch.length; |
518 deferredPosition = -1; | 523 deferredPosition = -1; |
519 deferredMatch = null; | 524 deferredMatch = null; |
520 updateHashtable(position + 1, newPosition); | 525 updateHashtable(position + 1, newPosition); |
521 position = newPosition; | 526 position = newPosition; |
522 } | 527 } |
523 else { | 528 else { |
524 outputLiteral(in[position]); | 529 outputLiteral(istr[position]); |
525 position = position + 1; | 530 position = position + 1; |
526 } | 531 } |
527 | 532 |
528 } | 533 } |
529 | 534 |
530 } | 535 } |
531 | 536 |
532 writeBits(0, 7); // end of block code | 537 writeBits(0, 7); // end of block code |
533 alignToByte(); | 538 alignToByte(); |
534 | 539 |
535 } | 540 } |
536 | 541 |
537 void compressHuffmanOnly() { | 542 void compressHuffmanOnly() { |
538 | 543 |
539 int position; | 544 int position; |
540 | 545 |
541 writeBits(0x01, 1); // BFINAL = 0x01 (final block) | 546 writeBits(0x01, 1); // BFINAL = 0x01 (final block) |
542 writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes) | 547 writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes) |
543 | 548 |
544 for (position = 0; position < inLength;) { | 549 for (position = 0; position < inLength;) { |
545 | 550 |
546 outputLiteral(in[position]); | 551 outputLiteral(istr[position]); |
547 position = position + 1; | 552 position = position + 1; |
548 | 553 |
549 } | 554 } |
550 | 555 |
551 writeBits(0, 7); // end of block code | 556 writeBits(0, 7); // end of block code |
552 alignToByte(); | 557 alignToByte(); |
553 | 558 |
554 } | 559 } |
555 | 560 |
556 void store() { | 561 void store() { |
557 | 562 |
558 // stored blocks are limited to 0xffff bytes | 563 // stored blocks are limited to 0xffff bytes |
559 | 564 |
560 int start = 0; | 565 int start = 0; |
561 int length = inLength; | 566 int length = inLength; |
562 int blockLength; | 567 int blockLength; |
563 int BFINAL = 0x00; // BFINAL = 0x00 or 0x01 (if final block), BTYPE = 0x00 (no compression) | 568 int BFINAL = 0x00; // BFINAL = 0x00 or 0x01 (if final block), BTYPE = 0x00 (no compression) |
564 | 569 |
565 while (length > 0) { | 570 while (length > 0) { |
566 | 571 |
567 if (length < 65535) { | 572 if (length < 65535) { |
568 blockLength = length; | 573 blockLength = length; |
569 BFINAL = 0x01; | 574 BFINAL = 0x01; |
570 } | 575 } |
571 else { | 576 else { |
572 blockLength = 65535; | 577 blockLength = 65535; |
573 BFINAL = 0x00; | 578 BFINAL = 0x00; |
574 } | 579 } |
575 | 580 |
576 // write data header | 581 // write data header |
577 bytes.write(cast(byte) BFINAL); | 582 bytes.write(cast(byte) BFINAL); |
578 writeShortLSB(bytes, blockLength); // LEN | 583 writeShortLSB(bytes, blockLength); // LEN |
579 writeShortLSB(bytes, blockLength ^ 0xffff); // NLEN (one's complement of LEN) | 584 writeShortLSB(bytes, blockLength ^ 0xffff); // NLEN (one's complement of LEN) |
580 | 585 |
581 // write actual data | 586 // write actual data |
582 bytes.write(in, start, blockLength); | 587 bytes.write(istr, start, blockLength); |
583 | 588 |
584 length = length - blockLength; | 589 length = length - blockLength; |
585 start = start + blockLength; | 590 start = start + blockLength; |
586 | 591 |
587 } | 592 } |
588 | 593 |
589 } | 594 } |
590 | 595 |
591 public byte[] deflate(byte[] input) { | 596 public byte[] deflate(byte[] input) { |
592 | 597 |
593 in = input; | 598 istr = input; |
594 inLength = input.length; | 599 inLength = input.length; |
595 | 600 |
596 // write zlib header | 601 // write zlib header |
597 bytes.write(cast(byte) 0x78); // window size = 0x70 (32768), compression method = 0x08 | 602 bytes.write(cast(byte) 0x78); // window size = 0x70 (32768), compression method = 0x08 |
598 bytes.write(cast(byte) 0x9C); // compression level = 0x80 (default), check bits = 0x1C | 603 bytes.write(cast(byte) 0x9C); // compression level = 0x80 (default), check bits = 0x1C |
599 | 604 |
600 // compute checksum | 605 // compute checksum |
601 for (int i = 0; i < inLength; i++) { | 606 for (int i = 0; i < inLength; i++) { |
602 updateAdler(in[i]); | 607 updateAdler(istr[i]); |
603 } | 608 } |
604 | 609 |
605 //store(); | 610 //store(); |
606 | 611 |
607 //compressHuffmanOnly(); | 612 //compressHuffmanOnly(); |
608 | 613 |
609 compress(); | 614 compress(); |
610 | 615 |
611 // write checksum | 616 // write checksum |
612 writeInt(bytes, adler32); | 617 writeInt(bytes, adler32); |
613 | 618 |
614 return bytes.toByteArray(); | 619 return bytes.toByteArray(); |
615 | 620 |
616 } | 621 } |
617 | 622 |
618 } | 623 } |