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: */
017: package org.apache.commons.io;
018:
019: import java.io.EOFException;
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.io.OutputStream;
023:
024: /**
025: * Utility code for dealing with different endian systems.
026: * <p>
027: * Different computer architectures adopt different conventions for
028: * byte ordering. In so-called "Little Endian" architectures (eg Intel),
029: * the low-order byte is stored in memory at the lowest address, and
030: * subsequent bytes at higher addresses. For "Big Endian" architectures
031: * (eg Motorola), the situation is reversed.
032: * This class helps you solve this incompatability.
033: * <p>
034: * Origin of code: Excalibur
035: *
036: * @author <a href="mailto:peter@apache.org">Peter Donald</a>
037: * @version $Id: EndianUtils.java 539638 2007-05-18 23:44:30Z bayard $
038: * @see org.apache.commons.io.input.SwappedDataInputStream
039: */
040: public class EndianUtils {
041:
042: /**
043: * Instances should NOT be constructed in standard programming.
044: */
045: public EndianUtils() {
046: super ();
047: }
048:
049: // ========================================== Swapping routines
050:
051: /**
052: * Converts a "short" value between endian systems.
053: * @param value value to convert
054: * @return the converted value
055: */
056: public static short swapShort(short value) {
057: return (short) ((((value >> 0) & 0xff) << 8) + (((value >> 8) & 0xff) << 0));
058: }
059:
060: /**
061: * Converts a "int" value between endian systems.
062: * @param value value to convert
063: * @return the converted value
064: */
065: public static int swapInteger(int value) {
066: return (((value >> 0) & 0xff) << 24)
067: + (((value >> 8) & 0xff) << 16)
068: + (((value >> 16) & 0xff) << 8)
069: + (((value >> 24) & 0xff) << 0);
070: }
071:
072: /**
073: * Converts a "long" value between endian systems.
074: * @param value value to convert
075: * @return the converted value
076: */
077: public static long swapLong(long value) {
078: return (((value >> 0) & 0xff) << 56)
079: + (((value >> 8) & 0xff) << 48)
080: + (((value >> 16) & 0xff) << 40)
081: + (((value >> 24) & 0xff) << 32)
082: + (((value >> 32) & 0xff) << 24)
083: + (((value >> 40) & 0xff) << 16)
084: + (((value >> 48) & 0xff) << 8)
085: + (((value >> 56) & 0xff) << 0);
086: }
087:
088: /**
089: * Converts a "float" value between endian systems.
090: * @param value value to convert
091: * @return the converted value
092: */
093: public static float swapFloat(float value) {
094: return Float.intBitsToFloat(swapInteger(Float
095: .floatToIntBits(value)));
096: }
097:
098: /**
099: * Converts a "double" value between endian systems.
100: * @param value value to convert
101: * @return the converted value
102: */
103: public static double swapDouble(double value) {
104: return Double.longBitsToDouble(swapLong(Double
105: .doubleToLongBits(value)));
106: }
107:
108: // ========================================== Swapping read/write routines
109:
110: /**
111: * Writes a "short" value to a byte array at a given offset. The value is
112: * converted to the opposed endian system while writing.
113: * @param data target byte array
114: * @param offset starting offset in the byte array
115: * @param value value to write
116: */
117: public static void writeSwappedShort(byte[] data, int offset,
118: short value) {
119: data[offset + 0] = (byte) ((value >> 0) & 0xff);
120: data[offset + 1] = (byte) ((value >> 8) & 0xff);
121: }
122:
123: /**
124: * Reads a "short" value from a byte array at a given offset. The value is
125: * converted to the opposed endian system while reading.
126: * @param data source byte array
127: * @param offset starting offset in the byte array
128: * @return the value read
129: */
130: public static short readSwappedShort(byte[] data, int offset) {
131: return (short) (((data[offset + 0] & 0xff) << 0) + ((data[offset + 1] & 0xff) << 8));
132: }
133:
134: /**
135: * Reads an unsigned short (16-bit) value from a byte array at a given
136: * offset. The value is converted to the opposed endian system while
137: * reading.
138: * @param data source byte array
139: * @param offset starting offset in the byte array
140: * @return the value read
141: */
142: public static int readSwappedUnsignedShort(byte[] data, int offset) {
143: return (((data[offset + 0] & 0xff) << 0) + ((data[offset + 1] & 0xff) << 8));
144: }
145:
146: /**
147: * Writes a "int" value to a byte array at a given offset. The value is
148: * converted to the opposed endian system while writing.
149: * @param data target byte array
150: * @param offset starting offset in the byte array
151: * @param value value to write
152: */
153: public static void writeSwappedInteger(byte[] data, int offset,
154: int value) {
155: data[offset + 0] = (byte) ((value >> 0) & 0xff);
156: data[offset + 1] = (byte) ((value >> 8) & 0xff);
157: data[offset + 2] = (byte) ((value >> 16) & 0xff);
158: data[offset + 3] = (byte) ((value >> 24) & 0xff);
159: }
160:
161: /**
162: * Reads a "int" value from a byte array at a given offset. The value is
163: * converted to the opposed endian system while reading.
164: * @param data source byte array
165: * @param offset starting offset in the byte array
166: * @return the value read
167: */
168: public static int readSwappedInteger(byte[] data, int offset) {
169: return (((data[offset + 0] & 0xff) << 0)
170: + ((data[offset + 1] & 0xff) << 8)
171: + ((data[offset + 2] & 0xff) << 16) + ((data[offset + 3] & 0xff) << 24));
172: }
173:
174: /**
175: * Reads an unsigned integer (32-bit) value from a byte array at a given
176: * offset. The value is converted to the opposed endian system while
177: * reading.
178: * @param data source byte array
179: * @param offset starting offset in the byte array
180: * @return the value read
181: */
182: public static long readSwappedUnsignedInteger(byte[] data,
183: int offset) {
184: long low = (((data[offset + 0] & 0xff) << 0)
185: + ((data[offset + 1] & 0xff) << 8) + ((data[offset + 2] & 0xff) << 16));
186:
187: long high = data[offset + 3] & 0xff;
188:
189: return (high << 24) + (0xffffffffL & low);
190: }
191:
192: /**
193: * Writes a "long" value to a byte array at a given offset. The value is
194: * converted to the opposed endian system while writing.
195: * @param data target byte array
196: * @param offset starting offset in the byte array
197: * @param value value to write
198: */
199: public static void writeSwappedLong(byte[] data, int offset,
200: long value) {
201: data[offset + 0] = (byte) ((value >> 0) & 0xff);
202: data[offset + 1] = (byte) ((value >> 8) & 0xff);
203: data[offset + 2] = (byte) ((value >> 16) & 0xff);
204: data[offset + 3] = (byte) ((value >> 24) & 0xff);
205: data[offset + 4] = (byte) ((value >> 32) & 0xff);
206: data[offset + 5] = (byte) ((value >> 40) & 0xff);
207: data[offset + 6] = (byte) ((value >> 48) & 0xff);
208: data[offset + 7] = (byte) ((value >> 56) & 0xff);
209: }
210:
211: /**
212: * Reads a "long" value from a byte array at a given offset. The value is
213: * converted to the opposed endian system while reading.
214: * @param data source byte array
215: * @param offset starting offset in the byte array
216: * @return the value read
217: */
218: public static long readSwappedLong(byte[] data, int offset) {
219: long low = ((data[offset + 0] & 0xff) << 0)
220: + ((data[offset + 1] & 0xff) << 8)
221: + ((data[offset + 2] & 0xff) << 16)
222: + ((data[offset + 3] & 0xff) << 24);
223: long high = ((data[offset + 4] & 0xff) << 0)
224: + ((data[offset + 5] & 0xff) << 8)
225: + ((data[offset + 6] & 0xff) << 16)
226: + ((data[offset + 7] & 0xff) << 24);
227: return (high << 32) + (0xffffffffL & low);
228: }
229:
230: /**
231: * Writes a "float" value to a byte array at a given offset. The value is
232: * converted to the opposed endian system while writing.
233: * @param data target byte array
234: * @param offset starting offset in the byte array
235: * @param value value to write
236: */
237: public static void writeSwappedFloat(byte[] data, int offset,
238: float value) {
239: writeSwappedInteger(data, offset, Float.floatToIntBits(value));
240: }
241:
242: /**
243: * Reads a "float" value from a byte array at a given offset. The value is
244: * converted to the opposed endian system while reading.
245: * @param data source byte array
246: * @param offset starting offset in the byte array
247: * @return the value read
248: */
249: public static float readSwappedFloat(byte[] data, int offset) {
250: return Float.intBitsToFloat(readSwappedInteger(data, offset));
251: }
252:
253: /**
254: * Writes a "double" value to a byte array at a given offset. The value is
255: * converted to the opposed endian system while writing.
256: * @param data target byte array
257: * @param offset starting offset in the byte array
258: * @param value value to write
259: */
260: public static void writeSwappedDouble(byte[] data, int offset,
261: double value) {
262: writeSwappedLong(data, offset, Double.doubleToLongBits(value));
263: }
264:
265: /**
266: * Reads a "double" value from a byte array at a given offset. The value is
267: * converted to the opposed endian system while reading.
268: * @param data source byte array
269: * @param offset starting offset in the byte array
270: * @return the value read
271: */
272: public static double readSwappedDouble(byte[] data, int offset) {
273: return Double.longBitsToDouble(readSwappedLong(data, offset));
274: }
275:
276: /**
277: * Writes a "short" value to an OutputStream. The value is
278: * converted to the opposed endian system while writing.
279: * @param output target OutputStream
280: * @param value value to write
281: * @throws IOException in case of an I/O problem
282: */
283: public static void writeSwappedShort(OutputStream output,
284: short value) throws IOException {
285: output.write((byte) ((value >> 0) & 0xff));
286: output.write((byte) ((value >> 8) & 0xff));
287: }
288:
289: /**
290: * Reads a "short" value from an InputStream. The value is
291: * converted to the opposed endian system while reading.
292: * @param input source InputStream
293: * @return the value just read
294: * @throws IOException in case of an I/O problem
295: */
296: public static short readSwappedShort(InputStream input)
297: throws IOException {
298: return (short) (((read(input) & 0xff) << 0) + ((read(input) & 0xff) << 8));
299: }
300:
301: /**
302: * Reads a unsigned short (16-bit) from an InputStream. The value is
303: * converted to the opposed endian system while reading.
304: * @param input source InputStream
305: * @return the value just read
306: * @throws IOException in case of an I/O problem
307: */
308: public static int readSwappedUnsignedShort(InputStream input)
309: throws IOException {
310: int value1 = read(input);
311: int value2 = read(input);
312:
313: return (((value1 & 0xff) << 0) + ((value2 & 0xff) << 8));
314: }
315:
316: /**
317: * Writes a "int" value to an OutputStream. The value is
318: * converted to the opposed endian system while writing.
319: * @param output target OutputStream
320: * @param value value to write
321: * @throws IOException in case of an I/O problem
322: */
323: public static void writeSwappedInteger(OutputStream output,
324: int value) throws IOException {
325: output.write((byte) ((value >> 0) & 0xff));
326: output.write((byte) ((value >> 8) & 0xff));
327: output.write((byte) ((value >> 16) & 0xff));
328: output.write((byte) ((value >> 24) & 0xff));
329: }
330:
331: /**
332: * Reads a "int" value from an InputStream. The value is
333: * converted to the opposed endian system while reading.
334: * @param input source InputStream
335: * @return the value just read
336: * @throws IOException in case of an I/O problem
337: */
338: public static int readSwappedInteger(InputStream input)
339: throws IOException {
340: int value1 = read(input);
341: int value2 = read(input);
342: int value3 = read(input);
343: int value4 = read(input);
344:
345: return ((value1 & 0xff) << 0) + ((value2 & 0xff) << 8)
346: + ((value3 & 0xff) << 16) + ((value4 & 0xff) << 24);
347: }
348:
349: /**
350: * Reads a unsigned integer (32-bit) from an InputStream. The value is
351: * converted to the opposed endian system while reading.
352: * @param input source InputStream
353: * @return the value just read
354: * @throws IOException in case of an I/O problem
355: */
356: public static long readSwappedUnsignedInteger(InputStream input)
357: throws IOException {
358: int value1 = read(input);
359: int value2 = read(input);
360: int value3 = read(input);
361: int value4 = read(input);
362:
363: long low = (((value1 & 0xff) << 0) + ((value2 & 0xff) << 8) + ((value3 & 0xff) << 16));
364:
365: long high = value4 & 0xff;
366:
367: return (high << 24) + (0xffffffffL & low);
368: }
369:
370: /**
371: * Writes a "long" value to an OutputStream. The value is
372: * converted to the opposed endian system while writing.
373: * @param output target OutputStream
374: * @param value value to write
375: * @throws IOException in case of an I/O problem
376: */
377: public static void writeSwappedLong(OutputStream output, long value)
378: throws IOException {
379: output.write((byte) ((value >> 0) & 0xff));
380: output.write((byte) ((value >> 8) & 0xff));
381: output.write((byte) ((value >> 16) & 0xff));
382: output.write((byte) ((value >> 24) & 0xff));
383: output.write((byte) ((value >> 32) & 0xff));
384: output.write((byte) ((value >> 40) & 0xff));
385: output.write((byte) ((value >> 48) & 0xff));
386: output.write((byte) ((value >> 56) & 0xff));
387: }
388:
389: /**
390: * Reads a "long" value from an InputStream. The value is
391: * converted to the opposed endian system while reading.
392: * @param input source InputStream
393: * @return the value just read
394: * @throws IOException in case of an I/O problem
395: */
396: public static long readSwappedLong(InputStream input)
397: throws IOException {
398: byte[] bytes = new byte[8];
399: for (int i = 0; i < 8; i++) {
400: bytes[i] = (byte) read(input);
401: }
402: return readSwappedLong(bytes, 0);
403: }
404:
405: /**
406: * Writes a "float" value to an OutputStream. The value is
407: * converted to the opposed endian system while writing.
408: * @param output target OutputStream
409: * @param value value to write
410: * @throws IOException in case of an I/O problem
411: */
412: public static void writeSwappedFloat(OutputStream output,
413: float value) throws IOException {
414: writeSwappedInteger(output, Float.floatToIntBits(value));
415: }
416:
417: /**
418: * Reads a "float" value from an InputStream. The value is
419: * converted to the opposed endian system while reading.
420: * @param input source InputStream
421: * @return the value just read
422: * @throws IOException in case of an I/O problem
423: */
424: public static float readSwappedFloat(InputStream input)
425: throws IOException {
426: return Float.intBitsToFloat(readSwappedInteger(input));
427: }
428:
429: /**
430: * Writes a "double" value to an OutputStream. The value is
431: * converted to the opposed endian system while writing.
432: * @param output target OutputStream
433: * @param value value to write
434: * @throws IOException in case of an I/O problem
435: */
436: public static void writeSwappedDouble(OutputStream output,
437: double value) throws IOException {
438: writeSwappedLong(output, Double.doubleToLongBits(value));
439: }
440:
441: /**
442: * Reads a "double" value from an InputStream. The value is
443: * converted to the opposed endian system while reading.
444: * @param input source InputStream
445: * @return the value just read
446: * @throws IOException in case of an I/O problem
447: */
448: public static double readSwappedDouble(InputStream input)
449: throws IOException {
450: return Double.longBitsToDouble(readSwappedLong(input));
451: }
452:
453: /**
454: * Reads the next byte from the input stream.
455: * @param input the stream
456: * @return the byte
457: * @throws IOException if the end of file is reached
458: */
459: private static int read(InputStream input) throws IOException {
460: int value = input.read();
461:
462: if (-1 == value) {
463: throw new EOFException("Unexpected EOF reached");
464: }
465:
466: return value;
467: }
468: }
|