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/PngChunk.java')
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java381
1 files changed, 381 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java
new file mode 100755
index 0000000000..74b438ea46
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/common/org/eclipse/swt/internal/image/PngChunk.java
@@ -0,0 +1,381 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 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 org.eclipse.swt.*;
+import java.io.*;
+
+class PngChunk extends Object {
+ byte[] reference;
+
+ static final int LENGTH_OFFSET = 0;
+ static final int TYPE_OFFSET = 4;
+ static final int DATA_OFFSET = 8;
+
+ static final int TYPE_FIELD_LENGTH = 4;
+ static final int LENGTH_FIELD_LENGTH = 4;
+ static final int MIN_LENGTH = 12;
+
+ static final int CHUNK_UNKNOWN = -1;
+ // Critical chunks.
+ static final int CHUNK_IHDR = 0;
+ static final int CHUNK_PLTE = 1;
+ static final int CHUNK_IDAT = 2;
+ static final int CHUNK_IEND = 3;
+ // Non-critical chunks.
+ static final int CHUNK_tRNS = 5;
+
+ static final byte[] TYPE_IHDR = {(byte) 'I', (byte) 'H', (byte) 'D', (byte) 'R'};
+ static final byte[] TYPE_PLTE = {(byte) 'P', (byte) 'L', (byte) 'T', (byte) 'E'};
+ static final byte[] TYPE_IDAT = {(byte) 'I', (byte) 'D', (byte) 'A', (byte) 'T'};
+ static final byte[] TYPE_IEND = {(byte) 'I', (byte) 'E', (byte) 'N', (byte) 'D'};
+ static final byte[] TYPE_tRNS = {(byte) 't', (byte) 'R', (byte) 'N', (byte) 'S'};
+
+ static final int[] CRC_TABLE;
+ static {
+ CRC_TABLE = new int[256];
+ for (int i = 0; i < 256; i++) {
+ CRC_TABLE[i] = i;
+ for (int j = 0; j < 8; j++) {
+ if ((CRC_TABLE[i] & 0x1) == 0) {
+ CRC_TABLE[i] = (CRC_TABLE[i] >> 1) & 0x7FFFFFFF;
+ } else {
+ CRC_TABLE[i] = 0xEDB88320 ^ ((CRC_TABLE[i] >> 1) & 0x7FFFFFFF);
+ }
+ }
+ }
+ }
+
+ int length;
+
+/**
+ * Construct a PngChunk using the reference bytes
+ * given.
+ */
+PngChunk(byte[] reference) {
+ super();
+ setReference(reference);
+ if (reference.length < LENGTH_OFFSET + LENGTH_FIELD_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE);
+ length = getInt32(LENGTH_OFFSET);
+}
+
+/**
+ * Construct a PngChunk with the specified number of
+ * data bytes.
+ */
+PngChunk(int dataLength) {
+ this(new byte[MIN_LENGTH + dataLength]);
+ setLength(dataLength);
+}
+
+/**
+ * Get the PngChunk's reference byteArray;
+ */
+byte[] getReference() {
+ return reference;
+}
+
+/**
+ * Set the PngChunk's reference byteArray;
+ */
+void setReference(byte[] reference) {
+ this.reference = reference;
+}
+
+/**
+ * Get the 16-bit integer from the reference byte
+ * array at the given offset.
+ */
+int getInt16(int offset) {
+ int answer = 0;
+ answer |= (reference[offset] & 0xFF) << 8;
+ answer |= (reference[offset + 1] & 0xFF);
+ return answer;
+}
+
+/**
+ * Set the 16-bit integer in the reference byte
+ * array at the given offset.
+ */
+void setInt16(int offset, int value) {
+ reference[offset] = (byte) ((value >> 8) & 0xFF);
+ reference[offset + 1] = (byte) (value & 0xFF);
+}
+
+/**
+ * Get the 32-bit integer from the reference byte
+ * array at the given offset.
+ */
+int getInt32(int offset) {
+ int answer = 0;
+ answer |= (reference[offset] & 0xFF) << 24;
+ answer |= (reference[offset + 1] & 0xFF) << 16;
+ answer |= (reference[offset + 2] & 0xFF) << 8;
+ answer |= (reference[offset + 3] & 0xFF);
+ return answer;
+}
+
+/**
+ * Set the 32-bit integer in the reference byte
+ * array at the given offset.
+ */
+void setInt32(int offset, int value) {
+ reference[offset] = (byte) ((value >> 24) & 0xFF);
+ reference[offset + 1] = (byte) ((value >> 16) & 0xFF);
+ reference[offset + 2] = (byte) ((value >> 8) & 0xFF);
+ reference[offset + 3] = (byte) (value & 0xFF);
+}
+
+/**
+ * Get the length of the data component of this chunk.
+ * This is not the length of the entire chunk.
+ */
+int getLength() {
+ return length;
+}
+
+/**
+ * Set the length of the data component of this chunk.
+ * This is not the length of the entire chunk.
+ */
+void setLength(int value) {
+ setInt32(LENGTH_OFFSET, value);
+ length = value;
+}
+
+/**
+ * Get the chunk type. This is a four byte value.
+ * Each byte should be an ASCII character.
+ * The first byte is upper case if the chunk is critical.
+ * The second byte is upper case if the chunk is publicly defined.
+ * The third byte must be upper case.
+ * The fourth byte is upper case if the chunk is unsafe to copy.
+ * Public chunk types are defined by the PNG Development Group.
+ */
+byte[] getTypeBytes() {
+ byte[] type = new byte[4];
+ System.arraycopy(reference, TYPE_OFFSET, type, 0, TYPE_FIELD_LENGTH);
+ return type;
+}
+
+/**
+ * Set the chunk type. This is a four byte value.
+ * Each byte should be an ASCII character.
+ * The first byte is upper case if the chunk is critical.
+ * The second byte is upper case if the chunk is publicly defined.
+ * The third byte must be upper case.
+ * The fourth byte is upper case if the chunk is unsafe to copy.
+ * Public chunk types are defined by the PNG Development Group.
+ */
+void setType(byte[] value) {
+ if (value.length != TYPE_FIELD_LENGTH) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ System.arraycopy(value, 0, reference, TYPE_OFFSET, TYPE_FIELD_LENGTH);
+}
+
+/**
+ * Get the chunk's data.
+ */
+byte[] getData() {
+ int dataLength = getLength();
+ if (reference.length < MIN_LENGTH + dataLength) {
+ SWT.error (SWT.ERROR_INVALID_RANGE);
+ }
+ byte[] data = new byte[dataLength];
+ System.arraycopy(reference, DATA_OFFSET, data, 0, dataLength);
+ return data;
+}
+
+/**
+ * Set the chunk's data.
+ * This method has two side-effects.
+ * 1. It will set the length field to be the length
+ * of the data array given.
+ * 2. It will set the CRC field to the computed CRC
+ * value of the data array given.
+ */
+void setData(byte[] data) {
+ setLength(data.length);
+ System.arraycopy(data, 0, reference, DATA_OFFSET, data.length);
+ setCRC(computeCRC());
+}
+
+/**
+ * Get the CRC value for the chunk's data.
+ * Ensure that the length field has a good
+ * value before making this call.
+ */
+int getCRC() {
+ int crcOffset = DATA_OFFSET + getLength();
+ return getInt32(crcOffset);
+}
+
+/**
+ * Set the CRC value for the chunk's data.
+ * Ensure that the length field has a good
+ * value before making this call.
+ */
+void setCRC(int value) {
+ int crcOffset = DATA_OFFSET + getLength();
+ setInt32(crcOffset, value);
+}
+
+/**
+ * Get the chunk's total size including the length, type, and crc fields.
+ */
+int getSize() {
+ return MIN_LENGTH + getLength();
+}
+
+/**
+ * Compute the CRC value for the chunk's data. Answer
+ * whether this value matches the value stored in the
+ * chunk.
+ */
+boolean checkCRC() {
+ int crc = computeCRC();
+ int storedCRC = getCRC();
+ return crc == storedCRC;
+}
+
+/**
+ * Answer the CRC value of chunk's data.
+ */
+int computeCRC() {
+ int crc = 0xFFFFFFFF;
+ int start = TYPE_OFFSET;
+ int stop = DATA_OFFSET + getLength();
+ for (int i = start; i < stop; i++) {
+ int index = (crc ^ reference[i]) & 0xFF;
+ crc = CRC_TABLE[index] ^ ((crc >> 8) & 0x00FFFFFF);
+ }
+ return ~crc;
+}
+
+boolean typeMatchesArray(byte[] array) {
+ for (int i = 0; i < TYPE_FIELD_LENGTH; i++) {
+ if (reference[TYPE_OFFSET + i] != array[i]){
+ return false;
+ }
+ }
+ return true;
+}
+
+boolean isCritical() {
+ char c = (char) getTypeBytes()[0];
+ return 'A' <= c && c <= 'Z';
+}
+
+int getChunkType() {
+ if (typeMatchesArray(TYPE_IHDR)) return CHUNK_IHDR;
+ if (typeMatchesArray(TYPE_PLTE)) return CHUNK_PLTE;
+ if (typeMatchesArray(TYPE_IDAT)) return CHUNK_IDAT;
+ if (typeMatchesArray(TYPE_IEND)) return CHUNK_IEND;
+ if (typeMatchesArray(TYPE_tRNS)) return CHUNK_tRNS;
+ return CHUNK_UNKNOWN;
+}
+
+/**
+ * Read the next PNG chunk from the input stream given.
+ * If unable to read a chunk, return null.
+ */
+static PngChunk readNextFromStream(LEDataInputStream stream) {
+ try {
+ int headerLength = LENGTH_FIELD_LENGTH + TYPE_FIELD_LENGTH;
+ byte[] headerBytes = new byte[headerLength];
+ int result = stream.read(headerBytes, 0, headerLength);
+ stream.unread(headerBytes);
+ if (result != headerLength) return null;
+
+ PngChunk tempChunk = new PngChunk(headerBytes);
+
+ int chunkLength = tempChunk.getSize();
+ byte[] chunk = new byte[chunkLength];
+ result = stream.read(chunk, 0, chunkLength);
+ if (result != chunkLength) return null;
+
+ switch (tempChunk.getChunkType()) {
+ case CHUNK_IHDR:
+ return new PngIhdrChunk(chunk);
+ case CHUNK_PLTE:
+ return new PngPlteChunk(chunk);
+ case CHUNK_IDAT:
+ return new PngIdatChunk(chunk);
+ case CHUNK_IEND:
+ return new PngIendChunk(chunk);
+ case CHUNK_tRNS:
+ return new PngTrnsChunk(chunk);
+ default:
+ return new PngChunk(chunk);
+ }
+ } catch (IOException e) {
+ return null;
+ }
+}
+
+/**
+ * Answer whether the chunk is a valid PNG chunk.
+ */
+void validate(PngFileReadState readState, PngIhdrChunk headerChunk) {
+ if (reference.length < MIN_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE);
+
+ byte[] type = getTypeBytes();
+
+ // The third character MUST be upper case.
+ char c = (char) type[2];
+ if (!('A' <= c && c <= 'Z')) SWT.error(SWT.ERROR_INVALID_IMAGE);
+
+ // All characters must be letters.
+ for (int i = 0; i < TYPE_FIELD_LENGTH; i++) {
+ c = (char) type[i];
+ if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) {
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ }
+ }
+
+ // The stored CRC must match the data's computed CRC.
+ if (!checkCRC()) SWT.error(SWT.ERROR_INVALID_IMAGE);
+}
+
+/**
+ * Provided so that subclasses can override and add
+ * data to the toString() call.
+ */
+void contributeToString(StringBuffer buffer) {}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("{");
+ buffer.append("\n\tLength: ");
+ buffer.append(getLength());
+ buffer.append("\n\tType: ");
+ byte[] type = getTypeBytes();
+ for(int i = 0; i < type.length; i++) {
+ buffer.append((char) type[i]);
+ }
+
+ contributeToString(buffer);
+
+ buffer.append("\n\tCRC: ");
+ buffer.append(Integer.toHexString(getCRC()));
+ buffer.append("\n}");
+ return buffer.toString();
+}
+
+}

Back to the top