]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/jpeg/drew/ByteArrayReader.java
Version 19, May 2018
[GpsPrune.git] / tim / prune / jpeg / drew / ByteArrayReader.java
1 /*
2  * Copyright 2002-2015 Drew Noakes
3  *
4  * More information about this project is available at:
5  *
6  *    https://drewnoakes.com/code/exif/
7  *    https://github.com/drewnoakes/metadata-extractor
8  */
9
10 package tim.prune.jpeg.drew;
11
12 import java.io.IOException;
13
14
15 /**
16  * Provides methods to read specific values from a byte array,
17  * with a consistent, checked exception structure for issues.
18  *
19  * @author Drew Noakes https://drewnoakes.com
20  */
21 public class ByteArrayReader
22 {
23         private final byte[] _buffer;
24         private boolean _isMotorolaByteOrder = true;
25
26         public ByteArrayReader(byte[] buffer)
27         {
28                 if (buffer == null)
29                         throw new NullPointerException();
30
31                 _buffer = buffer;
32         }
33
34         public void setMotorolaByteOrder(boolean motorolaByteOrder)
35         {
36                 _isMotorolaByteOrder = motorolaByteOrder;
37         }
38
39         public long getLength()
40         {
41                 return _buffer.length;
42         }
43
44         protected byte getByte(int index)
45         {
46                 return _buffer[index];
47         }
48
49         protected void validateIndex(int index, int bytesRequested) throws ExifException
50         {
51                 if (!isValidIndex(index, bytesRequested))
52                         throw new ExifException("Invalid index " + index);
53         }
54
55         private boolean isValidIndex(int index, int bytesRequested)
56         {
57                 return bytesRequested >= 0
58                         && index >= 0
59                         && ((long)index + (long)bytesRequested) <= (long)_buffer.length;
60         }
61
62         public byte[] getBytes(int index, int count) throws ExifException
63         {
64                 validateIndex(index, count);
65
66                 byte[] bytes = new byte[count];
67                 System.arraycopy(_buffer, index, bytes, 0, count);
68                 return bytes;
69         }
70
71         /**
72          * Returns an unsigned 8-bit int calculated from one byte of data at the specified index.
73          *
74          * @param index position within the data buffer to read byte
75          * @return the 8 bit int value, between 0 and 255
76          * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
77          */
78         public short getUInt8(int index) throws ExifException
79         {
80                 validateIndex(index, 1);
81
82                 return (short) (getByte(index) & 0xFF);
83         }
84
85         /**
86          * Returns a signed 8-bit int calculated from one byte of data at the specified index.
87          *
88          * @param index position within the data buffer to read byte
89          * @return the 8 bit int value, between 0x00 and 0xFF
90          * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
91          */
92         public byte getInt8(int index) throws ExifException
93         {
94                 validateIndex(index, 1);
95
96                 return getByte(index);
97         }
98
99         /**
100          * Returns an unsigned 16-bit int calculated from two bytes of data at the specified index.
101          *
102          * @param index position within the data buffer to read first byte
103          * @return the 16 bit int value, between 0x0000 and 0xFFFF
104          * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
105          */
106         public int getUInt16(int index) throws ExifException
107         {
108                 validateIndex(index, 2);
109
110                 if (_isMotorolaByteOrder) {
111                         // Motorola - MSB first
112                         return (getByte(index    ) << 8 & 0xFF00) |
113                                    (getByte(index + 1)      & 0xFF);
114                 } else {
115                         // Intel ordering - LSB first
116                         return (getByte(index + 1) << 8 & 0xFF00) |
117                                    (getByte(index    )      & 0xFF);
118                 }
119         }
120
121         /**
122          * Returns a signed 16-bit int calculated from two bytes of data at the specified index (MSB, LSB).
123          *
124          * @param index position within the data buffer to read first byte
125          * @return the 16 bit int value, between 0x0000 and 0xFFFF
126          * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
127          */
128         public short getInt16(int index) throws ExifException
129         {
130                 validateIndex(index, 2);
131
132                 if (_isMotorolaByteOrder) {
133                         // Motorola - MSB first
134                         return (short) (((short)getByte(index    ) << 8 & (short)0xFF00) |
135                                         ((short)getByte(index + 1)      & (short)0xFF));
136                 } else {
137                         // Intel ordering - LSB first
138                         return (short) (((short)getByte(index + 1) << 8 & (short)0xFF00) |
139                                         ((short)getByte(index    )      & (short)0xFF));
140                 }
141         }
142
143         /**
144          * Get a 32-bit unsigned integer from the buffer, returning it as a long.
145          *
146          * @param index position within the data buffer to read first byte
147          * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
148          * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
149          */
150         public long getUInt32(int index) throws ExifException
151         {
152                 validateIndex(index, 4);
153
154                 if (_isMotorolaByteOrder) {
155                         // Motorola - MSB first (big endian)
156                         return (((long)getByte(index    )) << 24 & 0xFF000000L) |
157                                    (((long)getByte(index + 1)) << 16 & 0xFF0000L) |
158                                    (((long)getByte(index + 2)) << 8  & 0xFF00L) |
159                                    (((long)getByte(index + 3))       & 0xFFL);
160                 } else {
161                         // Intel ordering - LSB first (little endian)
162                         return (((long)getByte(index + 3)) << 24 & 0xFF000000L) |
163                                    (((long)getByte(index + 2)) << 16 & 0xFF0000L) |
164                                    (((long)getByte(index + 1)) << 8  & 0xFF00L) |
165                                    (((long)getByte(index    ))       & 0xFFL);
166                 }
167         }
168
169         /**
170          * Returns a signed 32-bit integer from four bytes of data at the specified index the buffer.
171          *
172          * @param index position within the data buffer to read first byte
173          * @return the signed 32 bit int value, between 0x00000000 and 0xFFFFFFFF
174          * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
175          */
176         public int getInt32(int index) throws ExifException
177         {
178                 validateIndex(index, 4);
179
180                 if (_isMotorolaByteOrder) {
181                         // Motorola - MSB first (big endian)
182                         return (getByte(index    ) << 24 & 0xFF000000) |
183                                    (getByte(index + 1) << 16 & 0xFF0000) |
184                                    (getByte(index + 2) << 8  & 0xFF00) |
185                                    (getByte(index + 3)       & 0xFF);
186                 } else {
187                         // Intel ordering - LSB first (little endian)
188                         return (getByte(index + 3) << 24 & 0xFF000000) |
189                                    (getByte(index + 2) << 16 & 0xFF0000) |
190                                    (getByte(index + 1) << 8  & 0xFF00) |
191                                    (getByte(index    )       & 0xFF);
192                 }
193         }
194
195         /**
196          * Creates a String from the _data buffer starting at the specified index,
197          * and ending where <code>byte=='\0'</code> or where <code>length==maxLength</code>.
198          *
199          * @param index          The index within the buffer at which to start reading the string.
200          * @param maxLengthBytes The maximum number of bytes to read.  If a zero-byte is not reached within this limit,
201          *                       reading will stop and the string will be truncated to this length.
202          * @return The read string.
203          * @throws IOException The buffer does not contain enough bytes to satisfy this request.
204          */
205         public String getNullTerminatedString(int index, int maxLengthBytes) throws ExifException
206         {
207                 // NOTE currently only really suited to single-byte character strings
208
209                 byte[] bytes = getBytes(index, maxLengthBytes);
210
211                 // Count the number of non-null bytes
212                 int length = 0;
213                 while (length < bytes.length && bytes[length] != '\0')
214                         length++;
215
216                 return new String(bytes, 0, length);
217         }
218
219         public String getString(int index, int bytesRequested) throws ExifException
220         {
221                 // TODO: validate index
222                 return new String(getBytes(index, bytesRequested));
223         }
224 }