X-Git-Url: http://gitweb.fperrin.net/?p=GpsPrune.git;a=blobdiff_plain;f=tim%2Fprune%2Fjpeg%2Fdrew%2FByteArrayReader.java;fp=tim%2Fprune%2Fjpeg%2Fdrew%2FByteArrayReader.java;h=3b3d010e6eeb7154bd97849ea951e7c5e79fdac6;hp=0000000000000000000000000000000000000000;hb=92dad5df664287acb51728e9ea599f150765d34a;hpb=81843c3d8d0771bf00d0f26034a13aa515465c78 diff --git a/tim/prune/jpeg/drew/ByteArrayReader.java b/tim/prune/jpeg/drew/ByteArrayReader.java new file mode 100644 index 0000000..3b3d010 --- /dev/null +++ b/tim/prune/jpeg/drew/ByteArrayReader.java @@ -0,0 +1,224 @@ +/* + * Copyright 2002-2015 Drew Noakes + * + * More information about this project is available at: + * + * https://drewnoakes.com/code/exif/ + * https://github.com/drewnoakes/metadata-extractor + */ + +package tim.prune.jpeg.drew; + +import java.io.IOException; + + +/** + * Provides methods to read specific values from a byte array, + * with a consistent, checked exception structure for issues. + * + * @author Drew Noakes https://drewnoakes.com + */ +public class ByteArrayReader +{ + private final byte[] _buffer; + private boolean _isMotorolaByteOrder = true; + + public ByteArrayReader(byte[] buffer) + { + if (buffer == null) + throw new NullPointerException(); + + _buffer = buffer; + } + + public void setMotorolaByteOrder(boolean motorolaByteOrder) + { + _isMotorolaByteOrder = motorolaByteOrder; + } + + public long getLength() + { + return _buffer.length; + } + + protected byte getByte(int index) + { + return _buffer[index]; + } + + protected void validateIndex(int index, int bytesRequested) throws ExifException + { + if (!isValidIndex(index, bytesRequested)) + throw new ExifException("Invalid index " + index); + } + + private boolean isValidIndex(int index, int bytesRequested) + { + return bytesRequested >= 0 + && index >= 0 + && ((long)index + (long)bytesRequested) <= (long)_buffer.length; + } + + public byte[] getBytes(int index, int count) throws ExifException + { + validateIndex(index, count); + + byte[] bytes = new byte[count]; + System.arraycopy(_buffer, index, bytes, 0, count); + return bytes; + } + + /** + * Returns an unsigned 8-bit int calculated from one byte of data at the specified index. + * + * @param index position within the data buffer to read byte + * @return the 8 bit int value, between 0 and 255 + * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative + */ + public short getUInt8(int index) throws ExifException + { + validateIndex(index, 1); + + return (short) (getByte(index) & 0xFF); + } + + /** + * Returns a signed 8-bit int calculated from one byte of data at the specified index. + * + * @param index position within the data buffer to read byte + * @return the 8 bit int value, between 0x00 and 0xFF + * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative + */ + public byte getInt8(int index) throws ExifException + { + validateIndex(index, 1); + + return getByte(index); + } + + /** + * Returns an unsigned 16-bit int calculated from two bytes of data at the specified index. + * + * @param index position within the data buffer to read first byte + * @return the 16 bit int value, between 0x0000 and 0xFFFF + * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative + */ + public int getUInt16(int index) throws ExifException + { + validateIndex(index, 2); + + if (_isMotorolaByteOrder) { + // Motorola - MSB first + return (getByte(index ) << 8 & 0xFF00) | + (getByte(index + 1) & 0xFF); + } else { + // Intel ordering - LSB first + return (getByte(index + 1) << 8 & 0xFF00) | + (getByte(index ) & 0xFF); + } + } + + /** + * Returns a signed 16-bit int calculated from two bytes of data at the specified index (MSB, LSB). + * + * @param index position within the data buffer to read first byte + * @return the 16 bit int value, between 0x0000 and 0xFFFF + * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative + */ + public short getInt16(int index) throws ExifException + { + validateIndex(index, 2); + + if (_isMotorolaByteOrder) { + // Motorola - MSB first + return (short) (((short)getByte(index ) << 8 & (short)0xFF00) | + ((short)getByte(index + 1) & (short)0xFF)); + } else { + // Intel ordering - LSB first + return (short) (((short)getByte(index + 1) << 8 & (short)0xFF00) | + ((short)getByte(index ) & (short)0xFF)); + } + } + + /** + * Get a 32-bit unsigned integer from the buffer, returning it as a long. + * + * @param index position within the data buffer to read first byte + * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF + * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative + */ + public long getUInt32(int index) throws ExifException + { + validateIndex(index, 4); + + if (_isMotorolaByteOrder) { + // Motorola - MSB first (big endian) + return (((long)getByte(index )) << 24 & 0xFF000000L) | + (((long)getByte(index + 1)) << 16 & 0xFF0000L) | + (((long)getByte(index + 2)) << 8 & 0xFF00L) | + (((long)getByte(index + 3)) & 0xFFL); + } else { + // Intel ordering - LSB first (little endian) + return (((long)getByte(index + 3)) << 24 & 0xFF000000L) | + (((long)getByte(index + 2)) << 16 & 0xFF0000L) | + (((long)getByte(index + 1)) << 8 & 0xFF00L) | + (((long)getByte(index )) & 0xFFL); + } + } + + /** + * Returns a signed 32-bit integer from four bytes of data at the specified index the buffer. + * + * @param index position within the data buffer to read first byte + * @return the signed 32 bit int value, between 0x00000000 and 0xFFFFFFFF + * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative + */ + public int getInt32(int index) throws ExifException + { + validateIndex(index, 4); + + if (_isMotorolaByteOrder) { + // Motorola - MSB first (big endian) + return (getByte(index ) << 24 & 0xFF000000) | + (getByte(index + 1) << 16 & 0xFF0000) | + (getByte(index + 2) << 8 & 0xFF00) | + (getByte(index + 3) & 0xFF); + } else { + // Intel ordering - LSB first (little endian) + return (getByte(index + 3) << 24 & 0xFF000000) | + (getByte(index + 2) << 16 & 0xFF0000) | + (getByte(index + 1) << 8 & 0xFF00) | + (getByte(index ) & 0xFF); + } + } + + /** + * Creates a String from the _data buffer starting at the specified index, + * and ending where byte=='\0' or where length==maxLength. + * + * @param index The index within the buffer at which to start reading the string. + * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit, + * reading will stop and the string will be truncated to this length. + * @return The read string. + * @throws IOException The buffer does not contain enough bytes to satisfy this request. + */ + public String getNullTerminatedString(int index, int maxLengthBytes) throws ExifException + { + // NOTE currently only really suited to single-byte character strings + + byte[] bytes = getBytes(index, maxLengthBytes); + + // Count the number of non-null bytes + int length = 0; + while (length < bytes.length && bytes[length] != '\0') + length++; + + return new String(bytes, 0, length); + } + + public String getString(int index, int bytesRequested) throws ExifException + { + // TODO: validate index + return new String(getBytes(index, bytesRequested)); + } +}