]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/jpeg/drew/ByteArrayReader.java
Version 19, May 2018
[GpsPrune.git] / tim / prune / jpeg / drew / ByteArrayReader.java
diff --git a/tim/prune/jpeg/drew/ByteArrayReader.java b/tim/prune/jpeg/drew/ByteArrayReader.java
new file mode 100644 (file)
index 0000000..3b3d010
--- /dev/null
@@ -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 <code>byte=='\0'</code> or where <code>length==maxLength</code>.
+        *
+        * @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));
+       }
+}