source: josm/trunk/src/com/drew/lang/SequentialReader.java@ 15217

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

see #17848 - update to metadata-extractor 2.12.0

File size: 14.3 KB
Line 
1/*
2 * Copyright 2002-2019 Drew Noakes and contributors
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 com.drew.lang.annotations.NotNull;
25import com.drew.lang.annotations.Nullable;
26import com.drew.metadata.StringValue;
27
28import java.io.EOFException;
29import java.io.IOException;
30import java.io.UnsupportedEncodingException;
31import java.nio.charset.Charset;
32
33/**
34 * @author Drew Noakes https://drewnoakes.com
35 */
36@SuppressWarnings("WeakerAccess")
37public abstract class SequentialReader
38{
39 // TODO review whether the masks are needed (in both this and RandomAccessReader)
40
41 private boolean _isMotorolaByteOrder = true;
42
43 public abstract long getPosition() throws IOException;
44
45 /**
46 * Gets the next byte in the sequence.
47 *
48 * @return The read byte value
49 */
50 public abstract byte getByte() throws IOException;
51
52 /**
53 * Returns the required number of bytes from the sequence.
54 *
55 * @param count The number of bytes to be returned
56 * @return The requested bytes
57 */
58 @NotNull
59 public abstract byte[] getBytes(int count) throws IOException;
60
61 /**
62 * Retrieves bytes, writing them into a caller-provided buffer.
63 * @param buffer The array to write bytes to.
64 * @param offset The starting position within buffer to write to.
65 * @param count The number of bytes to be written.
66 */
67 public abstract void getBytes(@NotNull byte[] buffer, int offset, int count) throws IOException;
68
69 /**
70 * Skips forward in the sequence. If the sequence ends, an {@link EOFException} is thrown.
71 *
72 * @param n the number of byte to skip. Must be zero or greater.
73 * @throws EOFException the end of the sequence is reached.
74 * @throws IOException an error occurred reading from the underlying source.
75 */
76 public abstract void skip(long n) throws IOException;
77
78 /**
79 * Skips forward in the sequence, returning a boolean indicating whether the skip succeeded, or whether the sequence ended.
80 *
81 * @param n the number of byte to skip. Must be zero or greater.
82 * @return a boolean indicating whether the skip succeeded, or whether the sequence ended.
83 * @throws IOException an error occurred reading from the underlying source.
84 */
85 public abstract boolean trySkip(long n) throws IOException;
86
87 /**
88 * Returns an estimate of the number of bytes that can be read (or skipped
89 * over) from this {@link SequentialReader} without blocking by the next
90 * invocation of a method for this input stream. A single read or skip of
91 * this many bytes will not block, but may read or skip fewer bytes.
92 * <p>
93 * Note that while some implementations of {@link SequentialReader} like
94 * {@link SequentialByteArrayReader} will return the total remaining number
95 * of bytes in the stream, others will not. It is never correct to use the
96 * return value of this method to allocate a buffer intended to hold all
97 * data in this stream.
98 *
99 * @return an estimate of the number of bytes that can be read (or skipped
100 * over) from this {@link SequentialReader} without blocking or
101 * {@code 0} when it reaches the end of the input stream.
102 */
103 public abstract int available();
104
105 /**
106 * Sets the endianness of this reader.
107 * <ul>
108 * <li><code>true</code> for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.</li>
109 * <li><code>false</code> for Intel (or little) endianness, with LSB before MSB.</li>
110 * </ul>
111 *
112 * @param motorolaByteOrder <code>true</code> for Motorola/big endian, <code>false</code> for Intel/little endian
113 */
114 public void setMotorolaByteOrder(boolean motorolaByteOrder)
115 {
116 _isMotorolaByteOrder = motorolaByteOrder;
117 }
118
119 /**
120 * Gets the endianness of this reader.
121 * <ul>
122 * <li><code>true</code> for Motorola (or big) endianness (also known as network byte order), with MSB before LSB.</li>
123 * <li><code>false</code> for Intel (or little) endianness, with LSB before MSB.</li>
124 * </ul>
125 */
126 public boolean isMotorolaByteOrder()
127 {
128 return _isMotorolaByteOrder;
129 }
130
131 /**
132 * Returns an unsigned 8-bit int calculated from the next byte of the sequence.
133 *
134 * @return the 8 bit int value, between 0 and 255
135 */
136 public short getUInt8() throws IOException
137 {
138 return (short) (getByte() & 0xFF);
139 }
140
141 /**
142 * Returns a signed 8-bit int calculated from the next byte the sequence.
143 *
144 * @return the 8 bit int value, between 0x00 and 0xFF
145 */
146 public byte getInt8() throws IOException
147 {
148 return getByte();
149 }
150
151 /**
152 * Returns an unsigned 16-bit int calculated from the next two bytes of the sequence.
153 *
154 * @return the 16 bit int value, between 0x0000 and 0xFFFF
155 */
156 public int getUInt16() throws IOException
157 {
158 if (_isMotorolaByteOrder) {
159 // Motorola - MSB first
160 return (getByte() << 8 & 0xFF00) |
161 (getByte() & 0xFF);
162 } else {
163 // Intel ordering - LSB first
164 return (getByte() & 0xFF) |
165 (getByte() << 8 & 0xFF00);
166 }
167 }
168
169 /**
170 * Returns a signed 16-bit int calculated from two bytes of data (MSB, LSB).
171 *
172 * @return the 16 bit int value, between 0x0000 and 0xFFFF
173 * @throws IOException the buffer does not contain enough bytes to service the request
174 */
175 public short getInt16() throws IOException
176 {
177 if (_isMotorolaByteOrder) {
178 // Motorola - MSB first
179 return (short) (((short)getByte() << 8 & (short)0xFF00) |
180 ((short)getByte() & (short)0xFF));
181 } else {
182 // Intel ordering - LSB first
183 return (short) (((short)getByte() & (short)0xFF) |
184 ((short)getByte() << 8 & (short)0xFF00));
185 }
186 }
187
188 /**
189 * Get a 32-bit unsigned integer from the buffer, returning it as a long.
190 *
191 * @return the unsigned 32-bit int value as a long, between 0x00000000 and 0xFFFFFFFF
192 * @throws IOException the buffer does not contain enough bytes to service the request
193 */
194 public long getUInt32() throws IOException
195 {
196 if (_isMotorolaByteOrder) {
197 // Motorola - MSB first (big endian)
198 return (((long)getByte()) << 24 & 0xFF000000L) |
199 (((long)getByte()) << 16 & 0xFF0000L) |
200 (((long)getByte()) << 8 & 0xFF00L) |
201 (((long)getByte()) & 0xFFL);
202 } else {
203 // Intel ordering - LSB first (little endian)
204 return (((long)getByte()) & 0xFFL) |
205 (((long)getByte()) << 8 & 0xFF00L) |
206 (((long)getByte()) << 16 & 0xFF0000L) |
207 (((long)getByte()) << 24 & 0xFF000000L);
208 }
209 }
210
211 /**
212 * Returns a signed 32-bit integer from four bytes of data.
213 *
214 * @return the signed 32 bit int value, between 0x00000000 and 0xFFFFFFFF
215 * @throws IOException the buffer does not contain enough bytes to service the request
216 */
217 public int getInt32() throws IOException
218 {
219 if (_isMotorolaByteOrder) {
220 // Motorola - MSB first (big endian)
221 return (getByte() << 24 & 0xFF000000) |
222 (getByte() << 16 & 0xFF0000) |
223 (getByte() << 8 & 0xFF00) |
224 (getByte() & 0xFF);
225 } else {
226 // Intel ordering - LSB first (little endian)
227 return (getByte() & 0xFF) |
228 (getByte() << 8 & 0xFF00) |
229 (getByte() << 16 & 0xFF0000) |
230 (getByte() << 24 & 0xFF000000);
231 }
232 }
233
234 /**
235 * Get a signed 64-bit integer from the buffer.
236 *
237 * @return the 64 bit int value, between 0x0000000000000000 and 0xFFFFFFFFFFFFFFFF
238 * @throws IOException the buffer does not contain enough bytes to service the request
239 */
240 public long getInt64() throws IOException
241 {
242 if (_isMotorolaByteOrder) {
243 // Motorola - MSB first
244 return ((long)getByte() << 56 & 0xFF00000000000000L) |
245 ((long)getByte() << 48 & 0xFF000000000000L) |
246 ((long)getByte() << 40 & 0xFF0000000000L) |
247 ((long)getByte() << 32 & 0xFF00000000L) |
248 ((long)getByte() << 24 & 0xFF000000L) |
249 ((long)getByte() << 16 & 0xFF0000L) |
250 ((long)getByte() << 8 & 0xFF00L) |
251 ((long)getByte() & 0xFFL);
252 } else {
253 // Intel ordering - LSB first
254 return ((long)getByte() & 0xFFL) |
255 ((long)getByte() << 8 & 0xFF00L) |
256 ((long)getByte() << 16 & 0xFF0000L) |
257 ((long)getByte() << 24 & 0xFF000000L) |
258 ((long)getByte() << 32 & 0xFF00000000L) |
259 ((long)getByte() << 40 & 0xFF0000000000L) |
260 ((long)getByte() << 48 & 0xFF000000000000L) |
261 ((long)getByte() << 56 & 0xFF00000000000000L);
262 }
263 }
264
265 /**
266 * Gets a s15.16 fixed point float from the buffer.
267 * <p>
268 * This particular fixed point encoding has one sign bit, 15 numerator bits and 16 denominator bits.
269 *
270 * @return the floating point value
271 * @throws IOException the buffer does not contain enough bytes to service the request
272 */
273 public float getS15Fixed16() throws IOException
274 {
275 if (_isMotorolaByteOrder) {
276 float res = (getByte() & 0xFF) << 8 |
277 (getByte() & 0xFF);
278 int d = (getByte() & 0xFF) << 8 |
279 (getByte() & 0xFF);
280 return (float)(res + d/65536.0);
281 } else {
282 // this particular branch is untested
283 int d = (getByte() & 0xFF) |
284 (getByte() & 0xFF) << 8;
285 float res = (getByte() & 0xFF) |
286 (getByte() & 0xFF) << 8;
287 return (float)(res + d/65536.0);
288 }
289 }
290
291 public float getFloat32() throws IOException
292 {
293 return Float.intBitsToFloat(getInt32());
294 }
295
296 public double getDouble64() throws IOException
297 {
298 return Double.longBitsToDouble(getInt64());
299 }
300
301 @NotNull
302 public String getString(int bytesRequested) throws IOException
303 {
304 return new String(getBytes(bytesRequested));
305 }
306
307 @NotNull
308 public String getString(int bytesRequested, String charset) throws IOException
309 {
310 byte[] bytes = getBytes(bytesRequested);
311 try {
312 return new String(bytes, charset);
313 } catch (UnsupportedEncodingException e) {
314 return new String(bytes);
315 }
316 }
317
318 @NotNull
319 public String getString(int bytesRequested, @NotNull Charset charset) throws IOException
320 {
321 byte[] bytes = getBytes(bytesRequested);
322 return new String(bytes, charset);
323 }
324
325 @NotNull
326 public StringValue getStringValue(int bytesRequested, @Nullable Charset charset) throws IOException
327 {
328 return new StringValue(getBytes(bytesRequested), charset);
329 }
330
331 /**
332 * Creates a String from the stream, ending where <code>byte=='\0'</code> or where <code>length==maxLength</code>.
333 *
334 * @param maxLengthBytes The maximum number of bytes to read. If a zero-byte is not reached within this limit,
335 * reading will stop and the string will be truncated to this length.
336 * @return The read string.
337 * @throws IOException The buffer does not contain enough bytes to satisfy this request.
338 */
339 @NotNull
340 public String getNullTerminatedString(int maxLengthBytes, Charset charset) throws IOException
341 {
342 return getNullTerminatedStringValue(maxLengthBytes, charset).toString();
343 }
344
345 /**
346 * Creates a String from the stream, ending where <code>byte=='\0'</code> or where <code>length==maxLength</code>.
347 *
348 * @param maxLengthBytes The maximum number of bytes to read. If a <code>\0</code> byte is not reached within this limit,
349 * reading will stop and the string will be truncated to this length.
350 * @param charset The <code>Charset</code> to register with the returned <code>StringValue</code>, or <code>null</code> if the encoding
351 * is unknown
352 * @return The read string.
353 * @throws IOException The buffer does not contain enough bytes to satisfy this request.
354 */
355 @NotNull
356 public StringValue getNullTerminatedStringValue(int maxLengthBytes, Charset charset) throws IOException
357 {
358 byte[] bytes = getNullTerminatedBytes(maxLengthBytes);
359
360 return new StringValue(bytes, charset);
361 }
362
363 /**
364 * Returns the sequence of bytes punctuated by a <code>\0</code> value.
365 *
366 * @param maxLengthBytes The maximum number of bytes to read. If a <code>\0</code> byte is not reached within this limit,
367 * the returned array will be <code>maxLengthBytes</code> long.
368 * @return The read byte array, excluding the null terminator.
369 * @throws IOException The buffer does not contain enough bytes to satisfy this request.
370 */
371 @NotNull
372 public byte[] getNullTerminatedBytes(int maxLengthBytes) throws IOException
373 {
374 byte[] buffer = new byte[maxLengthBytes];
375
376 // Count the number of non-null bytes
377 int length = 0;
378 while (length < buffer.length && (buffer[length] = getByte()) != 0)
379 length++;
380
381 if (length == maxLengthBytes)
382 return buffer;
383
384 byte[] bytes = new byte[length];
385 if (length > 0)
386 System.arraycopy(buffer, 0, bytes, 0, length);
387 return bytes;
388 }
389}
Note: See TracBrowser for help on using the repository browser.