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