1 11 package org.eclipse.swt.internal.image; 12 13 import java.io.ByteArrayOutputStream ; 14 15 public class PngDeflater { 16 17 static final int BASE = 65521; 18 static final int WINDOW = 32768; 19 static final int MIN_LENGTH = 3; 20 static final int MAX_MATCHES = 32; 21 static final int HASH = 8209; 22 23 byte[] in; 24 int inLength; 25 26 ByteArrayOutputStream bytes = new ByteArrayOutputStream (1024); 27 28 int adler32 = 1; 29 30 int buffer, bitCount; 31 32 Link[] hashtable = new Link[HASH]; 33 Link[] window = new Link[WINDOW]; 34 int nextWindow; 35 36 class Link { 37 38 int hash, value; 39 Link previous, next; 40 41 Link() { 42 43 this.hash = 0; 44 this.value = 0; 45 this.previous = null; 46 this.next = null; 47 48 } 49 50 } 51 52 class Match { 53 54 int length, distance; 55 56 Match(int length, int distance) { 57 58 this.length = length; 59 this.distance = distance; 60 61 } 62 63 } 64 65 static final short mirrorBytes[] = { 66 67 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 68 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 69 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 70 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 71 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 72 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 73 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 74 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 75 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 76 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 77 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 78 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 79 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 80 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 81 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 82 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 83 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 84 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 85 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 86 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 87 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 88 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 89 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 90 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 91 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 92 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 93 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 94 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 95 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 96 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 97 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 98 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, 99 100 }; 101 102 static class Code { 103 104 int code, extraBits, min, max; 105 106 Code(int code, int extraBits, int min, int max) { 107 108 this.code = code; 109 this.extraBits = extraBits; 110 this.min = min; 111 this.max = max; 112 113 } 114 115 } 116 117 static final Code lengthCodes[] = { 118 119 new Code(257, 0, 3, 3), 120 new Code(258, 0, 4, 4), 121 new Code(259, 0, 5, 5), 122 new Code(260, 0, 6, 6), 123 new Code(261, 0, 7, 7), 124 new Code(262, 0, 8, 8), 125 new Code(263, 0, 9, 9), 126 new Code(264, 0, 10, 10), 127 new Code(265, 1, 11, 12), 128 new Code(266, 1, 13, 14), 129 new Code(267, 1, 15, 16), 130 new Code(268, 1, 17, 18), 131 new Code(269, 2, 19, 22), 132 new Code(270, 2, 23, 26), 133 new Code(271, 2, 27, 30), 134 new Code(272, 2, 31, 34), 135 new Code(273, 3, 35, 42), 136 new Code(274, 3, 43, 50), 137 new Code(275, 3, 51, 58), 138 new Code(276, 3, 59, 66), 139 new Code(277, 4, 67, 82), 140 new Code(278, 4, 83, 98), 141 new Code(279, 4, 99, 114), 142 new Code(280, 4, 115, 130), 143 new Code(281, 5, 131, 162), 144 new Code(282, 5, 163, 194), 145 new Code(283, 5, 195, 226), 146 new Code(284, 5, 227, 257), 147 new Code(285, 0, 258, 258) 148 149 }; 150 151 static final Code distanceCodes[] = { 152 153 new Code(0, 0, 1, 1), 154 new Code(1, 0, 2, 2), 155 new Code(2, 0, 3, 3), 156 new Code(3, 0, 4, 4), 157 new Code(4, 1, 5, 6), 158 new Code(5, 1, 7, 8), 159 new Code(6, 2, 9, 12), 160 new Code(7, 2, 13, 16), 161 new Code(8, 3, 17, 24), 162 new Code(9, 3, 25, 32), 163 new Code(10, 4, 33, 48), 164 new Code(11, 4, 49, 64), 165 new Code(12, 5, 65, 96), 166 new Code(13, 5, 97, 128), 167 new Code(14, 6, 129, 192), 168 new Code(15, 6, 193, 256), 169 new Code(16, 7, 257, 384), 170 new Code(17, 7, 385, 512), 171 new Code(18, 8, 513, 768), 172 new Code(19, 8, 769, 1024), 173 new Code(20, 9, 1025, 1536), 174 new Code(21, 9, 1537, 2048), 175 new Code(22, 10, 2049, 3072), 176 new Code(23, 10, 3073, 4096), 177 new Code(24, 11, 4097, 6144), 178 new Code(25, 11, 6145, 8192), 179 new Code(26, 12, 8193, 12288), 180 new Code(27, 12, 12289, 16384), 181 new Code(28, 13, 16385, 24576), 182 new Code(29, 13, 24577, 32768) 183 184 }; 185 186 void writeShortLSB(ByteArrayOutputStream baos, int theShort) { 187 188 byte byte1 = (byte) (theShort & 0xff); 189 byte byte2 = (byte) ((theShort >> 8) & 0xff); 190 byte[] temp = {byte1, byte2}; 191 baos.write(temp, 0, 2); 192 193 } 194 195 void writeInt(ByteArrayOutputStream baos, int theInt) { 196 197 byte byte1 = (byte) ((theInt >> 24) & 0xff); 198 byte byte2 = (byte) ((theInt >> 16) & 0xff); 199 byte byte3 = (byte) ((theInt >> 8) & 0xff); 200 byte byte4 = (byte) (theInt & 0xff); 201 byte[] temp = {byte1, byte2, byte3, byte4}; 202 baos.write(temp, 0, 4); 203 204 } 205 206 void updateAdler(byte value) { 207 208 int low = adler32 & 0xffff; 209 int high = (adler32 >> 16) & 0xffff; 210 int valueInt = value & 0xff; 211 low = (low + valueInt) % BASE; 212 high = (low + high) % BASE; 213 adler32 = (high << 16) | low; 214 215 } 216 217 int hash(byte[] bytes) { 218 219 int hash = ((bytes[0] & 0xff) << 24 | (bytes[1] & 0xff) << 16 | (bytes[2] & 0xff) << 8) % HASH; 220 if (hash < 0) { 221 hash = hash + HASH; 222 } 223 return hash; 224 225 } 226 227 void writeBits(int value, int count) { 228 229 buffer |= value << bitCount; 230 bitCount += count; 231 if (bitCount >= 16) { 232 bytes.write((byte) buffer); 233 bytes.write((byte) (buffer >>> 8)); 234 buffer >>>= 16; 235 bitCount -= 16; 236 } 237 238 } 239 240 void alignToByte() { 241 242 if (bitCount > 0) { 243 bytes.write((byte) buffer); 244 if (bitCount > 8) bytes.write((byte) (buffer >>> 8)); 245 } 246 buffer = 0; 247 bitCount = 0; 248 249 } 250 251 void outputLiteral(byte literal) { 252 253 int i = literal & 0xff; 254 255 if (i <= 143) { 256 writeBits(mirrorBytes[0x30 + i], 8); 258 } 259 else { 260 writeBits(1 + 2 * mirrorBytes[0x90 - 144 + i], 9); 262 } 263 264 } 265 266 Code findCode(int value, Code[] codes) { 267 268 int i, j, k; 269 270 i = -1; 271 j = codes.length; 272 while (true) { 273 k = (j + i) / 2; 274 if (value < codes[k].min) { 275 j = k; 276 } 277 else if (value > codes[k].max) { 278 i = k; 279 } 280 else { 281 return codes[k]; 282 } 283 } 284 285 } 286 287 void outputMatch(int length, int distance) { 288 289 Code d, l; 290 int thisLength; 291 292 while (length > 0) { 293 294 298 if (length > 260) { 299 thisLength = 258; 300 } 301 else if (length <= 258) { 302 thisLength = length; 303 } 304 else { 305 thisLength = length - 3; 306 } 307 308 length = length - thisLength; 309 310 l = findCode(thisLength, lengthCodes); 312 313 if (l.code <= 279) { 317 writeBits(mirrorBytes[(l.code - 256) * 2], 7); 318 } 319 else { 320 writeBits(mirrorBytes[0xc0 - 280 + l.code], 8); 321 } 322 323 if (l.extraBits != 0) { 325 writeBits(thisLength - l.min, l.extraBits); 326 } 327 328 d = findCode(distance, distanceCodes); 330 331 writeBits(mirrorBytes[d.code * 8], 5); 334 335 if (d.extraBits != 0) { 337 writeBits(distance - d.min, d.extraBits); 338 } 339 340 } 341 342 } 343 344 Match findLongestMatch(int position, Link firstPosition) { 345 346 Link link = firstPosition; 347 int numberOfMatches = 0; 348 Match bestMatch = new Match(-1, -1); 349 350 while (true) { 351 352 int matchPosition = link.value; 353 354 if (position - matchPosition < WINDOW && matchPosition != 0) { 355 356 int i; 357 358 for (i = 1; position + i < inLength; i++) { 359 if (in[position + i] != in[matchPosition + i]) { 360 break; 361 } 362 } 363 364 if (i >= MIN_LENGTH) { 365 366 if (i > bestMatch.length) { 367 bestMatch.length = i; 368 bestMatch.distance = position - matchPosition; 369 } 370 371 numberOfMatches = numberOfMatches + 1; 372 373 if (numberOfMatches == MAX_MATCHES) { 374 break; 375 } 376 377 } 378 379 } 380 381 link = link.next; 382 if (link == null) { 383 break; 384 } 385 386 } 387 388 if (bestMatch.length < MIN_LENGTH || bestMatch.distance < 1 || bestMatch.distance > WINDOW) { 389 return null; 390 } 391 392 return bestMatch; 393 394 } 395 396 void updateHashtable(int to, int from) { 397 398 byte[] data = new byte[3]; 399 int hash; 400 Link temp; 401 402 for (int i = to; i < from; i++) { 403 404 if (i + MIN_LENGTH > inLength) { 405 break; 406 } 407 408 data[0] = in[i]; 409 data[1] = in[i + 1]; 410 data[2] = in[i + 2]; 411 412 hash = hash(data); 413 414 if (window[nextWindow].previous != null) { 415 window[nextWindow].previous.next = null; 416 } 417 else if (window[nextWindow].hash != 0) { 418 hashtable[window[nextWindow].hash].next = null; 419 } 420 421 window[nextWindow].hash = hash; 422 window[nextWindow].value = i; 423 window[nextWindow].previous = null; 424 temp = window[nextWindow].next = hashtable[hash].next; 425 hashtable[hash].next = window[nextWindow]; 426 if (temp != null) { 427 temp.previous = window[nextWindow]; 428 } 429 430 nextWindow = nextWindow + 1; 431 if (nextWindow == WINDOW) { 432 nextWindow = 0; 433 } 434 435 } 436 437 } 438 439 void compress() { 440 441 int position, newPosition; 442 byte[] data = new byte[3]; 443 int hash; 444 for (int i = 0; i < HASH; i++) { 445 hashtable[i] = new Link(); 446 } 447 for (int i = 0; i < WINDOW; i++) { 448 window[i] = new Link(); 449 } 450 nextWindow = 0; 451 Link firstPosition; 452 Match match; 453 int deferredPosition = -1; 454 Match deferredMatch = null; 455 456 writeBits(0x01, 1); writeBits(0x01, 2); 459 outputLiteral(in[0]); 461 position = 1; 462 463 while (position < inLength) { 464 465 if (inLength - position < MIN_LENGTH) { 466 outputLiteral(in[position]); 467 position = position + 1; 468 continue; 469 } 470 471 data[0] = in[position]; 472 data[1] = in[position + 1]; 473 data[2] = in[position + 2]; 474 475 hash = hash(data); 476 firstPosition = hashtable[hash]; 477 478 match = findLongestMatch(position, firstPosition); 479 480 updateHashtable(position, position + 1); 481 482 if (match != null) { 483 484 if (deferredMatch != null) { 485 if (match.length > deferredMatch.length + 1) { 486 outputLiteral(in[deferredPosition]); 488 deferredPosition = position; 490 deferredMatch = match; 491 position = position + 1; 492 } 493 else { 494 outputMatch(deferredMatch.length, deferredMatch.distance); 496 newPosition = deferredPosition + deferredMatch.length; 497 deferredPosition = -1; 498 deferredMatch = null; 499 updateHashtable(position + 1, newPosition); 500 position = newPosition; 501 } 502 } 503 else { 504 deferredPosition = position; 506 deferredMatch = match; 507 position = position + 1; 508 } 509 510 } 511 512 else { 513 514 if (deferredMatch != null) { 516 outputMatch(deferredMatch.length, deferredMatch.distance); 517 newPosition = deferredPosition + deferredMatch.length; 518 deferredPosition = -1; 519 deferredMatch = null; 520 updateHashtable(position + 1, newPosition); 521 position = newPosition; 522 } 523 else { 524 outputLiteral(in[position]); 525 position = position + 1; 526 } 527 528 } 529 530 } 531 532 writeBits(0, 7); alignToByte(); 534 535 } 536 537 void compressHuffmanOnly() { 538 539 int position; 540 541 writeBits(0x01, 1); writeBits(0x01, 2); 544 for (position = 0; position < inLength;) { 545 546 outputLiteral(in[position]); 547 position = position + 1; 548 549 } 550 551 writeBits(0, 7); alignToByte(); 553 554 } 555 556 void store() { 557 558 560 int start = 0; 561 int length = inLength; 562 int blockLength; 563 int BFINAL = 0x00; 565 while (length > 0) { 566 567 if (length < 65535) { 568 blockLength = length; 569 BFINAL = 0x01; 570 } 571 else { 572 blockLength = 65535; 573 BFINAL = 0x00; 574 } 575 576 bytes.write((byte) BFINAL); 578 writeShortLSB(bytes, blockLength); writeShortLSB(bytes, blockLength ^ 0xffff); 581 bytes.write(in, start, blockLength); 583 584 length = length - blockLength; 585 start = start + blockLength; 586 587 } 588 589 } 590 591 public byte[] deflate(byte[] input) { 592 593 in = input; 594 inLength = input.length; 595 596 bytes.write((byte) 0x78); bytes.write((byte) 0x9C); 600 for (int i = 0; i < inLength; i++) { 602 updateAdler(in[i]); 603 } 604 605 607 609 compress(); 610 611 writeInt(bytes, adler32); 613 614 return bytes.toByteArray(); 615 616 } 617 618 } 619 | Popular Tags |