Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDeflater.java')
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDeflater.java618
1 files changed, 618 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDeflater.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDeflater.java
new file mode 100644
index 0000000000..d382f38d4f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngDeflater.java
@@ -0,0 +1,618 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal.image;
+
+import java.io.ByteArrayOutputStream;
+
+public class PngDeflater {
+
+ static final int BASE = 65521;
+ static final int WINDOW = 32768;
+ static final int MIN_LENGTH = 3;
+ static final int MAX_MATCHES = 32;
+ static final int HASH = 8209;
+
+ byte[] in;
+ int inLength;
+
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024);
+
+ int adler32 = 1;
+
+ int buffer, bitCount;
+
+ Link[] hashtable = new Link[HASH];
+ Link[] window = new Link[WINDOW];
+ int nextWindow;
+
+static class Link {
+
+ int hash, value;
+ Link previous, next;
+
+ Link() {
+
+ this.hash = 0;
+ this.value = 0;
+ this.previous = null;
+ this.next = null;
+
+ }
+
+}
+
+static class Match {
+
+ int length, distance;
+
+ Match(int length, int distance) {
+
+ this.length = length;
+ this.distance = distance;
+
+ }
+
+}
+
+static final short mirrorBytes[] = {
+
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+
+};
+
+static class Code {
+
+ int code, extraBits, min, max;
+
+ Code(int code, int extraBits, int min, int max) {
+
+ this.code = code;
+ this.extraBits = extraBits;
+ this.min = min;
+ this.max = max;
+
+ }
+
+}
+
+static final Code lengthCodes[] = {
+
+ new Code(257, 0, 3, 3),
+ new Code(258, 0, 4, 4),
+ new Code(259, 0, 5, 5),
+ new Code(260, 0, 6, 6),
+ new Code(261, 0, 7, 7),
+ new Code(262, 0, 8, 8),
+ new Code(263, 0, 9, 9),
+ new Code(264, 0, 10, 10),
+ new Code(265, 1, 11, 12),
+ new Code(266, 1, 13, 14),
+ new Code(267, 1, 15, 16),
+ new Code(268, 1, 17, 18),
+ new Code(269, 2, 19, 22),
+ new Code(270, 2, 23, 26),
+ new Code(271, 2, 27, 30),
+ new Code(272, 2, 31, 34),
+ new Code(273, 3, 35, 42),
+ new Code(274, 3, 43, 50),
+ new Code(275, 3, 51, 58),
+ new Code(276, 3, 59, 66),
+ new Code(277, 4, 67, 82),
+ new Code(278, 4, 83, 98),
+ new Code(279, 4, 99, 114),
+ new Code(280, 4, 115, 130),
+ new Code(281, 5, 131, 162),
+ new Code(282, 5, 163, 194),
+ new Code(283, 5, 195, 226),
+ new Code(284, 5, 227, 257),
+ new Code(285, 0, 258, 258)
+
+};
+
+static final Code distanceCodes[] = {
+
+ new Code(0, 0, 1, 1),
+ new Code(1, 0, 2, 2),
+ new Code(2, 0, 3, 3),
+ new Code(3, 0, 4, 4),
+ new Code(4, 1, 5, 6),
+ new Code(5, 1, 7, 8),
+ new Code(6, 2, 9, 12),
+ new Code(7, 2, 13, 16),
+ new Code(8, 3, 17, 24),
+ new Code(9, 3, 25, 32),
+ new Code(10, 4, 33, 48),
+ new Code(11, 4, 49, 64),
+ new Code(12, 5, 65, 96),
+ new Code(13, 5, 97, 128),
+ new Code(14, 6, 129, 192),
+ new Code(15, 6, 193, 256),
+ new Code(16, 7, 257, 384),
+ new Code(17, 7, 385, 512),
+ new Code(18, 8, 513, 768),
+ new Code(19, 8, 769, 1024),
+ new Code(20, 9, 1025, 1536),
+ new Code(21, 9, 1537, 2048),
+ new Code(22, 10, 2049, 3072),
+ new Code(23, 10, 3073, 4096),
+ new Code(24, 11, 4097, 6144),
+ new Code(25, 11, 6145, 8192),
+ new Code(26, 12, 8193, 12288),
+ new Code(27, 12, 12289, 16384),
+ new Code(28, 13, 16385, 24576),
+ new Code(29, 13, 24577, 32768)
+
+};
+
+void writeShortLSB(ByteArrayOutputStream baos, int theShort) {
+
+ byte byte1 = (byte) (theShort & 0xff);
+ byte byte2 = (byte) ((theShort >> 8) & 0xff);
+ byte[] temp = {byte1, byte2};
+ baos.write(temp, 0, 2);
+
+}
+
+void writeInt(ByteArrayOutputStream baos, int theInt) {
+
+ byte byte1 = (byte) ((theInt >> 24) & 0xff);
+ byte byte2 = (byte) ((theInt >> 16) & 0xff);
+ byte byte3 = (byte) ((theInt >> 8) & 0xff);
+ byte byte4 = (byte) (theInt & 0xff);
+ byte[] temp = {byte1, byte2, byte3, byte4};
+ baos.write(temp, 0, 4);
+
+}
+
+void updateAdler(byte value) {
+
+ int low = adler32 & 0xffff;
+ int high = (adler32 >> 16) & 0xffff;
+ int valueInt = value & 0xff;
+ low = (low + valueInt) % BASE;
+ high = (low + high) % BASE;
+ adler32 = (high << 16) | low;
+
+}
+
+int hash(byte[] bytes) {
+
+ int hash = ((bytes[0] & 0xff) << 24 | (bytes[1] & 0xff) << 16 | (bytes[2] & 0xff) << 8) % HASH;
+ if (hash < 0) {
+ hash = hash + HASH;
+ }
+ return hash;
+
+}
+
+void writeBits(int value, int count) {
+
+ buffer |= value << bitCount;
+ bitCount += count;
+ if (bitCount >= 16) {
+ bytes.write((byte) buffer);
+ bytes.write((byte) (buffer >>> 8));
+ buffer >>>= 16;
+ bitCount -= 16;
+ }
+
+}
+
+void alignToByte() {
+
+ if (bitCount > 0) {
+ bytes.write((byte) buffer);
+ if (bitCount > 8) bytes.write((byte) (buffer >>> 8));
+ }
+ buffer = 0;
+ bitCount = 0;
+
+}
+
+void outputLiteral(byte literal) {
+
+ int i = literal & 0xff;
+
+ if (i <= 143) {
+ // 0 through 143 are 8 bits long starting at 00110000
+ writeBits(mirrorBytes[0x30 + i], 8);
+ }
+ else {
+ // 144 through 255 are 9 bits long starting at 110010000
+ writeBits(1 + 2 * mirrorBytes[0x90 - 144 + i], 9);
+ }
+
+}
+
+Code findCode(int value, Code[] codes) {
+
+ int i, j, k;
+
+ i = -1;
+ j = codes.length;
+ while (true) {
+ k = (j + i) / 2;
+ if (value < codes[k].min) {
+ j = k;
+ }
+ else if (value > codes[k].max) {
+ i = k;
+ }
+ else {
+ return codes[k];
+ }
+ }
+
+}
+
+void outputMatch(int length, int distance) {
+
+ Code d, l;
+ int thisLength;
+
+ while (length > 0) {
+
+ // we can transmit matches of lengths 3 through 258 inclusive
+ // so if length exceeds 258, we must transmit in several steps,
+ // with 258 or less in each step
+
+ if (length > 260) {
+ thisLength = 258;
+ }
+ else if (length <= 258) {
+ thisLength = length;
+ }
+ else {
+ thisLength = length - 3;
+ }
+
+ length = length - thisLength;
+
+ // find length code
+ l = findCode(thisLength, lengthCodes);
+
+ // transmit the length code
+ // 256 through 279 are 7 bits long starting at 0000000
+ // 280 through 287 are 8 bits long starting at 11000000
+ if (l.code <= 279) {
+ writeBits(mirrorBytes[(l.code - 256) * 2], 7);
+ }
+ else {
+ writeBits(mirrorBytes[0xc0 - 280 + l.code], 8);
+ }
+
+ // transmit the extra bits
+ if (l.extraBits != 0) {
+ writeBits(thisLength - l.min, l.extraBits);
+ }
+
+ // find distance code
+ d = findCode(distance, distanceCodes);
+
+ // transmit the distance code
+ // 5 bits long starting at 00000
+ writeBits(mirrorBytes[d.code * 8], 5);
+
+ // transmit the extra bits
+ if (d.extraBits != 0) {
+ writeBits(distance - d.min, d.extraBits);
+ }
+
+ }
+
+}
+
+Match findLongestMatch(int position, Link firstPosition) {
+
+ Link link = firstPosition;
+ int numberOfMatches = 0;
+ Match bestMatch = new Match(-1, -1);
+
+ while (true) {
+
+ int matchPosition = link.value;
+
+ if (position - matchPosition < WINDOW && matchPosition != 0) {
+
+ int i;
+
+ for (i = 1; position + i < inLength; i++) {
+ if (in[position + i] != in[matchPosition + i]) {
+ break;
+ }
+ }
+
+ if (i >= MIN_LENGTH) {
+
+ if (i > bestMatch.length) {
+ bestMatch.length = i;
+ bestMatch.distance = position - matchPosition;
+ }
+
+ numberOfMatches = numberOfMatches + 1;
+
+ if (numberOfMatches == MAX_MATCHES) {
+ break;
+ }
+
+ }
+
+ }
+
+ link = link.next;
+ if (link == null) {
+ break;
+ }
+
+ }
+
+ if (bestMatch.length < MIN_LENGTH || bestMatch.distance < 1 || bestMatch.distance > WINDOW) {
+ return null;
+ }
+
+ return bestMatch;
+
+}
+
+void updateHashtable(int to, int from) {
+
+ byte[] data = new byte[3];
+ int hash;
+ Link temp;
+
+ for (int i = to; i < from; i++) {
+
+ if (i + MIN_LENGTH > inLength) {
+ break;
+ }
+
+ data[0] = in[i];
+ data[1] = in[i + 1];
+ data[2] = in[i + 2];
+
+ hash = hash(data);
+
+ if (window[nextWindow].previous != null) {
+ window[nextWindow].previous.next = null;
+ }
+ else if (window[nextWindow].hash != 0) {
+ hashtable[window[nextWindow].hash].next = null;
+ }
+
+ window[nextWindow].hash = hash;
+ window[nextWindow].value = i;
+ window[nextWindow].previous = null;
+ temp = window[nextWindow].next = hashtable[hash].next;
+ hashtable[hash].next = window[nextWindow];
+ if (temp != null) {
+ temp.previous = window[nextWindow];
+ }
+
+ nextWindow = nextWindow + 1;
+ if (nextWindow == WINDOW) {
+ nextWindow = 0;
+ }
+
+ }
+
+}
+
+void compress() {
+
+ int position, newPosition;
+ byte[] data = new byte[3];
+ int hash;
+ for (int i = 0; i < HASH; i++) {
+ hashtable[i] = new Link();
+ }
+ for (int i = 0; i < WINDOW; i++) {
+ window[i] = new Link();
+ }
+ nextWindow = 0;
+ Link firstPosition;
+ Match match;
+ int deferredPosition = -1;
+ Match deferredMatch = null;
+
+ writeBits(0x01, 1); // BFINAL = 0x01 (final block)
+ writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes)
+
+ // just output first byte so we never match at zero
+ outputLiteral(in[0]);
+ position = 1;
+
+ while (position < inLength) {
+
+ if (inLength - position < MIN_LENGTH) {
+ outputLiteral(in[position]);
+ position = position + 1;
+ continue;
+ }
+
+ data[0] = in[position];
+ data[1] = in[position + 1];
+ data[2] = in[position + 2];
+
+ hash = hash(data);
+ firstPosition = hashtable[hash];
+
+ match = findLongestMatch(position, firstPosition);
+
+ updateHashtable(position, position + 1);
+
+ if (match != null) {
+
+ if (deferredMatch != null) {
+ if (match.length > deferredMatch.length + 1) {
+ // output literal at deferredPosition
+ outputLiteral(in[deferredPosition]);
+ // defer this match
+ deferredPosition = position;
+ deferredMatch = match;
+ position = position + 1;
+ }
+ else {
+ // output deferredMatch
+ outputMatch(deferredMatch.length, deferredMatch.distance);
+ newPosition = deferredPosition + deferredMatch.length;
+ deferredPosition = -1;
+ deferredMatch = null;
+ updateHashtable(position + 1, newPosition);
+ position = newPosition;
+ }
+ }
+ else {
+ // defer this match
+ deferredPosition = position;
+ deferredMatch = match;
+ position = position + 1;
+ }
+
+ }
+
+ else {
+
+ // no match found
+ if (deferredMatch != null) {
+ outputMatch(deferredMatch.length, deferredMatch.distance);
+ newPosition = deferredPosition + deferredMatch.length;
+ deferredPosition = -1;
+ deferredMatch = null;
+ updateHashtable(position + 1, newPosition);
+ position = newPosition;
+ }
+ else {
+ outputLiteral(in[position]);
+ position = position + 1;
+ }
+
+ }
+
+ }
+
+ writeBits(0, 7); // end of block code
+ alignToByte();
+
+}
+
+void compressHuffmanOnly() {
+
+ int position;
+
+ writeBits(0x01, 1); // BFINAL = 0x01 (final block)
+ writeBits(0x01, 2); // BTYPE = 0x01 (compression with fixed Huffman codes)
+
+ for (position = 0; position < inLength;) {
+
+ outputLiteral(in[position]);
+ position = position + 1;
+
+ }
+
+ writeBits(0, 7); // end of block code
+ alignToByte();
+
+}
+
+void store() {
+
+ // stored blocks are limited to 0xffff bytes
+
+ int start = 0;
+ int length = inLength;
+ int blockLength;
+ int BFINAL = 0x00; // BFINAL = 0x00 or 0x01 (if final block), BTYPE = 0x00 (no compression)
+
+ while (length > 0) {
+
+ if (length < 65535) {
+ blockLength = length;
+ BFINAL = 0x01;
+ }
+ else {
+ blockLength = 65535;
+ BFINAL = 0x00;
+ }
+
+ // write data header
+ bytes.write((byte) BFINAL);
+ writeShortLSB(bytes, blockLength); // LEN
+ writeShortLSB(bytes, blockLength ^ 0xffff); // NLEN (one's complement of LEN)
+
+ // write actual data
+ bytes.write(in, start, blockLength);
+
+ length = length - blockLength;
+ start = start + blockLength;
+
+ }
+
+}
+
+public byte[] deflate(byte[] input) {
+
+ in = input;
+ inLength = input.length;
+
+ // write zlib header
+ bytes.write((byte) 0x78); // window size = 0x70 (32768), compression method = 0x08
+ bytes.write((byte) 0x9C); // compression level = 0x80 (default), check bits = 0x1C
+
+ // compute checksum
+ for (int i = 0; i < inLength; i++) {
+ updateAdler(in[i]);
+ }
+
+ //store();
+
+ //compressHuffmanOnly();
+
+ compress();
+
+ // write checksum
+ writeInt(bytes, adler32);
+
+ return bytes.toByteArray();
+
+}
+
+}

Back to the top