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 }