    001/**
    002 * Copyright (c) 2014 Digi International Inc.,
    003 * All rights not expressly granted are reserved.
    004 *
    005 * This Source Code Form is subject to the terms of the Mozilla Public
    006 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
    007 * You can obtain one at http://mozilla.org/MPL/2.0/.
    008 *
    009 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
    010 * =======================================================================
    011 */
    012package com.digi.xbee.api.utils;
    013
    014import java.io.ByteArrayInputStream;
    015import java.io.ByteArrayOutputStream;
    016
    017/**
    018 * Utility class containing methods to work with bytes and byte arrays and
    019 * several data type conversions.
    020 */
    021public class ByteUtils {
    022
    023        /**
    024         * Reads the given amount of bytes from the given byte array input stream.
    025         *
    026         * @param numBytes Number of bytes to read.
    027         * @param inputStream Byte array input stream to read bytes from.
    028         *
    029         * @return An array with the read bytes.
    030         *
    031         * @throws IllegalArgumentException if {@code numBytes < 0}.
    032         * @throws NullPointerException if {@code inputStream == null}.
    033         *
    034         * @see #readString(ByteArrayInputStream)
    035         * @see #readUntilCR(ByteArrayInputStream)
    036         */
    037        public static byte[] readBytes(int numBytes, ByteArrayInputStream inputStream) {
    038                if (inputStream == null)
    039                        throw new NullPointerException("Input stream cannot be null.");
    040                if (numBytes < 0)
    041                        throw new IllegalArgumentException("Number of bytes to read must be great than 0.");
    042
    043                byte[] data = new byte[numBytes];
    044                inputStream.read(data, 0, numBytes);
    045                return data;
    046        }
    047
    048        /**
    049         * Reads a null-terminated string from the given byte array input stream.
    050         *
    051         * @param inputStream Byte array input stream to read string  from.
    052         *
    053         * @return The read string from the given {@code ByteArrayInputStream}.
    054         *
    055         * @throws NullPointerException if {@code inputStream == null}.
    056         *
    057         * @see #readBytes(int, ByteArrayInputStream)
    058         * @see #readUntilCR(ByteArrayInputStream)
    059         */
    060        public static String readString(ByteArrayInputStream inputStream) {
    061                if (inputStream == null)
    062                        throw new NullPointerException("Input stream cannot be null.");
    063
    064                StringBuilder sb = new StringBuilder();
    065                byte readByte;
    066                while (((readByte = (byte)inputStream.read()) != 0x00) && readByte != -1)
    067                        sb.append((char)readByte);
    068                return sb.toString();
    069        }
    070
    071        /**
    072         * Converts the given long value into a byte array.
    073         *
    074         * @param value Long value to convert to byte array.
    075         *
    076         * @return Byte array of the given long value (8 bytes length).
    077         *
    078         * @see #byteArrayToLong(byte[])
    079         */
    080        public static byte[] longToByteArray(long value) {
    081                return new byte[] {
    082                                (byte)((value >>> 56) & 0xFF),
    083                                (byte)((value >>> 48) & 0xFF),
    084                                (byte)((value >>> 40) & 0xFF),
    085                                (byte)((value >>> 32) & 0xFF),
    086                                (byte)((value >>> 24) & 0xFF),
    087                                (byte)((value >>> 16) & 0xFF),
    088                                (byte)((value >>> 8) & 0xFF),
    089                                (byte)(value & 0xFF)
    090                };
    091        }
    092
    093        /**
    094         * Converts the given byte array (8 bytes length max) into a long.
    095         *
    096         * @param byteArray Byte array to convert to long (8 bytes length max).
    097         *
    098         * @return Converted long value.
    099         *
    100         * @throws NullPointerException if {@code b == null}.
    101         *
    102         * @see #longToByteArray(long)
    103         */
    104        public static long byteArrayToLong(byte[] byteArray) {
    105                if (byteArray == null)
    106                        throw new NullPointerException("Byte array cannot be null.");
    107
    108                byte[] values = byteArray;
    109                if (byteArray.length < 8) {
    110                        values = new byte[8];
    111                        int diff = 8 - byteArray.length;
    112                        for (int i = 0; i < diff; i++)
    113                                values[i] = 0;
    114                        for (int i = diff; i < 8; i++)
    115                                values[i] = byteArray[i - diff];
    116                }
    117                return ((long)values[0] << 56)
    118                                + ((long)(values[1] & 0xFF) << 48)
    119                                + ((long)(values[2] & 0xFF) << 40)
    120                                + ((long)(values[3] & 0xFF) << 32)
    121                                + ((long)(values[4] & 0xFF) << 24)
    122                                + ((values[5] & 0xFF) << 16)
    123                                + ((values[6] & 0xFF) <<  8)
    124                                + (values[7] & 0xFF);
    125        }
    126
    127        /**
    128         * Converts the given integer value into a byte array.
    129         *
    130         * @param value Integer value to convert to byte array.
    131         *
    132         * @return Byte array of the given integer (4 bytes length).
    133         *
    134         * @see #byteArrayToInt(byte[])
    135         */
    136        public static byte[] intToByteArray(int value) {
    137                return new byte[] {
    138                                (byte)((value >>> 24) & 0xFF),
    139                                (byte)((value >>> 16) & 0xFF),
    140                                (byte)((value >>> 8) & 0xFF),
    141                                (byte)(value & 0xFF)
    142                };
    143        }
    144
    145        /**
    146         * Converts the given byte array (4 bytes length max) into an integer.
    147         *
    148         * @param byteArray Byte array to convert to integer (4 bytes length max).
    149         *
    150         * @return Converted integer value.
    151         *
    152         * @throws NullPointerException if {@code byteArray == null}.
    153         *
    154         * @see #intToByteArray(int)
    155         */
    156        public static int byteArrayToInt(byte[] byteArray) {
    157                if (byteArray == null)
    158                        throw new NullPointerException("Byte array cannot be null.");
    159
    160                byte[] values = byteArray;
    161                if (byteArray.length < 4) {
    162                        values = new byte[4];
    163                        int diff = 4 - byteArray.length;
    164                        for (int i = 0; i < diff; i++)
    165                                values[i] = 0;
    166                        for (int i = diff; i < 4; i++)
    167                                values[i] = byteArray[i - diff];
    168                }
    169                return ((values[0] & 0xFF) << 24)
    170                                | ((values[1] & 0xFF) << 16)
    171                                | ((values[2] & 0xFF) << 8)
    172                                | (values[3] & 0xFF);
    173        }
    174
    175        /**
    176         * Converts the given short value into a byte array.
    177         *
    178         * @param value Short value to convert to byte array.
    179         *
    180         * @return Byte array of the given short (2 bytes length).
    181         *
    182         * @see #byteArrayToShort(byte[])
    183         */
    184        public static byte[] shortToByteArray(short value) {
    185                byte[] b = new byte[2];
    186                b[0] = (byte)((value >> 8) & 0xFF);
    187                b[1] = (byte)(value & 0xFF);
    188                return b;
    189        }
    190
    191        /**
    192         * Converts the given byte array (2 bytes length max) to short.
    193         *
    194         * @param byteArray Byte array to convert to short (2 bytes length max).
    195         *
    196         * @return Converted short value.
    197         *
    198         * @throws NullPointerException if {@code byteArray == null}.
    199         *
    200         * @see #shortToByteArray(short)
    201         */
    202        public static short byteArrayToShort(byte[] byteArray) {
    203                if (byteArray == null)
    204                        throw new NullPointerException("Byte array cannot be null.");
    205
    206                return (short) (((byteArray[0] << 8) & 0xFF00)
    207                                                | byteArray[1] & 0x00FF);
    208        }
    209
    210        /**
    211         * Converts the given string into a byte array.
    212         *
    213         * @param value String to convert to byte array.
    214         *
    215         * @return Byte array of the given string.
    216         *
    217         * @throws NullPointerException if {@code value == null}.
    218         *
    219         * @see #byteArrayToString(byte[])
    220         */
    221        public static byte[] stringToByteArray(String value) {
    222                if (value == null)
    223                        throw new NullPointerException("Value cannot be null.");
    224
    225                return value.getBytes();
    226        }
    227
    228        /**
    229         * Converts the given byte array into a string.
    230         *
    231         * @param value Byte array to convert to string.
    232         *
    233         * @return Converted String.
    234         *
    235         * @throws NullPointerException if {@code value == null}.
    236         */
    237        public static String byteArrayToString(byte[] value) {
    238                if (value == null)
    239                        throw new NullPointerException("Byte array cannot be null.");
    240
    241                return new String(value);
    242        }
    243
    244        /**
    245         * Converts the given byte into an integer.
    246         *
    247         * @param b Byte to convert to integer.
    248         *
    249         * @return Converted byte into integer.
    250         */
    251        public static int byteToInt(byte b) {
    252                return (int) b & 0xFF;
    253        }
    254
    255        /**
    256         * Returns whether the specified bit of the given integer is set to 1
    257         * or not.
    258         *
    259         * @param containerInteger Integer to check the given bit position
    260         *                         enablement state.
    261         * @param bitPosition Position of the bit to check its enablement state.
    262         *
    263         * @return {@code true} if the given bit position is set to {@code 1}
    264         *         in the {@code containerInteger}, {@code false} otherwise.
    265         */
    266        public static boolean isBitEnabled(int containerInteger, int bitPosition) {
    267                return (((containerInteger & 0xFFFFFFFF) >> bitPosition) & 0x01) == 0x01;
    268        }
    269
    270        /**
    271         * Reads an integer value from the given byte using the given bit offset
    272         * and the given bit size.
    273         *
    274         * @param containerByte Byte to read the integer from.
    275         * @param bitOffset Offset inside the byte to start reading integer value.
    276         * @param bitLength Size in bits of the integer value to read.
    277         *
    278         * @return The integer read value.
    279         */
    280        public static int readIntegerFromByte(byte containerByte, int bitOffset, int bitLength) {
    281                int readInteger = 0;
    282                for (int i = 0; i < bitLength; i++) {
    283                        if (isBitEnabled(containerByte, bitOffset + i))
    284                                readInteger = readInteger | (int)Math.pow(2, i);
    285                }
    286                return readInteger;
    287        }
    288
    289        /**
    290         * Reads a boolean value from the given byte at the given bit position.
    291         *
    292         * @param containerByte Byte to read boolean value from.
    293         * @param bitOffset Offset inside the byte to read the boolean value.
    294         *
    295         * @return The read boolean value.
    296         */
    297        public static boolean readBooleanFromByte(byte containerByte, int bitOffset) {
    298                return isBitEnabled(containerByte, bitOffset);
    299        }
    300
    301        /**
    302         * Reads from the given byte array input stream until a CR character is
    303         * found or the end of stream is reached. Read bytes are returned.
    304         *
    305         * @param inputStream Byte array input stream to read from.
    306         *
    307         * @return An array with the read bytes.
    308         *
    309         * @throws NullPointerException if {@code inputStream == null}.
    310         *
    311         * @see #readBytes(int, ByteArrayInputStream)
    312         * @see #readString(ByteArrayInputStream)
    313         */
    314        public static byte[] readUntilCR(ByteArrayInputStream inputStream) {
    315                if (inputStream == null)
    316                        throw new NullPointerException("Input stream cannot be null.");
    317
    318                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    319                byte readByte;
    320                while (((readByte = (byte)inputStream.read()) != 0x0D) && readByte != -1)
    321                        outputStream.write(readByte);
    322                return outputStream.toByteArray();
    323        }
    324
    325        /**
    326         * Generates a new byte array of the given size using the given data and
    327         * filling with ASCII zeros (0x48) the remaining space.
    328         *
    329         * <p>If new size is lower than current, array is truncated.</p>
    330         *
    331         * @param data Data to use in the new array.
    332         * @param finalSize Final size of the array.
    333         *
    334         * @return Final byte array of the given size containing the given data and
    335         *         replacing with zeros the remaining space.
    336         *
    337         * @throws NullPointerException if {@code data == null}.
    338         */
    339        public static byte[] newByteArray(byte[] data, int finalSize) {
    340                if (data == null)
    341                        throw new NullPointerException("Data cannot be null.");
    342
    343                byte[] filledArray = new byte[finalSize];
    344                int diff = finalSize - data.length;
    345                if (diff >= 0) {
    346                        for (int i = 0; i < diff; i++)
    347                                filledArray[i] = '0';
    348                        System.arraycopy(data, 0, filledArray, diff, data.length);
    349                } else
    350                        System.arraycopy(data, 0, filledArray, 0, finalSize);
    351                return filledArray;
    352        }
    353
    354        /**
    355         * Swaps the given byte array order.
    356         *
    357         * @param source Byte array to swap.
    358         *
    359         * @return The swapped byte array.
    360         */
    361        public static byte[] swapByteArray(byte[] source) {
    362                byte[] swapped = new byte[source.length];
    363                for (int i = 0; i < source.length; i++)
    364                        swapped[source.length - i - 1] = source[i];
    365                return swapped;
    366        }
    367}