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.imaging.common;
018
019import java.nio.ByteOrder;
020
021/**
022 * Convenience methods for converting data types to and from
023 * byte arrays.
024 */
025public final class ByteConversions {
026    private ByteConversions() {
027    }
028
029    public static byte[] toBytes(final short value, final ByteOrder byteOrder) {
030        final byte[] result = new byte[2];
031        toBytes(value, byteOrder, result, 0);
032        return result;
033    }
034
035    public static byte[] toBytes(final short[] values, final ByteOrder byteOrder) {
036        return toBytes(values, 0, values.length, byteOrder);
037    }
038
039    private static byte[] toBytes(final short[] values, final int offset, final int length, final ByteOrder byteOrder) {
040        final byte[] result = new byte[length * 2];
041        for (int i = 0; i < length; i++) {
042            toBytes(values[offset + i], byteOrder, result, i * 2);
043        }
044        return result;
045    }
046
047    private static void toBytes(final short value, final ByteOrder byteOrder, final byte[] result, final int offset) {
048        if (byteOrder == ByteOrder.BIG_ENDIAN) {
049            result[offset + 0] = (byte) (value >> 8);
050            result[offset + 1] = (byte) (value >> 0);
051        } else {
052            result[offset + 1] = (byte) (value >> 8);
053            result[offset + 0] = (byte) (value >> 0);
054        }
055    }
056
057    public static byte[] toBytes(final int value, final ByteOrder byteOrder) {
058        final byte[] result = new byte[4];
059        toBytes(value, byteOrder, result, 0);
060        return result;
061    }
062
063    public static byte[] toBytes(final int[] values, final ByteOrder byteOrder) {
064        return toBytes(values, 0, values.length, byteOrder);
065    }
066
067    private static byte[] toBytes(final int[] values, final int offset, final int length, final ByteOrder byteOrder) {
068        final byte[] result = new byte[length * 4];
069        for (int i = 0; i < length; i++) {
070            toBytes(values[offset + i], byteOrder, result, i * 4);
071        }
072        return result;
073    }
074
075    private static void toBytes(final int value, final ByteOrder byteOrder, final byte[] result, final int offset) {
076        if (byteOrder == ByteOrder.BIG_ENDIAN) {
077            result[offset + 0] = (byte) (value >> 24);
078            result[offset + 1] = (byte) (value >> 16);
079            result[offset + 2] = (byte) (value >> 8);
080            result[offset + 3] = (byte) (value >> 0);
081        } else {
082            result[offset + 3] = (byte) (value >> 24);
083            result[offset + 2] = (byte) (value >> 16);
084            result[offset + 1] = (byte) (value >> 8);
085            result[offset + 0] = (byte) (value >> 0);
086        }
087    }
088
089    public static byte[] toBytes(final float value, final ByteOrder byteOrder) {
090        final byte[] result = new byte[4];
091        toBytes(value, byteOrder, result, 0);
092        return result;
093    }
094
095    public static byte[] toBytes(final float[] values, final ByteOrder byteOrder) {
096        return toBytes(values, 0, values.length, byteOrder);
097    }
098
099    private static byte[] toBytes(final float[] values, final int offset, final int length, final ByteOrder byteOrder) {
100        final byte[] result = new byte[length * 4];
101        for (int i = 0; i < length; i++) {
102            toBytes(values[offset + i], byteOrder, result, i * 4);
103        }
104        return result;
105    }
106
107    private static void toBytes(final float value, final ByteOrder byteOrder, final byte[] result, final int offset) {
108        final int bits = Float.floatToRawIntBits(value);
109        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
110            result[offset + 0] = (byte) (0xff & (bits >> 0));
111            result[offset + 1] = (byte) (0xff & (bits >> 8));
112            result[offset + 2] = (byte) (0xff & (bits >> 16));
113            result[offset + 3] = (byte) (0xff & (bits >> 24));
114        } else {
115            result[offset + 3] = (byte) (0xff & (bits >> 0));
116            result[offset + 2] = (byte) (0xff & (bits >> 8));
117            result[offset + 1] = (byte) (0xff & (bits >> 16));
118            result[offset + 0] = (byte) (0xff & (bits >> 24));
119        }
120    }
121
122    public static byte[] toBytes(final double value, final ByteOrder byteOrder) {
123        final byte[] result = new byte[8];
124        toBytes(value, byteOrder, result, 0);
125        return result;
126    }
127
128    public static byte[] toBytes(final double[] values, final ByteOrder byteOrder) {
129        return toBytes(values, 0, values.length, byteOrder);
130    }
131
132    private static byte[] toBytes(final double[] values, final int offset,
133            final int length, final ByteOrder byteOrder) {
134        final byte[] result = new byte[length * 8];
135        for (int i = 0; i < length; i++) {
136            toBytes(values[offset + i], byteOrder, result, i * 8);
137        }
138        return result;
139    }
140
141    private static void toBytes(final double value, final ByteOrder byteOrder, final byte[] result, final int offset) {
142        final long bits = Double.doubleToRawLongBits(value);
143        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
144            result[offset + 0] = (byte) (0xff & (bits >> 0));
145            result[offset + 1] = (byte) (0xff & (bits >> 8));
146            result[offset + 2] = (byte) (0xff & (bits >> 16));
147            result[offset + 3] = (byte) (0xff & (bits >> 24));
148            result[offset + 4] = (byte) (0xff & (bits >> 32));
149            result[offset + 5] = (byte) (0xff & (bits >> 40));
150            result[offset + 6] = (byte) (0xff & (bits >> 48));
151            result[offset + 7] = (byte) (0xff & (bits >> 56));
152        } else {
153            result[offset + 7] = (byte) (0xff & (bits >> 0));
154            result[offset + 6] = (byte) (0xff & (bits >> 8));
155            result[offset + 5] = (byte) (0xff & (bits >> 16));
156            result[offset + 4] = (byte) (0xff & (bits >> 24));
157            result[offset + 3] = (byte) (0xff & (bits >> 32));
158            result[offset + 2] = (byte) (0xff & (bits >> 40));
159            result[offset + 1] = (byte) (0xff & (bits >> 48));
160            result[offset + 0] = (byte) (0xff & (bits >> 56));
161        }
162    }
163
164    public static byte[] toBytes(final RationalNumber value, final ByteOrder byteOrder) {
165        final byte[] result = new byte[8];
166        toBytes(value, byteOrder, result, 0);
167        return result;
168    }
169
170    public static byte[] toBytes(final RationalNumber[] values, final ByteOrder byteOrder) {
171        return toBytes(values, 0, values.length, byteOrder);
172    }
173
174    private static byte[] toBytes(final RationalNumber[] values, final int offset,
175            final int length, final ByteOrder byteOrder) {
176        final byte[] result = new byte[length * 8];
177        for (int i = 0; i < length; i++) {
178            toBytes(values[offset + i], byteOrder, result, i * 8);
179        }
180        return result;
181    }
182
183    private static void toBytes(final RationalNumber value, final ByteOrder byteOrder,
184            final byte[] result, final int offset) {
185        if (byteOrder == ByteOrder.BIG_ENDIAN) {
186            result[offset + 0] = (byte) (value.numerator >> 24);
187            result[offset + 1] = (byte) (value.numerator >> 16);
188            result[offset + 2] = (byte) (value.numerator >> 8);
189            result[offset + 3] = (byte) (value.numerator >> 0);
190            result[offset + 4] = (byte) (value.divisor >> 24);
191            result[offset + 5] = (byte) (value.divisor >> 16);
192            result[offset + 6] = (byte) (value.divisor >> 8);
193            result[offset + 7] = (byte) (value.divisor >> 0);
194        } else {
195            result[offset + 3] = (byte) (value.numerator >> 24);
196            result[offset + 2] = (byte) (value.numerator >> 16);
197            result[offset + 1] = (byte) (value.numerator >> 8);
198            result[offset + 0] = (byte) (value.numerator >> 0);
199            result[offset + 7] = (byte) (value.divisor >> 24);
200            result[offset + 6] = (byte) (value.divisor >> 16);
201            result[offset + 5] = (byte) (value.divisor >> 8);
202            result[offset + 4] = (byte) (value.divisor >> 0);
203        }
204    }
205
206    public static short toShort(final byte[] bytes, final ByteOrder byteOrder) {
207        return toShort(bytes, 0, byteOrder);
208    }
209
210    private static short toShort(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
211        return (short) toUInt16(bytes, offset, byteOrder);
212    }
213
214    public static short[] toShorts(final byte[] bytes, final ByteOrder byteOrder) {
215        return toShorts(bytes, 0, bytes.length, byteOrder);
216    }
217
218    private static short[] toShorts(final byte[] bytes, final int offset,
219            final int length, final ByteOrder byteOrder) {
220        final short[] result = new short[length / 2];
221        for (int i = 0; i < result.length; i++) {
222            result[i] = toShort(bytes, offset + 2 * i, byteOrder);
223        }
224        return result;
225    }
226
227    public static int toUInt16(final byte[] bytes, final ByteOrder byteOrder) {
228        return toUInt16(bytes, 0, byteOrder);
229    }
230
231    public static int toUInt16(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
232        final int byte0 = 0xff & bytes[offset + 0];
233        final int byte1 = 0xff & bytes[offset + 1];
234        if (byteOrder == ByteOrder.BIG_ENDIAN) {
235            return ((byte0 << 8) | byte1);
236        } else {
237            return ((byte1 << 8) | byte0);
238        }
239    }
240
241    public static int[] toUInt16s(final byte[] bytes, final ByteOrder byteOrder) {
242        return toUInt16s(bytes, 0, bytes.length, byteOrder);
243    }
244
245    private static int[] toUInt16s(final byte[] bytes, final int offset, final int length,
246            final ByteOrder byteOrder) {
247        final int[] result = new int[length / 2];
248        for (int i = 0; i < result.length; i++) {
249            result[i] = toUInt16(bytes, offset + 2 * i, byteOrder);
250        }
251        return result;
252    }
253
254    public static int toInt(final byte[] bytes, final ByteOrder byteOrder) {
255        return toInt(bytes, 0, byteOrder);
256    }
257
258    public static int toInt(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
259        final int byte0 = 0xff & bytes[offset + 0];
260        final int byte1 = 0xff & bytes[offset + 1];
261        final int byte2 = 0xff & bytes[offset + 2];
262        final int byte3 = 0xff & bytes[offset + 3];
263        if (byteOrder == ByteOrder.BIG_ENDIAN) {
264            return (byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3;
265        } else {
266            return (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
267        }
268    }
269
270    public static int[] toInts(final byte[] bytes, final ByteOrder byteOrder) {
271        return toInts(bytes, 0, bytes.length, byteOrder);
272    }
273
274    private static int[] toInts(final byte[] bytes, final int offset, final int length,
275            final ByteOrder byteOrder) {
276        final int[] result = new int[length / 4];
277        for (int i = 0; i < result.length; i++) {
278            result[i] = toInt(bytes, offset + 4 * i, byteOrder);
279        }
280        return result;
281    }
282
283    public static float toFloat(final byte[] bytes, final ByteOrder byteOrder) {
284        return toFloat(bytes, 0, byteOrder);
285    }
286
287    private static float toFloat(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
288        final int byte0 = 0xff & bytes[offset + 0];
289        final int byte1 = 0xff & bytes[offset + 1];
290        final int byte2 = 0xff & bytes[offset + 2];
291        final int byte3 = 0xff & bytes[offset + 3];
292        final int bits;
293        if (byteOrder == ByteOrder.BIG_ENDIAN) {
294            bits = (byte0 << 24) | (byte1 << 16) | (byte2 << 8) | (byte3 << 0);
295        } else {
296            bits = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | (byte0 << 0);
297        }
298        return Float.intBitsToFloat(bits);
299    }
300
301    public static float[] toFloats(final byte[] bytes, final ByteOrder byteOrder) {
302        return toFloats(bytes, 0, bytes.length, byteOrder);
303    }
304
305    private static float[] toFloats(final byte[] bytes, final int offset,
306            final int length, final ByteOrder byteOrder) {
307        final float[] result = new float[length / 4];
308        for (int i = 0; i < result.length; i++) {
309            result[i] = toFloat(bytes, offset + 4 * i, byteOrder);
310        }
311        return result;
312    }
313
314    public static double toDouble(final byte[] bytes, final ByteOrder byteOrder) {
315        return toDouble(bytes, 0, byteOrder);
316    }
317
318    private static double toDouble(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
319        final long byte0 = 0xffL & bytes[offset + 0];
320        final long byte1 = 0xffL & bytes[offset + 1];
321        final long byte2 = 0xffL & bytes[offset + 2];
322        final long byte3 = 0xffL & bytes[offset + 3];
323        final long byte4 = 0xffL & bytes[offset + 4];
324        final long byte5 = 0xffL & bytes[offset + 5];
325        final long byte6 = 0xffL & bytes[offset + 6];
326        final long byte7 = 0xffL & bytes[offset + 7];
327        final long bits;
328        if (byteOrder == ByteOrder.BIG_ENDIAN) {
329            bits = (byte0 << 56) | (byte1 << 48) | (byte2 << 40)
330                    | (byte3 << 32) | (byte4 << 24) | (byte5 << 16)
331                    | (byte6 << 8) | (byte7 << 0);
332        } else {
333            bits = (byte7 << 56) | (byte6 << 48) | (byte5 << 40)
334                    | (byte4 << 32) | (byte3 << 24) | (byte2 << 16)
335                    | (byte1 << 8) | (byte0 << 0);
336        }
337        return Double.longBitsToDouble(bits);
338    }
339
340    public static double[] toDoubles(final byte[] bytes, final ByteOrder byteOrder) {
341        return toDoubles(bytes, 0, bytes.length, byteOrder);
342    }
343
344    private static double[] toDoubles(final byte[] bytes, final int offset,
345            final int length, final ByteOrder byteOrder) {
346        final double[] result = new double[length / 8];
347        for (int i = 0; i < result.length; i++) {
348            result[i] = toDouble(bytes, offset + 8 * i, byteOrder);
349        }
350        return result;
351    }
352
353    public static RationalNumber toRational(final byte[] bytes, final ByteOrder byteOrder) {
354        return toRational(bytes, 0, byteOrder);
355    }
356
357    private static RationalNumber toRational(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
358        final int byte0 = 0xff & bytes[offset + 0];
359        final int byte1 = 0xff & bytes[offset + 1];
360        final int byte2 = 0xff & bytes[offset + 2];
361        final int byte3 = 0xff & bytes[offset + 3];
362        final int byte4 = 0xff & bytes[offset + 4];
363        final int byte5 = 0xff & bytes[offset + 5];
364        final int byte6 = 0xff & bytes[offset + 6];
365        final int byte7 = 0xff & bytes[offset + 7];
366        final int numerator;
367        final int divisor;
368        if (byteOrder == ByteOrder.BIG_ENDIAN) {
369            numerator = (byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3;
370            divisor = (byte4 << 24) | (byte5 << 16) | (byte6 << 8) | byte7;
371        } else {
372            numerator = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
373            divisor = (byte7 << 24) | (byte6 << 16) | (byte5 << 8) | byte4;
374        }
375        return new RationalNumber(numerator, divisor);
376    }
377
378    public static RationalNumber[] toRationals(final byte[] bytes, final ByteOrder byteOrder) {
379        return toRationals(bytes, 0, bytes.length, byteOrder);
380    }
381
382    private static RationalNumber[] toRationals(final byte[] bytes,
383            final int offset, final int length, final ByteOrder byteOrder) {
384        final RationalNumber[] result = new RationalNumber[length / 8];
385        for (int i = 0; i < result.length; i++) {
386            result[i] = toRational(bytes, offset + 8 * i, byteOrder);
387        }
388        return result;
389    }
390}