1 | /*
|
---|
2 | * Copyright 2002-2012 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 | * http://drewnoakes.com/code/exif/
|
---|
19 | * http://code.google.com/p/metadata-extractor/
|
---|
20 | */
|
---|
21 |
|
---|
22 | package com.drew.lang;
|
---|
23 |
|
---|
24 | import com.drew.lang.annotations.NotNull;
|
---|
25 |
|
---|
26 | import java.io.UnsupportedEncodingException;
|
---|
27 |
|
---|
28 | /**
|
---|
29 | * Provides methods to read specific values from a byte array, with a consistent, checked exception structure for
|
---|
30 | * issues.
|
---|
31 | * <p/>
|
---|
32 | * By default, the reader operates with Motorola byte order (big endianness). This can be changed by calling
|
---|
33 | * {@see setMotorolaByteOrder(boolean)}.
|
---|
34 | *
|
---|
35 | * @author Drew Noakes http://drewnoakes.com
|
---|
36 | * */
|
---|
37 | public class ByteArrayReader implements BufferReader
|
---|
38 | {
|
---|
39 | @NotNull
|
---|
40 | private final byte[] _buffer;
|
---|
41 | private boolean _isMotorolaByteOrder = true;
|
---|
42 |
|
---|
43 | @SuppressWarnings({ "ConstantConditions" })
|
---|
44 | @com.drew.lang.annotations.SuppressWarnings(value = "EI_EXPOSE_REP2", justification = "Design intent")
|
---|
45 | public ByteArrayReader(@NotNull byte[] buffer)
|
---|
46 | {
|
---|
47 | if (buffer == null)
|
---|
48 | throw new NullPointerException();
|
---|
49 |
|
---|
50 | _buffer = buffer;
|
---|
51 | }
|
---|
52 |
|
---|
53 | @Override
|
---|
54 | public long getLength()
|
---|
55 | {
|
---|
56 | return _buffer.length;
|
---|
57 | }
|
---|
58 |
|
---|
59 |
|
---|
60 | @Override
|
---|
61 | public void setMotorolaByteOrder(boolean motorolaByteOrder)
|
---|
62 | {
|
---|
63 | _isMotorolaByteOrder = motorolaByteOrder;
|
---|
64 | }
|
---|
65 |
|
---|
66 | @Override
|
---|
67 | public boolean isMotorolaByteOrder()
|
---|
68 | {
|
---|
69 | return _isMotorolaByteOrder;
|
---|
70 | }
|
---|
71 |
|
---|
72 | @Override
|
---|
73 | public short getUInt8(int index) throws BufferBoundsException
|
---|
74 | {
|
---|
75 | checkBounds(index, 1);
|
---|
76 |
|
---|
77 | return (short) (_buffer[index] & 255);
|
---|
78 | }
|
---|
79 |
|
---|
80 | @Override
|
---|
81 | public byte getInt8(int index) throws BufferBoundsException
|
---|
82 | {
|
---|
83 | checkBounds(index, 1);
|
---|
84 |
|
---|
85 | return _buffer[index];
|
---|
86 | }
|
---|
87 |
|
---|
88 | @Override
|
---|
89 | public int getUInt16(int index) throws BufferBoundsException
|
---|
90 | {
|
---|
91 | checkBounds(index, 2);
|
---|
92 |
|
---|
93 | if (_isMotorolaByteOrder) {
|
---|
94 | // Motorola - MSB first
|
---|
95 | return (_buffer[index ] << 8 & 0xFF00) |
|
---|
96 | (_buffer[index + 1] & 0xFF);
|
---|
97 | } else {
|
---|
98 | // Intel ordering - LSB first
|
---|
99 | return (_buffer[index + 1] << 8 & 0xFF00) |
|
---|
100 | (_buffer[index ] & 0xFF);
|
---|
101 | }
|
---|
102 | }
|
---|
103 |
|
---|
104 | @Override
|
---|
105 | public short getInt16(int index) throws BufferBoundsException
|
---|
106 | {
|
---|
107 | checkBounds(index, 2);
|
---|
108 |
|
---|
109 | if (_isMotorolaByteOrder) {
|
---|
110 | // Motorola - MSB first
|
---|
111 | return (short) (((short)_buffer[index ] << 8 & (short)0xFF00) |
|
---|
112 | ((short)_buffer[index + 1] & (short)0xFF));
|
---|
113 | } else {
|
---|
114 | // Intel ordering - LSB first
|
---|
115 | return (short) (((short)_buffer[index + 1] << 8 & (short)0xFF00) |
|
---|
116 | ((short)_buffer[index ] & (short)0xFF));
|
---|
117 | }
|
---|
118 | }
|
---|
119 |
|
---|
120 | @Override
|
---|
121 | public long getUInt32(int index) throws BufferBoundsException
|
---|
122 | {
|
---|
123 | checkBounds(index, 4);
|
---|
124 |
|
---|
125 | if (_isMotorolaByteOrder) {
|
---|
126 | // Motorola - MSB first (big endian)
|
---|
127 | return (((long)_buffer[index ]) << 24 & 0xFF000000L) |
|
---|
128 | (((long)_buffer[index + 1]) << 16 & 0xFF0000L) |
|
---|
129 | (((long)_buffer[index + 2]) << 8 & 0xFF00L) |
|
---|
130 | (((long)_buffer[index + 3]) & 0xFFL);
|
---|
131 | } else {
|
---|
132 | // Intel ordering - LSB first (little endian)
|
---|
133 | return (((long)_buffer[index + 3]) << 24 & 0xFF000000L) |
|
---|
134 | (((long)_buffer[index + 2]) << 16 & 0xFF0000L) |
|
---|
135 | (((long)_buffer[index + 1]) << 8 & 0xFF00L) |
|
---|
136 | (((long)_buffer[index ]) & 0xFFL);
|
---|
137 | }
|
---|
138 | }
|
---|
139 |
|
---|
140 | @Override
|
---|
141 | public int getInt32(int index) throws BufferBoundsException
|
---|
142 | {
|
---|
143 | checkBounds(index, 4);
|
---|
144 |
|
---|
145 | if (_isMotorolaByteOrder) {
|
---|
146 | // Motorola - MSB first (big endian)
|
---|
147 | return (_buffer[index ] << 24 & 0xFF000000) |
|
---|
148 | (_buffer[index + 1] << 16 & 0xFF0000) |
|
---|
149 | (_buffer[index + 2] << 8 & 0xFF00) |
|
---|
150 | (_buffer[index + 3] & 0xFF);
|
---|
151 | } else {
|
---|
152 | // Intel ordering - LSB first (little endian)
|
---|
153 | return (_buffer[index + 3] << 24 & 0xFF000000) |
|
---|
154 | (_buffer[index + 2] << 16 & 0xFF0000) |
|
---|
155 | (_buffer[index + 1] << 8 & 0xFF00) |
|
---|
156 | (_buffer[index ] & 0xFF);
|
---|
157 | }
|
---|
158 | }
|
---|
159 |
|
---|
160 | @Override
|
---|
161 | public long getInt64(int index) throws BufferBoundsException
|
---|
162 | {
|
---|
163 | checkBounds(index, 8);
|
---|
164 |
|
---|
165 | if (_isMotorolaByteOrder) {
|
---|
166 | // Motorola - MSB first
|
---|
167 | return ((long)_buffer[index ] << 56 & 0xFF00000000000000L) |
|
---|
168 | ((long)_buffer[index + 1] << 48 & 0xFF000000000000L) |
|
---|
169 | ((long)_buffer[index + 2] << 40 & 0xFF0000000000L) |
|
---|
170 | ((long)_buffer[index + 3] << 32 & 0xFF00000000L) |
|
---|
171 | ((long)_buffer[index + 4] << 24 & 0xFF000000L) |
|
---|
172 | ((long)_buffer[index + 5] << 16 & 0xFF0000L) |
|
---|
173 | ((long)_buffer[index + 6] << 8 & 0xFF00L) |
|
---|
174 | ((long)_buffer[index + 7] & 0xFFL);
|
---|
175 | } else {
|
---|
176 | // Intel ordering - LSB first
|
---|
177 | return ((long)_buffer[index + 7] << 56 & 0xFF00000000000000L) |
|
---|
178 | ((long)_buffer[index + 6] << 48 & 0xFF000000000000L) |
|
---|
179 | ((long)_buffer[index + 5] << 40 & 0xFF0000000000L) |
|
---|
180 | ((long)_buffer[index + 4] << 32 & 0xFF00000000L) |
|
---|
181 | ((long)_buffer[index + 3] << 24 & 0xFF000000L) |
|
---|
182 | ((long)_buffer[index + 2] << 16 & 0xFF0000L) |
|
---|
183 | ((long)_buffer[index + 1] << 8 & 0xFF00L) |
|
---|
184 | ((long)_buffer[index ] & 0xFFL);
|
---|
185 | }
|
---|
186 | }
|
---|
187 |
|
---|
188 | @Override
|
---|
189 | public float getS15Fixed16(int index) throws BufferBoundsException
|
---|
190 | {
|
---|
191 | checkBounds(index, 4);
|
---|
192 |
|
---|
193 | if (_isMotorolaByteOrder) {
|
---|
194 | float res = (_buffer[index ] & 255) << 8 |
|
---|
195 | (_buffer[index + 1] & 255);
|
---|
196 | int d = (_buffer[index + 2] & 255) << 8 |
|
---|
197 | (_buffer[index + 3] & 255);
|
---|
198 | return (float)(res + d/65536.0);
|
---|
199 | } else {
|
---|
200 | // this particular branch is untested
|
---|
201 | float res = (_buffer[index + 3] & 255) << 8 |
|
---|
202 | (_buffer[index + 2] & 255);
|
---|
203 | int d = (_buffer[index + 1] & 255) << 8 |
|
---|
204 | (_buffer[index ] & 255);
|
---|
205 | return (float)(res + d/65536.0);
|
---|
206 | }
|
---|
207 | }
|
---|
208 |
|
---|
209 | @Override
|
---|
210 | public float getFloat32(int index) throws BufferBoundsException
|
---|
211 | {
|
---|
212 | return Float.intBitsToFloat(getInt32(index));
|
---|
213 | }
|
---|
214 |
|
---|
215 | @Override
|
---|
216 | public double getDouble64(int index) throws BufferBoundsException
|
---|
217 | {
|
---|
218 | return Double.longBitsToDouble(getInt64(index));
|
---|
219 | }
|
---|
220 |
|
---|
221 | @Override
|
---|
222 | @NotNull
|
---|
223 | public byte[] getBytes(int index, int count) throws BufferBoundsException
|
---|
224 | {
|
---|
225 | checkBounds(index, count);
|
---|
226 |
|
---|
227 | byte[] bytes = new byte[count];
|
---|
228 | System.arraycopy(_buffer, index, bytes, 0, count);
|
---|
229 | return bytes;
|
---|
230 | }
|
---|
231 |
|
---|
232 | @Override
|
---|
233 | @NotNull
|
---|
234 | public String getString(int index, int bytesRequested) throws BufferBoundsException
|
---|
235 | {
|
---|
236 | return new String(getBytes(index, bytesRequested));
|
---|
237 | }
|
---|
238 |
|
---|
239 | @Override
|
---|
240 | @NotNull
|
---|
241 | public String getString(int index, int bytesRequested, String charset) throws BufferBoundsException
|
---|
242 | {
|
---|
243 | byte[] bytes = getBytes(index, bytesRequested);
|
---|
244 | try {
|
---|
245 | return new String(bytes, charset);
|
---|
246 | } catch (UnsupportedEncodingException e) {
|
---|
247 | return new String(bytes);
|
---|
248 | }
|
---|
249 | }
|
---|
250 |
|
---|
251 | @Override
|
---|
252 | @NotNull
|
---|
253 | public String getNullTerminatedString(int index, int maxLengthBytes) throws BufferBoundsException
|
---|
254 | {
|
---|
255 | // NOTE currently only really suited to single-byte character strings
|
---|
256 |
|
---|
257 | checkBounds(index, maxLengthBytes);
|
---|
258 |
|
---|
259 | // Check for null terminators
|
---|
260 | int length = 0;
|
---|
261 | while ((index + length) < _buffer.length && _buffer[index + length] != '\0' && length < maxLengthBytes)
|
---|
262 | length++;
|
---|
263 |
|
---|
264 | byte[] bytes = getBytes(index, length);
|
---|
265 | return new String(bytes);
|
---|
266 | }
|
---|
267 |
|
---|
268 | private void checkBounds(final int index, final int bytesRequested) throws BufferBoundsException
|
---|
269 | {
|
---|
270 | if (bytesRequested < 0 || index < 0 || (long)index + (long)bytesRequested - 1L >= (long)_buffer.length)
|
---|
271 | throw new BufferBoundsException(_buffer, index, bytesRequested);
|
---|
272 | }
|
---|
273 | }
|
---|