1 11 package org.eclipse.swt.internal.image; 12 13 14 import org.eclipse.swt.*; 15 import java.io.*; 16 17 class PngChunk extends Object { 18 byte[] reference; 19 20 static final int LENGTH_OFFSET = 0; 21 static final int TYPE_OFFSET = 4; 22 static final int DATA_OFFSET = 8; 23 24 static final int TYPE_FIELD_LENGTH = 4; 25 static final int LENGTH_FIELD_LENGTH = 4; 26 static final int MIN_LENGTH = 12; 27 28 static final int CHUNK_UNKNOWN = -1; 29 static final int CHUNK_IHDR = 0; 31 static final int CHUNK_PLTE = 1; 32 static final int CHUNK_IDAT = 2; 33 static final int CHUNK_IEND = 3; 34 static final int CHUNK_tRNS = 5; 36 37 static final byte[] TYPE_IHDR = {(byte) 'I', (byte) 'H', (byte) 'D', (byte) 'R'}; 38 static final byte[] TYPE_PLTE = {(byte) 'P', (byte) 'L', (byte) 'T', (byte) 'E'}; 39 static final byte[] TYPE_IDAT = {(byte) 'I', (byte) 'D', (byte) 'A', (byte) 'T'}; 40 static final byte[] TYPE_IEND = {(byte) 'I', (byte) 'E', (byte) 'N', (byte) 'D'}; 41 static final byte[] TYPE_tRNS = {(byte) 't', (byte) 'R', (byte) 'N', (byte) 'S'}; 42 43 static final int[] CRC_TABLE; 44 static { 45 CRC_TABLE = new int[256]; 46 for (int i = 0; i < 256; i++) { 47 CRC_TABLE[i] = i; 48 for (int j = 0; j < 8; j++) { 49 if ((CRC_TABLE[i] & 0x1) == 0) { 50 CRC_TABLE[i] = (CRC_TABLE[i] >> 1) & 0x7FFFFFFF; 51 } else { 52 CRC_TABLE[i] = 0xEDB88320 ^ ((CRC_TABLE[i] >> 1) & 0x7FFFFFFF); 53 } 54 } 55 } 56 } 57 58 int length; 59 60 64 PngChunk(byte[] reference) { 65 super(); 66 setReference(reference); 67 if (reference.length < LENGTH_OFFSET + LENGTH_FIELD_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE); 68 length = getInt32(LENGTH_OFFSET); 69 } 70 71 75 PngChunk(int dataLength) { 76 this(new byte[MIN_LENGTH + dataLength]); 77 setLength(dataLength); 78 } 79 80 83 byte[] getReference() { 84 return reference; 85 } 86 87 90 void setReference(byte[] reference) { 91 this.reference = reference; 92 } 93 94 98 int getInt16(int offset) { 99 int answer = 0; 100 answer |= (reference[offset] & 0xFF) << 8; 101 answer |= (reference[offset + 1] & 0xFF); 102 return answer; 103 } 104 105 109 void setInt16(int offset, int value) { 110 reference[offset] = (byte) ((value >> 8) & 0xFF); 111 reference[offset + 1] = (byte) (value & 0xFF); 112 } 113 114 118 int getInt32(int offset) { 119 int answer = 0; 120 answer |= (reference[offset] & 0xFF) << 24; 121 answer |= (reference[offset + 1] & 0xFF) << 16; 122 answer |= (reference[offset + 2] & 0xFF) << 8; 123 answer |= (reference[offset + 3] & 0xFF); 124 return answer; 125 } 126 127 131 void setInt32(int offset, int value) { 132 reference[offset] = (byte) ((value >> 24) & 0xFF); 133 reference[offset + 1] = (byte) ((value >> 16) & 0xFF); 134 reference[offset + 2] = (byte) ((value >> 8) & 0xFF); 135 reference[offset + 3] = (byte) (value & 0xFF); 136 } 137 138 142 int getLength() { 143 return length; 144 } 145 146 150 void setLength(int value) { 151 setInt32(LENGTH_OFFSET, value); 152 length = value; 153 } 154 155 164 byte[] getTypeBytes() { 165 byte[] type = new byte[4]; 166 System.arraycopy(reference, TYPE_OFFSET, type, 0, TYPE_FIELD_LENGTH); 167 return type; 168 } 169 170 179 void setType(byte[] value) { 180 if (value.length != TYPE_FIELD_LENGTH) { 181 SWT.error (SWT.ERROR_INVALID_ARGUMENT); 182 } 183 System.arraycopy(value, 0, reference, TYPE_OFFSET, TYPE_FIELD_LENGTH); 184 } 185 186 189 byte[] getData() { 190 int dataLength = getLength(); 191 if (reference.length < MIN_LENGTH + dataLength) { 192 SWT.error (SWT.ERROR_INVALID_RANGE); 193 } 194 byte[] data = new byte[dataLength]; 195 System.arraycopy(reference, DATA_OFFSET, data, 0, dataLength); 196 return data; 197 } 198 199 207 void setData(byte[] data) { 208 setLength(data.length); 209 System.arraycopy(data, 0, reference, DATA_OFFSET, data.length); 210 setCRC(computeCRC()); 211 } 212 213 218 int getCRC() { 219 int crcOffset = DATA_OFFSET + getLength(); 220 return getInt32(crcOffset); 221 } 222 223 228 void setCRC(int value) { 229 int crcOffset = DATA_OFFSET + getLength(); 230 setInt32(crcOffset, value); 231 } 232 233 236 int getSize() { 237 return MIN_LENGTH + getLength(); 238 } 239 240 245 boolean checkCRC() { 246 int crc = computeCRC(); 247 int storedCRC = getCRC(); 248 return crc == storedCRC; 249 } 250 251 254 int computeCRC() { 255 int crc = 0xFFFFFFFF; 256 int start = TYPE_OFFSET; 257 int stop = DATA_OFFSET + getLength(); 258 for (int i = start; i < stop; i++) { 259 int index = (crc ^ reference[i]) & 0xFF; 260 crc = CRC_TABLE[index] ^ ((crc >> 8) & 0x00FFFFFF); 261 } 262 return ~crc; 263 } 264 265 boolean typeMatchesArray(byte[] array) { 266 for (int i = 0; i < TYPE_FIELD_LENGTH; i++) { 267 if (reference[TYPE_OFFSET + i] != array[i]){ 268 return false; 269 } 270 } 271 return true; 272 } 273 274 boolean isCritical() { 275 char c = (char) getTypeBytes()[0]; 276 return 'A' <= c && c <= 'Z'; 277 } 278 279 int getChunkType() { 280 if (typeMatchesArray(TYPE_IHDR)) return CHUNK_IHDR; 281 if (typeMatchesArray(TYPE_PLTE)) return CHUNK_PLTE; 282 if (typeMatchesArray(TYPE_IDAT)) return CHUNK_IDAT; 283 if (typeMatchesArray(TYPE_IEND)) return CHUNK_IEND; 284 if (typeMatchesArray(TYPE_tRNS)) return CHUNK_tRNS; 285 return CHUNK_UNKNOWN; 286 } 287 288 292 static PngChunk readNextFromStream(LEDataInputStream stream) { 293 try { 294 int headerLength = LENGTH_FIELD_LENGTH + TYPE_FIELD_LENGTH; 295 byte[] headerBytes = new byte[headerLength]; 296 int result = stream.read(headerBytes, 0, headerLength); 297 stream.unread(headerBytes); 298 if (result != headerLength) return null; 299 300 PngChunk tempChunk = new PngChunk(headerBytes); 301 302 int chunkLength = tempChunk.getSize(); 303 byte[] chunk = new byte[chunkLength]; 304 result = stream.read(chunk, 0, chunkLength); 305 if (result != chunkLength) return null; 306 307 switch (tempChunk.getChunkType()) { 308 case CHUNK_IHDR: 309 return new PngIhdrChunk(chunk); 310 case CHUNK_PLTE: 311 return new PngPlteChunk(chunk); 312 case CHUNK_IDAT: 313 return new PngIdatChunk(chunk); 314 case CHUNK_IEND: 315 return new PngIendChunk(chunk); 316 case CHUNK_tRNS: 317 return new PngTrnsChunk(chunk); 318 default: 319 return new PngChunk(chunk); 320 } 321 } catch (IOException e) { 322 return null; 323 } 324 } 325 326 329 void validate(PngFileReadState readState, PngIhdrChunk headerChunk) { 330 if (reference.length < MIN_LENGTH) SWT.error(SWT.ERROR_INVALID_IMAGE); 331 332 byte[] type = getTypeBytes(); 333 334 char c = (char) type[2]; 336 if (!('A' <= c && c <= 'Z')) SWT.error(SWT.ERROR_INVALID_IMAGE); 337 338 for (int i = 0; i < TYPE_FIELD_LENGTH; i++) { 340 c = (char) type[i]; 341 if (!(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))) { 342 SWT.error(SWT.ERROR_INVALID_IMAGE); 343 } 344 } 345 346 if (!checkCRC()) SWT.error(SWT.ERROR_INVALID_IMAGE); 348 } 349 350 354 void contributeToString(StringBuffer buffer) {} 355 356 362 public String toString() { 363 StringBuffer buffer = new StringBuffer (); 364 buffer.append("{"); 365 buffer.append("\n\tLength: "); 366 buffer.append(getLength()); 367 buffer.append("\n\tType: "); 368 byte[] type = getTypeBytes(); 369 for(int i = 0; i < type.length; i++) { 370 buffer.append((char) type[i]); 371 } 372 373 contributeToString(buffer); 374 375 buffer.append("\n\tCRC: "); 376 buffer.append(Integer.toHexString(getCRC())); 377 buffer.append("\n}"); 378 return buffer.toString(); 379 } 380 381 } 382 | Popular Tags |