    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        }
    237        return ((byte1 << 8) | byte0);
    238    }
    239
    240    public static int[] toUInt16s(final byte[] bytes, final ByteOrder byteOrder) {
    241        return toUInt16s(bytes, 0, bytes.length, byteOrder);
    242    }
    243
    244    private static int[] toUInt16s(final byte[] bytes, final int offset, final int length,
    245            final ByteOrder byteOrder) {
    246        final int[] result = new int[length / 2];
    247        for (int i = 0; i < result.length; i++) {
    248            result[i] = toUInt16(bytes, offset + 2 * i, byteOrder);
    249        }
    250        return result;
    251    }
    252
    253    public static int toInt(final byte[] bytes, final ByteOrder byteOrder) {
    254        return toInt(bytes, 0, byteOrder);
    255    }
    256
    257    public static int toInt(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
    258        final int byte0 = 0xff & bytes[offset + 0];
    259        final int byte1 = 0xff & bytes[offset + 1];
    260        final int byte2 = 0xff & bytes[offset + 2];
    261        final int byte3 = 0xff & bytes[offset + 3];
    262        if (byteOrder == ByteOrder.BIG_ENDIAN) {
    263            return (byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3;
    264        }
    265        return (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
    266    }
    267
    268    public static int[] toInts(final byte[] bytes, final ByteOrder byteOrder) {
    269        return toInts(bytes, 0, bytes.length, byteOrder);
    270    }
    271
    272    private static int[] toInts(final byte[] bytes, final int offset, final int length,
    273            final ByteOrder byteOrder) {
    274        final int[] result = new int[length / 4];
    275        for (int i = 0; i < result.length; i++) {
    276            result[i] = toInt(bytes, offset + 4 * i, byteOrder);
    277        }
    278        return result;
    279    }
    280
    281    public static float toFloat(final byte[] bytes, final ByteOrder byteOrder) {
    282        return toFloat(bytes, 0, byteOrder);
    283    }
    284
    285    private static float toFloat(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
    286        final int byte0 = 0xff & bytes[offset + 0];
    287        final int byte1 = 0xff & bytes[offset + 1];
    288        final int byte2 = 0xff & bytes[offset + 2];
    289        final int byte3 = 0xff & bytes[offset + 3];
    290        final int bits;
    291        if (byteOrder == ByteOrder.BIG_ENDIAN) {
    292            bits = (byte0 << 24) | (byte1 << 16) | (byte2 << 8) | (byte3 << 0);
    293        } else {
    294            bits = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | (byte0 << 0);
    295        }
    296        return Float.intBitsToFloat(bits);
    297    }
    298
    299    public static float[] toFloats(final byte[] bytes, final ByteOrder byteOrder) {
    300        return toFloats(bytes, 0, bytes.length, byteOrder);
    301    }
    302
    303    private static float[] toFloats(final byte[] bytes, final int offset,
    304            final int length, final ByteOrder byteOrder) {
    305        final float[] result = new float[length / 4];
    306        for (int i = 0; i < result.length; i++) {
    307            result[i] = toFloat(bytes, offset + 4 * i, byteOrder);
    308        }
    309        return result;
    310    }
    311
    312    public static double toDouble(final byte[] bytes, final ByteOrder byteOrder) {
    313        return toDouble(bytes, 0, byteOrder);
    314    }
    315
    316    private static double toDouble(final byte[] bytes, final int offset, final ByteOrder byteOrder) {
    317        final long byte0 = 0xffL & bytes[offset + 0];
    318        final long byte1 = 0xffL & bytes[offset + 1];
    319        final long byte2 = 0xffL & bytes[offset + 2];
    320        final long byte3 = 0xffL & bytes[offset + 3];
    321        final long byte4 = 0xffL & bytes[offset + 4];
    322        final long byte5 = 0xffL & bytes[offset + 5];
    323        final long byte6 = 0xffL & bytes[offset + 6];
    324        final long byte7 = 0xffL & bytes[offset + 7];
    325        final long bits;
    326        if (byteOrder == ByteOrder.BIG_ENDIAN) {
    327            bits = (byte0 << 56) | (byte1 << 48) | (byte2 << 40)
    328                    | (byte3 << 32) | (byte4 << 24) | (byte5 << 16)
    329                    | (byte6 << 8) | (byte7 << 0);
    330        } else {
    331            bits = (byte7 << 56) | (byte6 << 48) | (byte5 << 40)
    332                    | (byte4 << 32) | (byte3 << 24) | (byte2 << 16)
    333                    | (byte1 << 8) | (byte0 << 0);
    334        }
    335        return Double.longBitsToDouble(bits);
    336    }
    337
    338    public static double[] toDoubles(final byte[] bytes, final ByteOrder byteOrder) {
    339        return toDoubles(bytes, 0, bytes.length, byteOrder);
    340    }
    341
    342    private static double[] toDoubles(final byte[] bytes, final int offset,
    343            final int length, final ByteOrder byteOrder) {
    344        final double[] result = new double[length / 8];
    345        for (int i = 0; i < result.length; i++) {
    346            result[i] = toDouble(bytes, offset + 8 * i, byteOrder);
    347        }
    348        return result;
    349    }
    350
    351    /**
    352     * Interprets the content of a specified bytes array to create
    353     * an instance of the RationalNumber class.
    354     * @param bytes a valid array dimensioned to at least 8.
    355     * @param byteOrder the byte order for integer conversion
    356     * @param unsignedType indicates whether the extracted value is
    357     * an unsigned type.
    358     * @return a valid instance
    359     */
    360    public static RationalNumber toRational(
    361            final byte[] bytes,
    362            final ByteOrder byteOrder,
    363            final boolean unsignedType) {
    364        return toRational(bytes, 0, byteOrder, unsignedType);
    365    }
    366
    367    private static RationalNumber toRational(
    368            final byte[] bytes,
    369            final int offset,
    370            final ByteOrder byteOrder,
    371            final boolean unsignedType) {
    372        final int byte0 = 0xff & bytes[offset + 0];
    373        final int byte1 = 0xff & bytes[offset + 1];
    374        final int byte2 = 0xff & bytes[offset + 2];
    375        final int byte3 = 0xff & bytes[offset + 3];
    376        final int byte4 = 0xff & bytes[offset + 4];
    377        final int byte5 = 0xff & bytes[offset + 5];
    378        final int byte6 = 0xff & bytes[offset + 6];
    379        final int byte7 = 0xff & bytes[offset + 7];
    380        final int numerator;
    381        final int divisor;
    382        if (byteOrder == ByteOrder.BIG_ENDIAN) {
    383            numerator = (byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3;
    384            divisor = (byte4 << 24) | (byte5 << 16) | (byte6 << 8) | byte7;
    385        } else {
    386            numerator = (byte3 << 24) | (byte2 << 16) | (byte1 << 8) | byte0;
    387            divisor = (byte7 << 24) | (byte6 << 16) | (byte5 << 8) | byte4;
    388        }
    389        return new RationalNumber(numerator, divisor, unsignedType);
    390    }
    391
    392    public static RationalNumber[] toRationals(
    393            final byte[] bytes,
    394            final ByteOrder byteOrder,
    395            boolean unsignedType) {
    396        return toRationals(bytes, 0, bytes.length, byteOrder, unsignedType);
    397    }
    398
    399    private static RationalNumber[] toRationals(
    400            final byte[] bytes,
    401            final int offset,
    402            final int length,
    403            final ByteOrder byteOrder,
    404            boolean unsignedType) {
    405        final RationalNumber[] result = new RationalNumber[length / 8];
    406        for (int i = 0; i < result.length; i++) {
    407            result[i] = toRational(bytes, offset + 8 * i, byteOrder, unsignedType);
    408        }
    409        return result;
    410    }
    411}