2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.protocol.util;
11 import java.io.FileInputStream;
12 import java.io.IOException;
13 import java.nio.ByteBuffer;
14 import java.nio.charset.CharacterCodingException;
15 import java.nio.charset.Charset;
16 import java.util.Arrays;
17 import java.util.BitSet;
19 import org.apache.commons.codec.binary.Hex;
23 * Util class for methods working with byte array.
26 public final class ByteArray {
31 * Returns a new byte array from given byte array, starting at start index
32 * with the size of the length parameter. Byte array given as parameter
38 * beginning index, inclusive
40 * how many bytes should be in the sub-array
41 * @return a new byte array that is a sub-array of the original
43 public static byte[] subByte(final byte[] bytes, int startIndex, int length) {
44 if (bytes.length == 0 || length < 0 || length > bytes.length || startIndex < 0 || startIndex > bytes.length || startIndex + length > bytes.length) {
45 throw new IllegalArgumentException("Cannot create subByte, invalid arguments: Length: " + length + " startIndex: " + startIndex);
47 final byte[] res = new byte[length];
48 System.arraycopy(bytes, startIndex, res, 0, length);
53 * Converts byte array to Integer. If there are less bytes in the array as
54 * required (4), the method will push adequate number of zero bytes
55 * prepending given byte array.
58 * array to be converted to int
61 public static int bytesToInt(byte[] bytes) {
62 if (bytes.length > Integer.SIZE / 8) {
63 throw new IllegalArgumentException("Cannot convert bytes to integer. Byte array too big.");
65 byte[] res = new byte[Integer.SIZE / 8];
66 if (bytes.length != Integer.SIZE / 8) {
67 System.arraycopy(bytes, 0, res, Integer.SIZE / 8 - bytes.length, bytes.length);
71 final ByteBuffer buff = ByteBuffer.wrap(res);
76 * Converts byte array to long. If there are less bytes in the array as
77 * required (Long.Size), the method will push adequate number of zero bytes
78 * prepending given byte array.
81 * array to be converted to long
84 public static long bytesToLong(byte[] bytes) {
85 if (bytes.length > Long.SIZE / 8) {
86 throw new IllegalArgumentException("Cannot convert bytes to long.Byte array too big.");
88 byte[] res = new byte[Long.SIZE / 8];
89 if (bytes.length != Long.SIZE / 8) {
90 System.arraycopy(bytes, 0, res, Long.SIZE / 8 - bytes.length, bytes.length);
94 final ByteBuffer buff = ByteBuffer.wrap(res);
95 return buff.getLong();
99 * Converts byte array to float IEEE 754 format. If there are less bytes in
100 * the array as required (Float.Size), the method will push adequate number
101 * of zero bytes prepending given byte array.
104 * array to be converted to float
107 public static float bytesToFloat(byte[] bytes) {
108 if (bytes.length > Float.SIZE / 8) {
109 throw new IllegalArgumentException("Cannot convert bytes to float.Byte array too big.");
111 byte[] res = new byte[Float.SIZE / 8];
112 if (bytes.length != Float.SIZE / 8) {
113 System.arraycopy(bytes, 0, res, Float.SIZE / 8 - bytes.length, bytes.length);
117 final ByteBuffer buff = ByteBuffer.wrap(res);
118 return buff.getFloat();
122 * Cuts 'count' number of bytes from the beginning of given byte array.
125 * array to be cut, cannot be null
127 * how many bytes needed to be cut, needs to be > 0
128 * @return bytes array without first 'count' bytes
130 public static byte[] cutBytes(byte[] bytes, int count) {
131 if (bytes.length == 0 || count > bytes.length || count <= 0) {
132 throw new IllegalArgumentException("Cannot cut bytes, invalid arguments: Count: " + count + " bytes.length: " + bytes.length);
134 return Arrays.copyOfRange(bytes, count, bytes.length);
138 * Parse byte to bits, from the leftmost bit.
142 * @return array of booleans with size of 8
144 public static boolean[] parseBits(byte b) {
145 final boolean[] bits = new boolean[Byte.SIZE];
147 for (int i = Byte.SIZE - 1; i >= 0; i--) {
148 bits[j] = ((b & (1 << i)) != 0);
155 * Parses array of bytes to BitSet, from left most bit.
158 * array of bytes to be parsed
159 * @return BitSet with length = bytes.length * Byte.SIZE
161 public static BitSet bytesToBitSet(byte[] bytes) {
162 final BitSet bitSet = new BitSet(bytes.length * Byte.SIZE);
163 for (int bytes_iter = 0; bytes_iter < bytes.length; bytes_iter++) {
164 final int offset = bytes_iter * Byte.SIZE;
165 for (int byte_iter = Byte.SIZE - 1; byte_iter >= 0; byte_iter--) {
166 bitSet.set(offset + (Byte.SIZE - byte_iter - 1), (bytes[bytes_iter] & 1 << (byte_iter)) != 0);
173 * Parses BitSet to bytes, from most left bit.
176 * BitSet to be parsed
177 * @param returnedLength
178 * Length of returned array. Overlapping flags are truncated.
179 * @return parsed array of bytes with length of bitSet.length / Byte.SIZE
181 public static byte[] bitSetToBytes(BitSet bitSet, int returnedLength) {
182 final byte[] bytes = new byte[returnedLength];
184 for (int bytes_iter = 0; bytes_iter < bytes.length; bytes_iter++) {
185 final int offset = bytes_iter * Byte.SIZE;
187 for (int byte_iter = Byte.SIZE - 1; byte_iter >= 0; byte_iter--) {
188 bytes[bytes_iter] |= (bitSet.get(offset + (Byte.SIZE - byte_iter - 1)) ? 1 << byte_iter : 0);
195 * Parses file to array of bytes
198 * path to file to by parsed
199 * @return parsed array of bytes
201 public static byte[] fileToBytes(String name) throws IOException {
202 final File file = new File(name);
206 if (file.length() > Integer.MAX_VALUE) {
207 throw new IOException("Too large file to load in byte array.");
210 final FileInputStream fin = new FileInputStream(file);
211 final byte[] byteArray = new byte[(int) file.length()];
213 while (offset < byteArray.length && (numRead = fin.read(byteArray, offset, byteArray.length - offset)) >= 0) {
225 * Parses integer to array of bytes
228 * integer to be parsed
229 * @return parsed array of bytes with length of Integer.SIZE/Byte.SIZE
231 public static byte[] intToBytes(int num) {
232 final ByteBuffer bytesBuffer = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE);
233 bytesBuffer.putInt(num);
235 return bytesBuffer.array();
239 * Parses integer to array of bytes
242 * integer to be parsed
243 * @return parsed array of bytes with length of Long.SIZE/Byte.SIZE
245 public static byte[] longToBytes(long num) {
246 final ByteBuffer bytesBuffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE);
247 bytesBuffer.putLong(num);
249 return bytesBuffer.array();
253 * Copies range of bits from passed byte and align to right.<br/>
256 * source byte to copy from
258 * bit from which will copy (inclusive) - numbered from 0
260 * of bits to by copied - <1,8>
261 * @return copied value aligned to right
263 public static byte copyBitsRange(byte src, int fromBit, int length) {
264 if (fromBit < 0 | fromBit > Byte.SIZE - 1 | length < 1 | length > Byte.SIZE) {
265 throw new IllegalArgumentException("fromBit or toBit is out of range.");
267 if (fromBit + length > Byte.SIZE) {
268 throw new IllegalArgumentException("Out of range.");
274 for (int i = fromBit + length - 1; i >= fromBit; i--) {
276 if ((src & 1 << (Byte.SIZE - i - 1)) != 0) {
277 retByte |= 1 << retI;
287 * Copies whole source byte array to destination from offset.<br/>
288 * Length of src can't be bigger than dest length minus offset
297 public static void copyWhole(byte[] src, byte[] dest, int offset) {
298 if (dest.length - offset < src.length) {
299 throw new ArrayIndexOutOfBoundsException("Can't copy whole array.");
302 System.arraycopy(src, 0, dest, offset, src.length);
306 * Convert array of bytes to java short.<br/>
307 * Size can't be bigger than size of short in bytes.
311 * @return array of bytes
313 public static short bytesToShort(byte[] bytes) {
314 if (bytes.length > Short.SIZE / Byte.SIZE) {
315 throw new IllegalArgumentException("Cannot convert bytes to short. Byte array too big.");
317 byte[] res = new byte[Short.SIZE / Byte.SIZE];
318 if (bytes.length != Short.SIZE / Byte.SIZE) {
319 System.arraycopy(bytes, 0, res, Integer.SIZE / Byte.SIZE - bytes.length, bytes.length);
323 final ByteBuffer buff = ByteBuffer.wrap(res);
324 return buff.getShort();
328 * Convert short java representation to array of bytes.
332 * @return short represented as array of bytes
334 public static byte[] shortToBytes(short num) {
335 final ByteBuffer bytesBuffer = ByteBuffer.allocate(Short.SIZE / Byte.SIZE);
336 bytesBuffer.putShort(num);
338 return bytesBuffer.array();
342 * Convert float java representation to array of bytes.
346 * @return float represented as array of bytes
348 public static byte[] floatToBytes(float num) {
349 final ByteBuffer bytesBuffer = ByteBuffer.allocate(Float.SIZE / Byte.SIZE);
350 bytesBuffer.putFloat(num);
352 return bytesBuffer.array();
356 * Pretty print array of bytes as hex encoded string with 16 bytes per line.
357 * Each byte is separated by space, after first 8 bytes there are 2 spaces
360 public static String bytesToHexString(byte[] array) {
361 return bytesToHexString(array, 16, " ", 8, " ");
365 * Pretty-print an array of bytes as hex-encoded string. Separate them
366 * with specified separator.
368 public static String toHexString(final byte[] array, final String separator) {
369 final StringBuilder sb = new StringBuilder();
370 for (int i = 0; i < array.length; i++) {
371 sb.append(Hex.encodeHexString(new byte[] { array[i] }));
372 if (i + 1 != array.length)
373 sb.append(separator);
375 return sb.toString();
379 * Convert array of bytes to hexadecimal String.
383 * number of bytes that should by displayed in one line
384 * @param byteSeparator
385 * string that will be placed after each byte
387 * number of bytes that make a 'word' (group of bytes)
388 * @param wordSeparator
389 * string that will be placed after each word
390 * @return Hexadecimal string representation of given byte array
392 public static String bytesToHexString(byte[] array, int bytesOnLine, String byteSeparator, int wordCount, String wordSeparator) {
393 final StringBuilder sb = new StringBuilder();
394 for (int i = 0; i < array.length; i++) {
395 sb.append(Hex.encodeHexString(new byte[] { array[i] }));
396 if ((i + 1) % bytesOnLine == 0) {
399 sb.append(byteSeparator);
400 if ((i + 1) % wordCount == 0) {
401 sb.append(wordSeparator);
406 return sb.toString();
410 * Decodes bytes to human readable UTF-8 string. If bytes are not valid
411 * UTF-8, they are represented as raw binary.
414 * bytes to be decoded to string
415 * @return String representation of passed bytes
417 public static String bytesToHRString(byte[] bytes) {
419 return Charset.forName("UTF-8").newDecoder().decode(ByteBuffer.wrap(bytes)).toString();
420 } catch (final CharacterCodingException e) {
421 return Arrays.toString(bytes);
426 * Searches for byte sequence in given array. Returns the index of first occurrence of
427 * this sequence (where it starts).
428 * @param bytes byte array where to search for sequence
429 * @param sequence to be searched in given byte array
430 * @return -1 if the sequence could not be found in given byte array
431 * int index of first occurrence of the sequence in bytes
433 public static int findByteSequence(byte[] bytes, byte[] sequence) {
434 if (bytes.length < sequence.length)
435 throw new IllegalArgumentException("Sequence to be found is longer than the given byte array.");
436 if (bytes.length == sequence.length)
437 if (Arrays.equals(bytes, sequence))
442 for (int i = 0; i < bytes.length; i++) {
443 if (bytes[i] == sequence[j]) {
445 if (j == sequence.length)
453 private static final byte maskBits[] = new byte[] { 0, -128, -64, -32, -16, -8, -4, -2 };
454 public static final byte[] maskBytes(final byte[] original,
456 if (original.length * 8 < bits)
457 throw new IllegalArgumentException("Attempted to apply invalid mask (too long)");
459 final int needbytes = (bits +7) / 8;
460 // We need to have a new copy of the underlying byte array, so that
461 // the original bytes stay untouched
462 final byte[] bytes = Arrays.copyOf(original, original.length);
464 final int needmask = bits % 8;
466 bytes[needbytes-1] &= maskBits[needmask];
468 // zero-out the rest of the bytes
469 for (int i = needbytes ; i < bytes.length; i++) {