| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.imaging.common; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.RandomAccessFile; |
| |
| import org.apache.commons.imaging.ImageReadException; |
| |
| public class BinaryInputStream extends InputStream implements BinaryConstants |
| { |
| protected boolean debug = false; |
| |
| public final void setDebug(boolean b) |
| { |
| debug = b; |
| } |
| |
| public final boolean getDebug() |
| { |
| return debug; |
| } |
| |
| private final InputStream is; |
| |
| public BinaryInputStream(byte bytes[], int byteOrder) |
| { |
| this.byteOrder = byteOrder; |
| this.is = new ByteArrayInputStream(bytes); |
| } |
| |
| public BinaryInputStream(InputStream is, int byteOrder) |
| { |
| this.byteOrder = byteOrder; |
| this.is = is; |
| } |
| |
| public BinaryInputStream(InputStream is) |
| { |
| this.is = is; |
| } |
| |
| // default byte order for Java, many file formats. |
| private int byteOrder = BYTE_ORDER_NETWORK; |
| |
| protected void setByteOrder(int a, int b) throws ImageReadException |
| { |
| if (a != b) |
| throw new ImageReadException("Byte Order bytes don't match (" + a |
| + ", " + b + ")."); |
| |
| if (a == BYTE_ORDER_MOTOROLA) |
| byteOrder = a; |
| else if (a == BYTE_ORDER_INTEL) |
| byteOrder = a; |
| else |
| throw new ImageReadException("Unknown Byte Order hint: " + a); |
| } |
| |
| protected void setByteOrder(int byteOrder) |
| { |
| this.byteOrder = byteOrder; |
| } |
| |
| protected int getByteOrder() |
| { |
| return byteOrder; |
| } |
| |
| @Override |
| public int read() throws IOException |
| { |
| return is.read(); |
| } |
| |
| protected final int convertByteArrayToInt(String name, byte bytes[]) |
| { |
| return convertByteArrayToInt(name, bytes, byteOrder); |
| } |
| |
| public final int convertByteArrayToShort(String name, byte bytes[]) |
| { |
| return convertByteArrayToShort(name, bytes, byteOrder); |
| } |
| |
| public final int convertByteArrayToShort(String name, int start, |
| byte bytes[]) |
| { |
| return convertByteArrayToShort(name, start, bytes, byteOrder); |
| } |
| |
| public final int read4Bytes(String name, String exception) |
| throws IOException |
| { |
| return read4Bytes(name, exception, byteOrder); |
| } |
| |
| public final int read3Bytes(String name, String exception) |
| throws IOException |
| { |
| return read3Bytes(name, exception, byteOrder); |
| } |
| |
| public final int read2Bytes(String name, String exception) |
| throws IOException |
| { |
| return read2Bytes(name, exception, byteOrder); |
| } |
| |
| protected final void readRandomBytes() throws IOException |
| { |
| |
| for (int counter = 0; counter < 100; counter++) |
| { |
| readByte("" + counter, "Random Data"); |
| } |
| } |
| |
| public final void debugNumber(String msg, int data) |
| { |
| debugNumber(msg, data, 1); |
| } |
| |
| public final void debugNumber(String msg, int data, int bytes) |
| { |
| System.out.print(msg + ": " + data + " ("); |
| int byteData = data; |
| for (int i = 0; i < bytes; i++) |
| { |
| if (i > 0) |
| System.out.print(","); |
| int singleByte = 0xff & byteData; |
| System.out.print((char) singleByte + " [" + singleByte + "]"); |
| byteData >>= 8; |
| } |
| System.out.println(") [0x" + Integer.toHexString(data) + ", " |
| + Integer.toBinaryString(data) + "]"); |
| } |
| |
| public final void readAndVerifyBytes(byte expected[], String exception) |
| throws ImageReadException, IOException |
| { |
| for (int i = 0; i < expected.length; i++) |
| { |
| int data = is.read(); |
| byte b = (byte) (0xff & data); |
| |
| if ((data < 0) || (b != expected[i])) |
| { |
| System.out.println("i" + ": " + i); |
| |
| this.debugByteArray("expected", expected); |
| debugNumber("data[" + i + "]", b); |
| // debugNumber("expected[" + i + "]", expected[i]); |
| |
| throw new ImageReadException(exception); |
| } |
| } |
| } |
| |
| protected final void readAndVerifyBytes(String name, byte expected[], |
| String exception) throws ImageReadException, IOException |
| { |
| byte bytes[] = readByteArray(name, expected.length, exception); |
| |
| for (int i = 0; i < expected.length; i++) |
| { |
| if (bytes[i] != expected[i]) |
| { |
| System.out.println("i" + ": " + i); |
| debugNumber("bytes[" + i + "]", bytes[i]); |
| debugNumber("expected[" + i + "]", expected[i]); |
| |
| throw new ImageReadException(exception); |
| } |
| } |
| } |
| |
| public final void skipBytes(int length, String exception) |
| throws IOException |
| { |
| long total = 0; |
| while (length != total) |
| { |
| long skipped = is.skip(length - total); |
| if (skipped < 1) |
| throw new IOException(exception + " (" + skipped + ")"); |
| total += skipped; |
| } |
| } |
| |
| protected final void scanForByte(byte value) throws IOException |
| { |
| int count = 0; |
| for (int i = 0; count < 3; i++) |
| // while(count<3) |
| { |
| int b = is.read(); |
| if (b < 0) |
| return; |
| if ((0xff & b) == value) |
| { |
| System.out.println("\t" + i + ": match."); |
| count++; |
| } |
| } |
| } |
| |
| public final byte readByte(String name, String exception) |
| throws IOException |
| { |
| int result = is.read(); |
| |
| if ((result < 0)) |
| { |
| System.out.println(name + ": " + result); |
| throw new IOException(exception); |
| } |
| |
| if (debug) |
| debugNumber(name, result); |
| |
| return (byte) (0xff & result); |
| } |
| |
| protected final RationalNumber[] convertByteArrayToRationalArray( |
| String name, byte bytes[], int start, int length, int byteOrder) |
| { |
| int expectedLength = start + length * 8; |
| |
| if (bytes.length < expectedLength) |
| { |
| System.out.println(name + ": expected length: " + expectedLength |
| + ", actual length: " + bytes.length); |
| return null; |
| } |
| |
| RationalNumber result[] = new RationalNumber[length]; |
| |
| for (int i = 0; i < length; i++) |
| { |
| result[i] = convertByteArrayToRational(name, bytes, start + i * 8, |
| byteOrder); |
| } |
| |
| return result; |
| } |
| |
| protected final RationalNumber convertByteArrayToRational(String name, |
| byte bytes[], int byteOrder) |
| { |
| return convertByteArrayToRational(name, bytes, 0, byteOrder); |
| } |
| |
| protected final RationalNumber convertByteArrayToRational(String name, |
| byte bytes[], int start, int byteOrder) |
| { |
| int numerator = convertByteArrayToInt(name, bytes, start + 0, 4, |
| byteOrder); |
| int divisor = convertByteArrayToInt(name, bytes, start + 4, 4, |
| byteOrder); |
| |
| return new RationalNumber(numerator, divisor); |
| } |
| |
| protected final int convertByteArrayToInt(String name, byte bytes[], |
| int byteOrder) |
| { |
| return convertByteArrayToInt(name, bytes, 0, 4, byteOrder); |
| } |
| |
| protected final int convertByteArrayToInt(String name, byte bytes[], |
| int start, int length, int byteOrder) |
| { |
| byte byte0 = bytes[start + 0]; |
| byte byte1 = bytes[start + 1]; |
| byte byte2 = bytes[start + 2]; |
| byte byte3 = 0; |
| if (length == 4) |
| byte3 = bytes[start + 3]; |
| |
| // return convert4BytesToInt(name, byte0, byte1, byte2, byte3, |
| // byteOrder); |
| |
| int result; |
| |
| if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian |
| result = ((0xff & byte0) << 24) + ((0xff & byte1) << 16) |
| + ((0xff & byte2) << 8) + ((0xff & byte3) << 0); |
| // result = (( byte0) << 24) + ((byte1) << 16) |
| // + (( byte2) << 8) + (( byte3) << 0); |
| else |
| // intel, little endian |
| result = ((0xff & byte3) << 24) + ((0xff & byte2) << 16) |
| + ((0xff & byte1) << 8) + ((0xff & byte0) << 0); |
| // result = (( byte3) << 24) + (( byte2) << 16) |
| // + (( byte1) << 8) + (( byte0) << 0); |
| |
| if (debug) |
| debugNumber(name, result, 4); |
| |
| return result; |
| } |
| |
| protected final int[] convertByteArrayToIntArray(String name, byte bytes[], |
| int start, int length, int byteOrder) |
| { |
| int expectedLength = start + length * 4; |
| |
| if (bytes.length < expectedLength) |
| { |
| System.out.println(name + ": expected length: " + expectedLength |
| + ", actual length: " + bytes.length); |
| return null; |
| } |
| |
| int result[] = new int[length]; |
| |
| for (int i = 0; i < length; i++) |
| { |
| result[i] = convertByteArrayToInt(name, bytes, start + i * 4, 4, |
| byteOrder); |
| } |
| |
| return result; |
| } |
| |
| protected final int convertByteArrayToShort(String name, byte bytes[], |
| int byteOrder) |
| { |
| return convertByteArrayToShort(name, 0, bytes, byteOrder); |
| } |
| |
| protected final int convertByteArrayToShort(String name, int start, |
| byte bytes[], int byteOrder) |
| { |
| byte byte0 = bytes[start + 0]; |
| byte byte1 = bytes[start + 1]; |
| |
| // return convert2BytesToShort(name, byte0, byte1, byteOrder); |
| |
| int result; |
| |
| if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian |
| result = ((0xff & byte0) << 8) + ((0xff & byte1) << 0); |
| else |
| // intel, little endian |
| result = ((0xff & byte1) << 8) + ((0xff & byte0) << 0); |
| |
| if (debug) |
| debugNumber(name, result, 2); |
| |
| return result; |
| } |
| |
| protected final int[] convertByteArrayToShortArray(String name, |
| byte bytes[], int start, int length, int byteOrder) |
| { |
| int expectedLength = start + length * 2; |
| |
| if (bytes.length < expectedLength) |
| { |
| System.out.println(name + ": expected length: " + expectedLength |
| + ", actual length: " + bytes.length); |
| return null; |
| } |
| |
| int result[] = new int[length]; |
| |
| for (int i = 0; i < length; i++) |
| { |
| result[i] = convertByteArrayToShort(name, start + i * 2, bytes, |
| byteOrder); |
| |
| // byte byte0 = bytes[start + i * 2]; |
| // byte byte1 = bytes[start + i * 2 + 1]; |
| // result[i] = convertBytesToShort(name, byte0, byte1, byteOrder); |
| } |
| |
| return result; |
| } |
| |
| public final byte[] readByteArray(String name, int length, String exception) |
| throws IOException |
| { |
| byte result[] = new byte[length]; |
| |
| int read = 0; |
| while (read < length) |
| { |
| int count = is.read(result, read, length - read); |
| if (count < 1) |
| throw new IOException(exception); |
| |
| read += count; |
| } |
| |
| if (debug) |
| { |
| for (int i = 0; ((i < length) && (i < 150)); i++) |
| { |
| debugNumber(name + " (" + i + ")", 0xff & result[i]); |
| } |
| } |
| return result; |
| } |
| |
| protected final void debugByteArray(String name, byte bytes[]) |
| { |
| System.out.println(name + ": " + bytes.length); |
| |
| for (int i = 0; ((i < bytes.length) && (i < 50)); i++) |
| { |
| debugNumber(name + " (" + i + ")", bytes[i]); |
| } |
| } |
| |
| protected final void debugNumberArray(String name, int numbers[], int length) |
| { |
| System.out.println(name + ": " + numbers.length); |
| |
| for (int i = 0; ((i < numbers.length) && (i < 50)); i++) |
| { |
| debugNumber(name + " (" + i + ")", numbers[i], length); |
| } |
| } |
| |
| public final byte[] readBytearray(String name, byte bytes[], int start, |
| int count) |
| { |
| if (bytes.length < (start + count)) |
| return null; |
| |
| byte result[] = new byte[count]; |
| System.arraycopy(bytes, start, result, 0, count); |
| |
| if (debug) |
| debugByteArray(name, result); |
| |
| return result; |
| } |
| |
| public final byte[] readByteArray(int length, String error) |
| throws ImageReadException, IOException |
| { |
| boolean verbose = false; |
| boolean strict = true; |
| return readByteArray(length, error, verbose, strict); |
| } |
| |
| public final byte[] readByteArray(int length, String error, |
| boolean verbose, boolean strict) throws ImageReadException, |
| IOException |
| { |
| byte bytes[] = new byte[length]; |
| int total = 0; |
| int read; |
| while ((read = read(bytes, total, length - total)) > 0) |
| total += read; |
| if (total < length) |
| { |
| if (strict) |
| throw new ImageReadException(error); |
| else if(verbose) |
| System.out.println(error); |
| return null; |
| } |
| return bytes; |
| } |
| |
| protected final byte[] getBytearrayTail(String name, byte bytes[], int count) |
| { |
| return readBytearray(name, bytes, count, bytes.length - count); |
| } |
| |
| protected final byte[] getBytearrayHead(String name, byte bytes[], int count) |
| { |
| return readBytearray(name, bytes, 0, bytes.length - count); |
| } |
| |
| public final boolean compareByteArrays(byte a[], int aStart, byte b[], |
| int bStart, int length) |
| { |
| if (a.length < (aStart + length)) |
| return false; |
| if (b.length < (bStart + length)) |
| return false; |
| |
| for (int i = 0; i < length; i++) |
| { |
| if (a[aStart + i] != b[bStart + i]) |
| { |
| debugNumber("a[" + (aStart + i) + "]", a[aStart + i]); |
| debugNumber("b[" + (bStart + i) + "]", b[bStart + i]); |
| |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| protected final int read4Bytes(String name, String exception, int byteOrder) |
| throws IOException |
| { |
| int size = 4; |
| byte bytes[] = new byte[size]; |
| |
| int read = 0; |
| while (read < size) |
| { |
| int count = is.read(bytes, read, size - read); |
| if (count < 1) |
| throw new IOException(exception); |
| |
| read += count; |
| } |
| |
| return convertByteArrayToInt(name, bytes, byteOrder); |
| } |
| |
| protected final int read3Bytes(String name, String exception, int byteOrder) |
| throws IOException |
| { |
| int size = 3; |
| byte bytes[] = new byte[size]; |
| |
| int read = 0; |
| while (read < size) |
| { |
| int count = is.read(bytes, read, size - read); |
| if (count < 1) |
| throw new IOException(exception); |
| |
| read += count; |
| } |
| |
| return convertByteArrayToInt(name, bytes, 0, 3, byteOrder); |
| |
| } |
| |
| protected final int read2Bytes(String name, String exception, int byteOrder) |
| throws IOException |
| { |
| int size = 2; |
| byte bytes[] = new byte[size]; |
| |
| int read = 0; |
| while (read < size) |
| { |
| int count = is.read(bytes, read, size - read); |
| if (count < 1) |
| throw new IOException(exception); |
| |
| read += count; |
| } |
| |
| return convertByteArrayToShort(name, bytes, byteOrder); |
| } |
| |
| public final int read1ByteInteger(String exception) |
| throws ImageReadException, IOException |
| { |
| int byte0 = is.read(); |
| if (byte0 < 0) |
| throw new ImageReadException(exception); |
| |
| return 0xff & byte0; |
| } |
| |
| public final int read2ByteInteger(String exception) |
| throws ImageReadException, IOException |
| { |
| int byte0 = is.read(); |
| int byte1 = is.read(); |
| if (byte0 < 0 || byte1 < 0) |
| throw new ImageReadException(exception); |
| |
| if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian |
| return ((0xff & byte0) << 8) + ((0xff & byte1) << 0); |
| else |
| // intel, little endian |
| return ((0xff & byte1) << 8) + ((0xff & byte0) << 0); |
| } |
| |
| public final int read4ByteInteger(String exception) |
| throws ImageReadException, IOException |
| { |
| int byte0 = is.read(); |
| int byte1 = is.read(); |
| int byte2 = is.read(); |
| int byte3 = is.read(); |
| if (byte0 < 0 || byte1 < 0 || byte2 < 0 || byte3 < 0) |
| throw new ImageReadException(exception); |
| |
| if (byteOrder == BYTE_ORDER_MOTOROLA) // motorola, big endian |
| return ((0xff & byte0) << 24) + ((0xff & byte1) << 16) |
| + ((0xff & byte2) << 8) + ((0xff & byte3) << 0); |
| else |
| // intel, little endian |
| return ((0xff & byte3) << 24) + ((0xff & byte2) << 16) |
| + ((0xff & byte1) << 8) + ((0xff & byte0) << 0); |
| } |
| |
| protected final void printCharQuad(String msg, int i) |
| { |
| System.out.println(msg + ": '" + (char) (0xff & (i >> 24)) |
| + (char) (0xff & (i >> 16)) + (char) (0xff & (i >> 8)) |
| + (char) (0xff & (i >> 0)) + "'"); |
| |
| } |
| |
| protected final void printByteBits(String msg, byte i) |
| { |
| System.out.println(msg + ": '" + Integer.toBinaryString(0xff & i)); |
| } |
| |
| protected final static int charsToQuad(char c1, char c2, char c3, char c4) |
| { |
| return (((0xff & c1) << 24) | ((0xff & c2) << 16) | ((0xff & c3) << 8) | ((0xff & c4) << 0)); |
| } |
| |
| public final int findNull(byte src[]) |
| { |
| return findNull(src, 0); |
| } |
| |
| public final int findNull(byte src[], int start) |
| { |
| for (int i = start; i < src.length; i++) |
| { |
| if (src[i] == 0) |
| return i; |
| |
| } |
| return -1; |
| } |
| |
| protected final byte[] getRAFBytes(RandomAccessFile raf, long pos, |
| int length, String exception) throws IOException |
| { |
| byte result[] = new byte[length]; |
| |
| if (debug) |
| { |
| System.out.println("getRAFBytes pos" + ": " + pos); |
| System.out.println("getRAFBytes length" + ": " + length); |
| } |
| |
| raf.seek(pos); |
| |
| int read = 0; |
| while (read < length) |
| { |
| int count = raf.read(result, read, length - read); |
| if (count < 1) |
| throw new IOException(exception); |
| |
| read += count; |
| } |
| |
| return result; |
| |
| } |
| |
| protected void skipBytes(int length) throws IOException |
| { |
| skipBytes(length, "Couldn't skip bytes"); |
| } |
| |
| } |