source: josm/trunk/src/com/drew/lang/RandomAccessReader.java@ 13061

Last change on this file since 13061 was 13061, checked in by Don-vip, 6 years ago

fix #15505 - update to metadata-extractor 2.10.1

File size: 17.3 KB
Line 
1/*
2 * Copyright 2002-2017 Drew Noakes
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * More information about this project is available at:
17 *
18 * https://drewnoakes.com/code/exif/
19 * https://github.com/drewnoakes/metadata-extractor
20 */
21
22package com.drew.lang;
23
24import java.io.IOException;
25import java.io.UnsupportedEncodingException;
26import java.nio.charset.Charset;
27
28import com.drew.lang.annotations.NotNull;
29import com.drew.lang.annotations.Nullable;
30import com.drew.metadata.StringValue;
31
32/**
33 * Base class for random access data reading operations of common data types.
34 * <p>
35 * By default, the reader operates with Motorola byte order (big endianness). This can be changed by calling
36 * {@link com.drew.lang.RandomAccessReader#setMotorolaByteOrder(boolean)}.
37 * <p>
38 * Concrete implementations include:
39 * <ul>
40 * <li>{@link ByteArrayReader}</li>
41 * </ul>
42 *
43 * @author Drew Noakes https://drewnoakes.com
44 */
45public abstract class RandomAccessReader
46{
47 private boolean _isMotorolaByteOrder = true;
48
49 public abstract int toUnshiftedOffset(int localOffset);
50
51 /**
52 * Gets the byte value at the specified byte <code>index</code>.
53 * <p>
54 * Implementations should not perform any bounds checking in this method. That should be performed
55 * in <code>validateIndex</code> and <code>isValidIndex</code>.
56 *
57 * @param index The index from which to read the byte
58 * @return The read byte value
59 * @throws IllegalArgumentException <code>index</code> is negative
60 * @throws BufferBoundsException if the requested byte is beyond the end of the underlying data source
61 * @throws IOException if the byte is unable to be read
62 */
63 public abstract byte getByte(int index) throws IOException;
64
65 /**
66 * Returns the required number of bytes from the specified index from the underlying source.
67 *
68 * @param index The index from which the bytes begins in the underlying source
69 * @param count The number of bytes to be returned
70 * @return The requested bytes
71 * @throws IllegalArgumentException <code>index</code> or <code>count</code> are negative
72 * @throws BufferBoundsException if the requested bytes extend beyond the end of the underlying data source
73 * @throws IOException if the byte is unable to be read
74 */
75 @NotNull
76 public abstract byte[] getBytes(int index, int count) throws IOException;
77
78 /**
79 * Ensures that the buffered bytes extend to cover the specified index. If not, an attempt is made
80 * to read to that point.
81 * <p>
82 * If the stream ends before the point is reached, a {@link BufferBoundsException} is raised.
83 *
84 * @param index the index from which the required bytes start
85 * @param bytesRequested the number of bytes which are required
86 * @throws IOException if the stream ends before the required number of bytes are acquired
87 */
88 protected abstract void validateIndex(int index, int bytesRequested) throws IOException;
89
90 protected abstract boolean isValidIndex(int index, int bytesRequested) throws IOException;
91
92 /**
93 * Returns the length of the data source in bytes.
94 * <p>
95 * This is a simple operation for implementations (such as
96 * {@link ByteArrayReader}) that have the entire data source available.
97 * <p>
98 * Users of this method must be aware that sequentially accessed implementations
99 * will have to read and buffer the entire data source in
100 * order to determine the length.
101 *
102 * @return the length of the data source, in bytes.
103 */
104 public abstract long getLength() throws IOException;
105
106 /**
107 * Sets the endianness of this reader.
108 * <ul>
109 * <li><code>true</code> for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.</li>
110 * <li><code>false</code> for Intel (or little) endianness, with LSB before MSB.</li>
111 * </ul>
112 *
113 * @param motorolaByteOrder <code>true</code> for Motorola/big endian, <code>false</code> for Intel/little endian
114 */
115 public void setMotorolaByteOrder(boolean motorolaByteOrder)
116 {
117 _isMotorolaByteOrder = motorolaByteOrder;
118 }
119
120 /**
121 * Gets the endianness of this reader.
122 * <ul>
123 * <li><code>true</code> for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.</li>
124 * <li><code>false</code> for Intel (or little) endianness, with LSB before MSB.</li>
125 * </ul>
126 */
127 public boolean isMotorolaByteOrder()
128 {
129 return _isMotorolaByteOrder;
130 }
131
132 /**
133 * Gets whether a bit at a specific index is set or not.
134 *
135 * @param index the number of bits at which to test
136 * @return true if the bit is set, otherwise false
137 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
138 */
139 public boolean getBit(int index) throws IOException
140 {
141 int byteIndex = index / 8;
142 int bitIndex = index % 8;
143
144 validateIndex(byteIndex, 1);
145
146 byte b = getByte(byteIndex);
147 return ((b >> bitIndex) & 1) == 1;
148 }
149
150 /**
151 * Returns an unsigned 8-bit int calculated from one byte of data at the specified index.
152 *
153 * @param index position within the data buffer to read byte
154 * @return the 8 bit int value, between 0 and 255
155 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
156 */
157 public short getUInt8(int index) throws IOException
158 {
159 validateIndex(index, 1);
160
161 return (short) (getByte(index) & 0xFF);
162 }
163
164 /**
165 * Returns a signed 8-bit int calculated from one byte of data at the specified index.
166 *
167 * @param index position within the data buffer to read byte
168 * @return the 8 bit int value, between 0x00 and 0xFF
169 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
170 */
171 public byte getInt8(int index) throws IOException
172 {
173 validateIndex(index, 1);
174
175 return getByte(index);
176 }
177
178 /**
179 * Returns an unsigned 16-bit int calculated from two bytes of data at the specified index.
180 *
181 * @param index position within the data buffer to read first byte
182 * @return the 16 bit int value, between 0x0000 and 0xFFFF
183 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
184 */
185 public int getUInt16(int index) throws IOException
186 {
187 validateIndex(index, 2);
188
189 if (_isMotorolaByteOrder) {
190 // Motorola - MSB first
191 return (getByte(index ) << 8 & 0xFF00) |
192 (getByte(index + 1) & 0xFF);
193 } else {
194 // Intel ordering - LSB first
195 return (getByte(index + 1) << 8 & 0xFF00) |
196 (getByte(index ) & 0xFF);
197 }
198 }
199
200 /**
201 * Returns a signed 16-bit int calculated from two bytes of data at the specified index (MSB, LSB).
202 *
203 * @param index position within the data buffer to read first byte
204 * @return the 16 bit int value, between 0x0000 and 0xFFFF
205 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
206 */
207 public short getInt16(int index) throws IOException
208 {
209 validateIndex(index, 2);
210
211 if (_isMotorolaByteOrder) {
212 // Motorola - MSB first
213 return (short) ((getByte(index ) << 8 & (short)0xFF00) |
214 (getByte(index + 1) & (short)0xFF));
215 } else {
216 // Intel ordering - LSB first
217 return (short) ((getByte(index + 1) << 8 & (short)0xFF00) |
218 (getByte(index ) & (short)0xFF));
219 }
220 }
221
222 /**
223 * Get a 24-bit unsigned integer from the buffer, returning it as an int.
224 *
225 * @param index position within the data buffer to read first byte
226 * @return the unsigned 24-bit int value as a long, between 0x00000000 and 0x00FFFFFF
227 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
228 */
229 public int getInt24(int index) throws IOException
230 {
231 validateIndex(index, 3);
232
233 if (_isMotorolaByteOrder) {
234 // Motorola - MSB first (big endian)
235 return ((getByte(index )) << 16 & 0xFF0000) |
236 ((getByte(index + 1)) << 8 & 0xFF00) |
237 ((getByte(index + 2)) & 0xFF);
238 } else {
239 // Intel ordering - LSB first (little endian)
240 return ((getByte(index + 2)) << 16 & 0xFF0000) |
241 ((getByte(index + 1)) << 8 & 0xFF00) |
242 ((getByte(index )) & 0xFF);
243 }
244 }
245
246 /**
247 * Get a 32-bit unsigned integer from the buffer, returning it as a long.
248 *
249 * @param index position within the data buffer to read first byte
250 * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
251 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
252 */
253 public long getUInt32(int index) throws IOException
254 {
255 validateIndex(index, 4);
256
257 if (_isMotorolaByteOrder) {
258 // Motorola - MSB first (big endian)
259 return (((long)getByte(index )) << 24 & 0xFF000000L) |
260 (((long)getByte(index + 1)) << 16 & 0xFF0000L) |
261 (((long)getByte(index + 2)) << 8 & 0xFF00L) |
262 ((getByte(index + 3)) & 0xFFL);
263 } else {
264 // Intel ordering - LSB first (little endian)
265 return (((long)getByte(index + 3)) << 24 & 0xFF000000L) |
266 (((long)getByte(index + 2)) << 16 & 0xFF0000L) |
267 (((long)getByte(index + 1)) << 8 & 0xFF00L) |
268 ((getByte(index )) & 0xFFL);
269 }
270 }
271
272 /**
273 * Returns a signed 32-bit integer from four bytes of data at the specified index the buffer.
274 *
275 * @param index position within the data buffer to read first byte
276 * @return the signed 32 bit int value, between 0x00000000 and 0xFFFFFFFF
277 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
278 */
279 public int getInt32(int index) throws IOException
280 {
281 validateIndex(index, 4);
282
283 if (_isMotorolaByteOrder) {
284 // Motorola - MSB first (big endian)
285 return (getByte(index ) << 24 & 0xFF000000) |
286 (getByte(index + 1) << 16 & 0xFF0000) |
287 (getByte(index + 2) << 8 & 0xFF00) |
288 (getByte(index + 3) & 0xFF);
289 } else {
290 // Intel ordering - LSB first (little endian)
291 return (getByte(index + 3) << 24 & 0xFF000000) |
292 (getByte(index + 2) << 16 & 0xFF0000) |
293 (getByte(index + 1) << 8 & 0xFF00) |
294 (getByte(index ) & 0xFF);
295 }
296 }
297
298 /**
299 * Get a signed 64-bit integer from the buffer.
300 *
301 * @param index position within the data buffer to read first byte
302 * @return the 64 bit int value, between 0x0000000000000000 and 0xFFFFFFFFFFFFFFFF
303 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
304 */
305 public long getInt64(int index) throws IOException
306 {
307 validateIndex(index, 8);
308
309 if (_isMotorolaByteOrder) {
310 // Motorola - MSB first
311 return ((long)getByte(index ) << 56 & 0xFF00000000000000L) |
312 ((long)getByte(index + 1) << 48 & 0xFF000000000000L) |
313 ((long)getByte(index + 2) << 40 & 0xFF0000000000L) |
314 ((long)getByte(index + 3) << 32 & 0xFF00000000L) |
315 ((long)getByte(index + 4) << 24 & 0xFF000000L) |
316 ((long)getByte(index + 5) << 16 & 0xFF0000L) |
317 ((long)getByte(index + 6) << 8 & 0xFF00L) |
318 (getByte(index + 7) & 0xFFL);
319 } else {
320 // Intel ordering - LSB first
321 return ((long)getByte(index + 7) << 56 & 0xFF00000000000000L) |
322 ((long)getByte(index + 6) << 48 & 0xFF000000000000L) |
323 ((long)getByte(index + 5) << 40 & 0xFF0000000000L) |
324 ((long)getByte(index + 4) << 32 & 0xFF00000000L) |
325 ((long)getByte(index + 3) << 24 & 0xFF000000L) |
326 ((long)getByte(index + 2) << 16 & 0xFF0000L) |
327 ((long)getByte(index + 1) << 8 & 0xFF00L) |
328 (getByte(index ) & 0xFFL);
329 }
330 }
331
332 /**
333 * Gets a s15.16 fixed point float from the buffer.
334 * <p>
335 * This particular fixed point encoding has one sign bit, 15 numerator bits and 16 denominator bits.
336 *
337 * @return the floating point value
338 * @throws IOException the buffer does not contain enough bytes to service the request, or index is negative
339 */
340 public float getS15Fixed16(int index) throws IOException
341 {
342 validateIndex(index, 4);
343
344 if (_isMotorolaByteOrder) {
345 float res = (getByte(index ) & 0xFF) << 8 |
346 (getByte(index + 1) & 0xFF);
347 int d = (getByte(index + 2) & 0xFF) << 8 |
348 (getByte(index + 3) & 0xFF);
349 return (float)(res + d/65536.0);
350 } else {
351 // this particular branch is untested
352 float res = (getByte(index + 3) & 0xFF) << 8 |
353 (getByte(index + 2) & 0xFF);
354 int d = (getByte(index + 1) & 0xFF) << 8 |
355 (getByte(index ) & 0xFF);
356 return (float)(res + d/65536.0);
357 }
358 }
359
360 public float getFloat32(int index) throws IOException
361 {
362 return Float.intBitsToFloat(getInt32(index));
363 }
364
365 public double getDouble64(int index) throws IOException
366 {
367 return Double.longBitsToDouble(getInt64(index));
368 }
369
370 @NotNull
371 public StringValue getStringValue(int index, int bytesRequested, @Nullable Charset charset) throws IOException
372 {
373 return new StringValue(getBytes(index, bytesRequested), charset);
374 }
375
376 @NotNull
377 public String getString(int index, int bytesRequested, @NotNull Charset charset) throws IOException
378 {
379 return new String(getBytes(index, bytesRequested), charset.name());
380 }
381
382 @NotNull
383 public String getString(int index, int bytesRequested, @NotNull String charset) throws IOException
384 {
385 byte[] bytes = getBytes(index, bytesRequested);
386 try {
387 return new String(bytes, charset);
388 } catch (UnsupportedEncodingException e) {
389 return new String(bytes);
390 }
391 }
392
393 /**
394 * Creates a String from the _data buffer starting at the specified index,
395 * and ending where <code>byte=='\0'</code> or where <code>length==maxLength</code>.
396 *
397 * @param index The index within the buffer at which to start reading the string.
398 * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit,
399 * reading will stop and the string will be truncated to this length.
400 * @return The read string.
401 * @throws IOException The buffer does not contain enough bytes to satisfy this request.
402 */
403 @NotNull
404 public String getNullTerminatedString(int index, int maxLengthBytes, @NotNull Charset charset) throws IOException
405 {
406 return new String(getNullTerminatedBytes(index, maxLengthBytes), charset.name());
407 }
408
409 @NotNull
410 public StringValue getNullTerminatedStringValue(int index, int maxLengthBytes, @Nullable Charset charset) throws IOException
411 {
412 byte[] bytes = getNullTerminatedBytes(index, maxLengthBytes);
413
414 return new StringValue(bytes, charset);
415 }
416
417 /**
418 * Returns the sequence of bytes punctuated by a <code>\0</code> value.
419 *
420 * @param index The index within the buffer at which to start reading the string.
421 * @param maxLengthBytes The maximum number of bytes to read. If a <code>\0</code> byte is not reached within this limit,
422 * the returned array will be <code>maxLengthBytes</code> long.
423 * @return The read byte array, excluding the null terminator.
424 * @throws IOException The buffer does not contain enough bytes to satisfy this request.
425 */
426 @NotNull
427 public byte[] getNullTerminatedBytes(int index, int maxLengthBytes) throws IOException
428 {
429 byte[] buffer = getBytes(index, maxLengthBytes);
430
431 // Count the number of non-null bytes
432 int length = 0;
433 while (length < buffer.length && buffer[length] != 0)
434 length++;
435
436 if (length == maxLengthBytes)
437 return buffer;
438
439 byte[] bytes = new byte[length];
440 if (length > 0)
441 System.arraycopy(buffer, 0, bytes, 0, length);
442 return bytes;
443 }
444}
Note: See TracBrowser for help on using the repository browser.