001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.io;
018
019import static org.apache.commons.io.IOUtils.EOF;
020
021import java.io.EOFException;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.OutputStream;
025
026/**
027 * Helps with different endian systems.
028 * <p>
029 * Different computer architectures adopt different conventions for
030 * byte ordering. In so-called "Little Endian" architectures (eg Intel),
031 * the low-order byte is stored in memory at the lowest address, and
032 * subsequent bytes at higher addresses. For "Big Endian" architectures
033 * (eg Motorola), the situation is reversed.
034 * This class helps you solve this incompatibility.
035 * </p>
036 * <p>
037 * Provenance: Excalibur
038 * </p>
039 *
040 * @see org.apache.commons.io.input.SwappedDataInputStream
041 */
042public class EndianUtils {
043
044    /**
045     * Reads the next byte from the input stream.
046     * @param input  the stream
047     * @return the byte
048     * @throws IOException if the end of file is reached
049     */
050    private static int read(final InputStream input) throws IOException {
051        final int value = input.read();
052        if (EOF == value) {
053            throw new EOFException("Unexpected EOF reached");
054        }
055        return value;
056    }
057
058    /**
059     * Reads a "double" value from a byte array at a given offset. The value is
060     * converted to the opposed endian system while reading.
061     * @param data source byte array
062     * @param offset starting offset in the byte array
063     * @return the value read
064     */
065    public static double readSwappedDouble(final byte[] data, final int offset) {
066        return Double.longBitsToDouble(readSwappedLong(data, offset));
067    }
068
069    /**
070     * Reads a "double" value from an InputStream. The value is
071     * converted to the opposed endian system while reading.
072     * @param input source InputStream
073     * @return the value just read
074     * @throws IOException in case of an I/O problem
075     */
076    public static double readSwappedDouble(final InputStream input) throws IOException {
077        return Double.longBitsToDouble(readSwappedLong(input));
078    }
079
080    /**
081     * Reads a "float" value from a byte array at a given offset. The value is
082     * converted to the opposed endian system while reading.
083     * @param data source byte array
084     * @param offset starting offset in the byte array
085     * @return the value read
086     */
087    public static float readSwappedFloat(final byte[] data, final int offset) {
088        return Float.intBitsToFloat(readSwappedInteger(data, offset));
089    }
090
091    /**
092     * Reads a "float" value from an InputStream. The value is
093     * converted to the opposed endian system while reading.
094     * @param input source InputStream
095     * @return the value just read
096     * @throws IOException in case of an I/O problem
097     */
098    public static float readSwappedFloat(final InputStream input) throws IOException {
099        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}