1 /******************************************************************************* 2 * Copyright (c) 2000, 2011 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.swt.internal.image; 15 16 17 import java.io.*; 18 19 import org.eclipse.swt.*; 20 21 public class PngDecodingDataStream extends InputStream { 22 InputStream stream; 23 byte currentByte; 24 int nextBitIndex; 25 26 PngLzBlockReader lzBlockReader; 27 int adlerValue; 28 29 static final int PRIME = 65521; 30 static final int MAX_BIT = 7; 31 PngDecodingDataStream(InputStream stream)32PngDecodingDataStream(InputStream stream) throws IOException { 33 super(); 34 this.stream = stream; 35 nextBitIndex = MAX_BIT + 1; 36 adlerValue = 1; 37 lzBlockReader = new PngLzBlockReader(this); 38 readCompressedDataHeader(); 39 lzBlockReader.readNextBlockHeader(); 40 } 41 42 /** 43 * This method should be called when the image decoder thinks 44 * that all of the compressed image data has been read. This 45 * method will ensure that the next data value is an end of 46 * block marker. If there are more blocks after this one, 47 * the method will read them and ensure that they are empty. 48 */ assertImageDataAtEnd()49void assertImageDataAtEnd() throws IOException { 50 lzBlockReader.assertCompressedDataAtEnd(); 51 } 52 53 @Override close()54public void close() throws IOException { 55 assertImageDataAtEnd(); 56 checkAdler(); 57 } 58 getNextIdatBits(int length)59int getNextIdatBits(int length) throws IOException { 60 int value = 0; 61 for (int i = 0; i < length; i++) { 62 value |= (getNextIdatBit() << i); 63 } 64 return value; 65 } 66 getNextIdatBit()67int getNextIdatBit() throws IOException { 68 if (nextBitIndex > MAX_BIT) { 69 currentByte = getNextIdatByte(); 70 nextBitIndex = 0; 71 } 72 return (currentByte & (1 << nextBitIndex)) >> nextBitIndex++; 73 } 74 getNextIdatByte()75byte getNextIdatByte() throws IOException { 76 byte nextByte = (byte)stream.read(); 77 nextBitIndex = MAX_BIT + 1; 78 return nextByte; 79 } 80 updateAdler(byte value)81void updateAdler(byte value) { 82 int low = adlerValue & 0xFFFF; 83 int high = (adlerValue >> 16) & 0xFFFF; 84 int valueInt = value & 0xFF; 85 low = (low + valueInt) % PRIME; 86 high = (low + high) % PRIME; 87 adlerValue = (high << 16) | low; 88 } 89 90 @Override read()91public int read() throws IOException { 92 byte nextDecodedByte = lzBlockReader.getNextByte(); 93 updateAdler(nextDecodedByte); 94 return nextDecodedByte & 0xFF; 95 } 96 97 @Override read(byte[] buffer, int off, int len)98public int read(byte[] buffer, int off, int len) throws IOException { 99 for (int i = 0; i < len; i++) { 100 int b = read(); 101 if (b == -1) return i; 102 buffer[off + i] = (byte)b; 103 } 104 return len; 105 } 106 error()107void error() { 108 SWT.error(SWT.ERROR_INVALID_IMAGE); 109 } 110 readCompressedDataHeader()111private void readCompressedDataHeader() throws IOException { 112 byte headerByte1 = getNextIdatByte(); 113 byte headerByte2 = getNextIdatByte(); 114 115 int number = ((headerByte1 & 0xFF) << 8) | (headerByte2 & 0xFF); 116 if (number % 31 != 0) error(); 117 118 int compressionMethod = headerByte1 & 0x0F; 119 if (compressionMethod != 8) error(); 120 121 int windowSizeHint = (headerByte1 & 0xF0) >> 4; 122 if (windowSizeHint > 7) error(); 123 int windowSize = (1 << (windowSizeHint + 8)); 124 lzBlockReader.setWindowSize(windowSize); 125 126 int dictionary = (headerByte2 & (1 << 5)); 127 if (dictionary != 0) error(); 128 129 // int compressionLevel = (headerByte2 & 0xC0) >> 6; 130 } 131 checkAdler()132void checkAdler() throws IOException { 133 int storedAdler = ((getNextIdatByte() & 0xFF) << 24) 134 | ((getNextIdatByte() & 0xFF) << 16) 135 | ((getNextIdatByte() & 0xFF) << 8) 136 | (getNextIdatByte() & 0xFF); 137 if (storedAdler != adlerValue) error(); 138 } 139 140 } 141