1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.io;
18
19 import static org.apache.commons.io.IOUtils.EOF;
20
21 import java.io.EOFException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25
26 /**
27 * Helps with different endian systems.
28 * <p>
29 * Different computer architectures adopt different conventions for
30 * byte ordering. In so-called "Little Endian" architectures (eg Intel),
31 * the low-order byte is stored in memory at the lowest address, and
32 * subsequent bytes at higher addresses. For "Big Endian" architectures
33 * (eg Motorola), the situation is reversed.
34 * This class helps you solve this incompatibility.
35 * </p>
36 * <p>
37 * Provenance: Excalibur
38 * </p>
39 *
40 * @see org.apache.commons.io.input.SwappedDataInputStream
41 */
42 public class EndianUtils {
43
44 /**
45 * Reads the next byte from the input stream.
46 * @param input the stream
47 * @return the byte
48 * @throws IOException if the end of file is reached
49 */
50 private static int read(final InputStream input) throws IOException {
51 final int value = input.read();
52 if (EOF == value) {
53 throw new EOFException("Unexpected EOF reached");
54 }
55 return value;
56 }
57
58 /**
59 * Reads a "double" value from a byte array at a given offset. The value is
60 * converted to the opposed endian system while reading.
61 * @param data source byte array
62 * @param offset starting offset in the byte array
63 * @return the value read
64 */
65 public static double readSwappedDouble(final byte[] data, final int offset) {
66 return Double.longBitsToDouble(readSwappedLong(data, offset));
67 }
68
69 /**
70 * Reads a "double" value from an InputStream. The value is
71 * converted to the opposed endian system while reading.
72 * @param input source InputStream
73 * @return the value just read
74 * @throws IOException in case of an I/O problem
75 */
76 public static double readSwappedDouble(final InputStream input) throws IOException {
77 return Double.longBitsToDouble(readSwappedLong(input));
78 }
79
80 /**
81 * Reads a "float" value from a byte array at a given offset. The value is
82 * converted to the opposed endian system while reading.
83 * @param data source byte array
84 * @param offset starting offset in the byte array
85 * @return the value read
86 */
87 public static float readSwappedFloat(final byte[] data, final int offset) {
88 return Float.intBitsToFloat(readSwappedInteger(data, offset));
89 }
90
91 /**
92 * Reads a "float" value from an InputStream. The value is
93 * converted to the opposed endian system while reading.
94 * @param input source InputStream
95 * @return the value just read
96 * @throws IOException in case of an I/O problem
97 */
98 public static float readSwappedFloat(final InputStream input) throws IOException {
99 return Float.intBitsToFloat(readSwappedInteger(input));
100 }
101
102 /**
103 * Reads an "int" value from a byte array at a given offset. The value is
104 * converted to the opposed endian system while reading.
105 * @param data source byte array
106 * @param offset starting offset in the byte array
107 * @return the value read
108 */
109 public static int readSwappedInteger(final byte[] data, final int offset) {
110 return ((data[offset + 0] & 0xff) << 0) +
111 ((data[offset + 1] & 0xff) << 8) +
112 ((data[offset + 2] & 0xff) << 16) +
113 ((data[offset + 3] & 0xff) << 24);
114 }
115
116 /**
117 * Reads an "int" value from an InputStream. The value is
118 * converted to the opposed endian system while reading.
119 * @param input source InputStream
120 * @return the value just read
121 * @throws IOException in case of an I/O problem
122 */
123 public static int readSwappedInteger(final InputStream input) throws IOException {
124 final int value1 = read(input);
125 final int value2 = read(input);
126 final int value3 = read(input);
127 final int value4 = read(input);
128 return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16) + ((value4 & 0xff) << 24);
129 }
130
131 /**
132 * Reads a "long" value from a byte array at a given offset. The value is
133 * converted to the opposed endian system while reading.
134 * @param data source byte array
135 * @param offset starting offset in the byte array
136 * @return the value read
137 */
138 public static long readSwappedLong(final byte[] data, final int offset) {
139 final long low = readSwappedInteger(data, offset);
140 final long high = readSwappedInteger(data, offset + 4);
141 return (high << 32) + (0xffffffffL & low);
142 }
143
144 /**
145 * Reads a "long" value from an InputStream. The value is
146 * converted to the opposed endian system while reading.
147 * @param input source InputStream
148 * @return the value just read
149 * @throws IOException in case of an I/O problem
150 */
151 public static long readSwappedLong(final InputStream input) throws IOException {
152 final byte[] bytes = new byte[8];
153 for (int i = 0; i < 8; i++) {
154 bytes[i] = (byte) read(input);
155 }
156 return readSwappedLong(bytes, 0);
157 }
158
159 /**
160 * Reads a "short" value from a byte array at a given offset. The value is
161 * converted to the opposed endian system while reading.
162 * @param data source byte array
163 * @param offset starting offset in the byte array
164 * @return the value read
165 */
166 public static short readSwappedShort(final byte[] data, final int offset) {
167 return (short) (((data[offset + 0] & 0xff) << 0) + ((data[offset + 1] & 0xff) << 8));
168 }
169
170 /**
171 * Reads a "short" value from an InputStream. The value is
172 * converted to the opposed endian system while reading.
173 * @param input source InputStream
174 * @return the value just read
175 * @throws IOException in case of an I/O problem
176 */
177 public static short readSwappedShort(final InputStream input) throws IOException {
178 return (short) (((read(input) & 0xff) << 0) + ((read(input) & 0xff) << 8));
179 }
180
181 /**
182 * Reads an unsigned integer (32-bit) value from a byte array at a given
183 * offset. The value is converted to the opposed endian system while
184 * reading.
185 * @param data source byte array
186 * @param offset starting offset in the byte array
187 * @return the value read
188 */
189 public static long readSwappedUnsignedInteger(final byte[] data, final int offset) {
190 final long low = ((data[offset + 0] & 0xff) << 0) +
191 ((data[offset + 1] & 0xff) << 8) +
192 ((data[offset + 2] & 0xff) << 16);
193 final long high = data[offset + 3] & 0xff;
194 return (high << 24) + (0xffffffffL & low);
195 }
196
197 /**
198 * Reads an unsigned integer (32-bit) from an InputStream. The value is
199 * converted to the opposed endian system while reading.
200 * @param input source InputStream
201 * @return the value just read
202 * @throws IOException in case of an I/O problem
203 */
204 public static long readSwappedUnsignedInteger(final InputStream input) throws IOException {
205 final int value1 = read(input);
206 final int value2 = read(input);
207 final int value3 = read(input);
208 final int value4 = read(input);
209 final long low = ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16);
210 final long high = value4 & 0xff;
211 return (high << 24) + (0xffffffffL & low);
212 }
213
214 /**
215 * Reads an unsigned short (16-bit) value from a byte array at a given
216 * offset. The value is converted to the opposed endian system while
217 * reading.
218 * @param data source byte array
219 * @param offset starting offset in the byte array
220 * @return the value read
221 */
222 public static int readSwappedUnsignedShort(final byte[] data, final int offset) {
223 return ((data[offset + 0] & 0xff) << 0) + ((data[offset + 1] & 0xff) << 8);
224 }
225
226 /**
227 * Reads an unsigned short (16-bit) from an InputStream. The value is
228 * converted to the opposed endian system while reading.
229 * @param input source InputStream
230 * @return the value just read
231 * @throws IOException in case of an I/O problem
232 */
233 public static int readSwappedUnsignedShort(final InputStream input) throws IOException {
234 final int value1 = read(input);
235 final int value2 = read(input);
236
237 return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8);
238 }
239
240 /**
241 * Converts a "double" value between endian systems.
242 * @param value value to convert
243 * @return the converted value
244 */
245 public static double swapDouble(final double value) {
246 return Double.longBitsToDouble(swapLong(Double.doubleToLongBits(value)));
247 }
248
249 /**
250 * Converts a "float" value between endian systems.
251 * @param value value to convert
252 * @return the converted value
253 */
254 public static float swapFloat(final float value) {
255 return Float.intBitsToFloat(swapInteger(Float.floatToIntBits(value)));
256 }
257
258 /**
259 * Converts an "int" value between endian systems.
260 * @param value value to convert
261 * @return the converted value
262 */
263 public static int swapInteger(final int value) {
264 return
265 ((value >> 0 & 0xff) << 24) +
266 ((value >> 8 & 0xff) << 16) +
267 ((value >> 16 & 0xff) << 8) +
268 ((value >> 24 & 0xff) << 0);
269 }
270
271 /**
272 * Converts a "long" value between endian systems.
273 * @param value value to convert
274 * @return the converted value
275 */
276 public static long swapLong(final long value) {
277 return
278 ((value >> 0 & 0xff) << 56) +
279 ((value >> 8 & 0xff) << 48) +
280 ((value >> 16 & 0xff) << 40) +
281 ((value >> 24 & 0xff) << 32) +
282 ((value >> 32 & 0xff) << 24) +
283 ((value >> 40 & 0xff) << 16) +
284 ((value >> 48 & 0xff) << 8) +
285 ((value >> 56 & 0xff) << 0);
286 }
287
288 /**
289 * Converts a "short" value between endian systems.
290 * @param value value to convert
291 * @return the converted value
292 */
293 public static short swapShort(final short value) {
294 return (short) (((value >> 0 & 0xff) << 8) +
295 ((value >> 8 & 0xff) << 0));
296 }
297
298 /**
299 * Writes a "double" value to a byte array at a given offset. The value is
300 * converted to the opposed endian system while writing.
301 * @param data target byte array
302 * @param offset starting offset in the byte array
303 * @param value value to write
304 */
305 public static void writeSwappedDouble(final byte[] data, final int offset, final double value) {
306 writeSwappedLong(data, offset, Double.doubleToLongBits(value));
307 }
308
309 /**
310 * Writes a "double" value to an OutputStream. The value is
311 * converted to the opposed endian system while writing.
312 * @param output target OutputStream
313 * @param value value to write
314 * @throws IOException in case of an I/O problem
315 */
316 public static void writeSwappedDouble(final OutputStream output, final double value) throws IOException {
317 writeSwappedLong(output, Double.doubleToLongBits(value));
318 }
319
320 /**
321 * Writes a "float" value to a byte array at a given offset. The value is
322 * converted to the opposed endian system while writing.
323 * @param data target byte array
324 * @param offset starting offset in the byte array
325 * @param value value to write
326 */
327 public static void writeSwappedFloat(final byte[] data, final int offset, final float value) {
328 writeSwappedInteger(data, offset, Float.floatToIntBits(value));
329 }
330
331 /**
332 * Writes a "float" value to an OutputStream. The value is
333 * converted to the opposed endian system while writing.
334 * @param output target OutputStream
335 * @param value value to write
336 * @throws IOException in case of an I/O problem
337 */
338 public static void writeSwappedFloat(final OutputStream output, final float value) throws IOException {
339 writeSwappedInteger(output, Float.floatToIntBits(value));
340 }
341
342 /**
343 * Writes an "int" value to a byte array at a given offset. The value is
344 * converted to the opposed endian system while writing.
345 * @param data target byte array
346 * @param offset starting offset in the byte array
347 * @param value value to write
348 */
349 public static void writeSwappedInteger(final byte[] data, final int offset, final int value) {
350 data[offset + 0] = (byte) (value >> 0 & 0xff);
351 data[offset + 1] = (byte) (value >> 8 & 0xff);
352 data[offset + 2] = (byte) (value >> 16 & 0xff);
353 data[offset + 3] = (byte) (value >> 24 & 0xff);
354 }
355
356 /**
357 * Writes an "int" value to an OutputStream. The value is converted to the opposed endian system while writing.
358 *
359 * @param output target OutputStream
360 * @param value value to write
361 * @throws IOException in case of an I/O problem
362 */
363 public static void writeSwappedInteger(final OutputStream output, final int value) throws IOException {
364 output.write((byte) (value >> 0 & 0xff));
365 output.write((byte) (value >> 8 & 0xff));
366 output.write((byte) (value >> 16 & 0xff));
367 output.write((byte) (value >> 24 & 0xff));
368 }
369
370 /**
371 * Writes a "long" value to a byte array at a given offset. The value is
372 * converted to the opposed endian system while writing.
373 * @param data target byte array
374 * @param offset starting offset in the byte array
375 * @param value value to write
376 */
377 public static void writeSwappedLong(final byte[] data, final int offset, final long value) {
378 data[offset + 0] = (byte) (value >> 0 & 0xff);
379 data[offset + 1] = (byte) (value >> 8 & 0xff);
380 data[offset + 2] = (byte) (value >> 16 & 0xff);
381 data[offset + 3] = (byte) (value >> 24 & 0xff);
382 data[offset + 4] = (byte) (value >> 32 & 0xff);
383 data[offset + 5] = (byte) (value >> 40 & 0xff);
384 data[offset + 6] = (byte) (value >> 48 & 0xff);
385 data[offset + 7] = (byte) (value >> 56 & 0xff);
386 }
387
388 /**
389 * Writes a "long" value to an OutputStream. The value is
390 * converted to the opposed endian system while writing.
391 * @param output target OutputStream
392 * @param value value to write
393 * @throws IOException in case of an I/O problem
394 */
395 public static void writeSwappedLong(final OutputStream output, final long value) throws IOException {
396 output.write((byte) (value >> 0 & 0xff));
397 output.write((byte) (value >> 8 & 0xff));
398 output.write((byte) (value >> 16 & 0xff));
399 output.write((byte) (value >> 24 & 0xff));
400 output.write((byte) (value >> 32 & 0xff));
401 output.write((byte) (value >> 40 & 0xff));
402 output.write((byte) (value >> 48 & 0xff));
403 output.write((byte) (value >> 56 & 0xff));
404 }
405
406 /**
407 * Writes a "short" value to a byte array at a given offset. The value is
408 * converted to the opposed endian system while writing.
409 * @param data target byte array
410 * @param offset starting offset in the byte array
411 * @param value value to write
412 */
413 public static void writeSwappedShort(final byte[] data, final int offset, final short value) {
414 data[offset + 0] = (byte) (value >> 0 & 0xff);
415 data[offset + 1] = (byte) (value >> 8 & 0xff);
416 }
417
418 /**
419 * Writes a "short" value to an OutputStream. The value is
420 * converted to the opposed endian system while writing.
421 * @param output target OutputStream
422 * @param value value to write
423 * @throws IOException in case of an I/O problem
424 */
425 public static void writeSwappedShort(final OutputStream output, final short value) throws IOException {
426 output.write((byte) (value >> 0 & 0xff));
427 output.write((byte) (value >> 8 & 0xff));
428 }
429
430 /**
431 * Instances should NOT be constructed in standard programming.
432 */
433 public EndianUtils() {
434 }
435 }