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 with the size of the length parameter.
32 * Byte array given as parameter stays untouched.
34 * @param bytes original byte array
35 * @param startIndex beginning index, inclusive
36 * @param length how many bytes should be in the sub-array
37 * @return a new byte array that is a sub-array of the original
39 public static byte[] subByte(final byte[] bytes, final int startIndex, final int length) {
40 if (bytes.length == 0 || length < 0 || length > bytes.length || startIndex < 0 || startIndex > bytes.length
41 || startIndex + length > bytes.length) {
42 throw new IllegalArgumentException("Cannot create subByte, invalid arguments: Length: " + length + " startIndex: " + startIndex);
44 final byte[] res = new byte[length];
45 System.arraycopy(bytes, startIndex, res, 0, length);
50 * Converts byte array to Integer. If there are less bytes in the array as required (4), the method will push
51 * adequate number of zero bytes prepending given byte array.
53 * @param bytes array to be converted to int
56 public static int bytesToInt(final byte[] bytes) {
57 if (bytes.length > Integer.SIZE / 8) {
58 throw new IllegalArgumentException("Cannot convert bytes to integer. Byte array too big.");
60 byte[] res = new byte[Integer.SIZE / 8];
61 if (bytes.length != Integer.SIZE / 8) {
62 System.arraycopy(bytes, 0, res, Integer.SIZE / 8 - bytes.length, bytes.length);
66 final ByteBuffer buff = ByteBuffer.wrap(res);
71 * Converts byte array to long. If there are less bytes in the array as required (Long.Size), the method will push
72 * adequate number of zero bytes prepending given byte array.
74 * @param bytes array to be converted to long
77 public static long bytesToLong(final byte[] bytes) {
78 if (bytes.length > Long.SIZE / 8) {
79 throw new IllegalArgumentException("Cannot convert bytes to long.Byte array too big.");
81 byte[] res = new byte[Long.SIZE / 8];
82 if (bytes.length != Long.SIZE / 8) {
83 System.arraycopy(bytes, 0, res, Long.SIZE / 8 - bytes.length, bytes.length);
87 final ByteBuffer buff = ByteBuffer.wrap(res);
88 return buff.getLong();
92 * Converts byte array to float IEEE 754 format. If there are less bytes in the array as required (Float.Size), the
93 * method will push adequate number of zero bytes prepending given byte array.
95 * @param bytes array to be converted to float
98 public static float bytesToFloat(final byte[] bytes) {
99 if (bytes.length > Float.SIZE / 8) {
100 throw new IllegalArgumentException("Cannot convert bytes to float.Byte array too big.");
102 byte[] res = new byte[Float.SIZE / 8];
103 if (bytes.length != Float.SIZE / 8) {
104 System.arraycopy(bytes, 0, res, Float.SIZE / 8 - bytes.length, bytes.length);
108 final ByteBuffer buff = ByteBuffer.wrap(res);
109 return buff.getFloat();
113 * Cuts 'count' number of bytes from the beginning of given byte array.
115 * @param bytes array to be cut, cannot be null
116 * @param count how many bytes needed to be cut, needs to be > 0
117 * @return bytes array without first 'count' bytes
119 public static byte[] cutBytes(final byte[] bytes, final int count) {
120 if (bytes.length == 0 || count > bytes.length || count <= 0) {
121 throw new IllegalArgumentException("Cannot cut bytes, invalid arguments: Count: " + count + " bytes.length: " + bytes.length);
123 return Arrays.copyOfRange(bytes, count, bytes.length);
127 * Parse byte to bits, from the leftmost bit.
129 * @param b byte to be parsed
130 * @return array of booleans with size of 8
132 public static boolean[] parseBits(final byte b) {
133 final boolean[] bits = new boolean[Byte.SIZE];
135 for (int i = Byte.SIZE - 1; i >= 0; i--) {
136 bits[j] = ((b & (1 << i)) != 0);
143 * Parses array of bytes to BitSet, from left most bit.
145 * @param bytes array of bytes to be parsed
146 * @return BitSet with length = bytes.length * Byte.SIZE
148 public static BitSet bytesToBitSet(final byte[] bytes) {
149 final BitSet bitSet = new BitSet(bytes.length * Byte.SIZE);
150 for (int bytes_iter = 0; bytes_iter < bytes.length; bytes_iter++) {
151 final int offset = bytes_iter * Byte.SIZE;
152 for (int byte_iter = Byte.SIZE - 1; byte_iter >= 0; byte_iter--) {
153 bitSet.set(offset + (Byte.SIZE - byte_iter - 1), (bytes[bytes_iter] & 1 << (byte_iter)) != 0);
160 * Parses BitSet to bytes, from most left bit.
162 * @param bitSet BitSet to be parsed
163 * @param returnedLength Length of returned array. Overlapping flags are truncated.
164 * @return parsed array of bytes with length of bitSet.length / Byte.SIZE
166 public static byte[] bitSetToBytes(final BitSet bitSet, final int returnedLength) {
167 final byte[] bytes = new byte[returnedLength];
169 for (int bytes_iter = 0; bytes_iter < bytes.length; bytes_iter++) {
170 final int offset = bytes_iter * Byte.SIZE;
172 for (int byte_iter = Byte.SIZE - 1; byte_iter >= 0; byte_iter--) {
173 bytes[bytes_iter] |= (bitSet.get(offset + (Byte.SIZE - byte_iter - 1)) ? 1 << byte_iter : 0);
180 * Parses file to array of bytes
182 * @param name path to file to by parsed
183 * @return parsed array of bytes
185 public static byte[] fileToBytes(final String name) throws IOException {
186 final File file = new File(name);
190 if (file.length() > Integer.MAX_VALUE) {
191 throw new IOException("Too large file to load in byte array.");
194 final FileInputStream fin = new FileInputStream(file);
195 final byte[] byteArray = new byte[(int) file.length()];
197 while (offset < byteArray.length && (numRead = fin.read(byteArray, offset, byteArray.length - offset)) >= 0) {
209 * Parses integer to array of bytes
211 * @param num integer to be parsed
212 * @return parsed array of bytes with length of Integer.SIZE/Byte.SIZE
214 public static byte[] intToBytes(final int num) {
215 return intToBytes(num, Integer.SIZE / Byte.SIZE);
219 * Parses integer to array of bytes
221 * @param num integer to be parsed
222 * @param size desired byte array length
223 * @return parsed array of bytes with length of size
225 public static byte[] intToBytes(final int num, final int size) {
226 final int finalSize = Integer.SIZE / Byte.SIZE;
227 final ByteBuffer bytesBuffer = ByteBuffer.allocate(finalSize);
228 bytesBuffer.putInt(num);
229 return ByteArray.subByte(bytesBuffer.array(), finalSize - size, size);
233 * Parses long to array of bytes
235 * @param num long to be parsed
236 * @return parsed array of bytes with length of Long.SIZE/Byte.SIZE
238 public static byte[] longToBytes(final int num) {
239 return longToBytes(num, Long.SIZE / Byte.SIZE);
243 * Parses long to array of bytes
245 * @param num long to be parsed
246 * @param size desired byte array length
247 * @return parsed array of bytes with length of size
249 public static byte[] longToBytes(final long num, final int size) {
250 final int finalSize = Long.SIZE / Byte.SIZE;
251 final ByteBuffer bytesBuffer = ByteBuffer.allocate(finalSize);
252 bytesBuffer.putLong(num);
253 return ByteArray.subByte(bytesBuffer.array(), finalSize - size, size);
257 * Copies range of bits from passed byte and align to right.<br/>
259 * @param src source byte to copy from
260 * @param fromBit bit from which will copy (inclusive) - numbered from 0
261 * @param length of bits to by copied - <1,8>
262 * @return copied value aligned to right
264 public static byte copyBitsRange(final byte src, final int fromBit, final int length) {
265 if (fromBit < 0 | fromBit > Byte.SIZE - 1 | length < 1 | length > Byte.SIZE) {
266 throw new IllegalArgumentException("fromBit or toBit is out of range.");
268 if (fromBit + length > Byte.SIZE) {
269 throw new IllegalArgumentException("Out of range.");
275 for (int i = fromBit + length - 1; i >= fromBit; i--) {
277 if ((src & 1 << (Byte.SIZE - i - 1)) != 0) {
278 retByte |= 1 << retI;
288 * Copies whole source byte array to destination from offset.<br/>
289 * Length of src can't be bigger than dest length minus offset
295 public static void copyWhole(final byte[] src, final byte[] dest, final int offset) {
296 if (dest.length - offset < src.length) {
297 throw new ArrayIndexOutOfBoundsException("Can't copy whole array.");
300 System.arraycopy(src, 0, dest, offset, src.length);
304 * Convert array of bytes to java short.<br/>
305 * Size can't be bigger than size of short in bytes.
307 * @param bytes byte[]
308 * @return array of bytes
310 public static short bytesToShort(final byte[] bytes) {
311 if (bytes.length > Short.SIZE / Byte.SIZE) {
312 throw new IllegalArgumentException("Cannot convert bytes to short. Byte array too big.");
314 byte[] res = new byte[Short.SIZE / Byte.SIZE];
315 if (bytes.length != Short.SIZE / Byte.SIZE) {
316 System.arraycopy(bytes, 0, res, Integer.SIZE / Byte.SIZE - bytes.length, bytes.length);
320 final ByteBuffer buff = ByteBuffer.wrap(res);
321 return buff.getShort();
325 * Convert short java representation to array of bytes.
328 * @return short represented as array of bytes
330 public static byte[] shortToBytes(final short num) {
331 final ByteBuffer bytesBuffer = ByteBuffer.allocate(Short.SIZE / Byte.SIZE);
332 bytesBuffer.putShort(num);
334 return bytesBuffer.array();
338 * Convert float java representation to array of bytes.
341 * @return float represented as array of bytes
343 public static byte[] floatToBytes(final float num) {
344 final ByteBuffer bytesBuffer = ByteBuffer.allocate(Float.SIZE / Byte.SIZE);
345 bytesBuffer.putFloat(num);
347 return bytesBuffer.array();
351 * Pretty print array of bytes as hex encoded string with 16 bytes per line. Each byte is separated by space, after
352 * first 8 bytes there are 2 spaces instead of one.
354 public static String bytesToHexString(final byte[] array) {
355 return bytesToHexString(array, 16, " ", 8, " ");
359 * Pretty-print an array of bytes as hex-encoded string. Separate them with specified separator.
361 public static String toHexString(final byte[] array, final String separator) {
362 final StringBuilder sb = new StringBuilder();
363 for (int i = 0; i < array.length; i++) {
364 sb.append(Hex.encodeHexString(new byte[] { array[i] }));
365 if (i + 1 != array.length) {
366 sb.append(separator);
369 return sb.toString();
373 * Convert array of bytes to hexadecimal String.
376 * @param bytesOnLine number of bytes that should by displayed in one line
377 * @param byteSeparator string that will be placed after each byte
378 * @param wordCount number of bytes that make a 'word' (group of bytes)
379 * @param wordSeparator string that will be placed after each word
380 * @return Hexadecimal string representation of given byte array
382 public static String bytesToHexString(final byte[] array, final int bytesOnLine, final String byteSeparator, final int wordCount,
383 final String wordSeparator) {
384 final StringBuilder sb = new StringBuilder();
385 for (int i = 0; i < array.length; i++) {
386 sb.append(Hex.encodeHexString(new byte[] { array[i] }));
387 if ((i + 1) % bytesOnLine == 0) {
390 sb.append(byteSeparator);
391 if ((i + 1) % wordCount == 0) {
392 sb.append(wordSeparator);
397 return sb.toString();
401 * Decodes bytes to human readable UTF-8 string. If bytes are not valid UTF-8, they are represented as raw binary.
403 * @param bytes bytes to be decoded to string
404 * @return String representation of passed bytes
406 public static String bytesToHRString(final byte[] bytes) {
408 return Charset.forName("UTF-8").newDecoder().decode(ByteBuffer.wrap(bytes)).toString();
409 } catch (final CharacterCodingException e) {
410 return Arrays.toString(bytes);
415 * Searches for byte sequence in given array. Returns the index of first occurrence of this sequence (where it
418 * @param bytes byte array where to search for sequence
419 * @param sequence to be searched in given byte array
420 * @return -1 if the sequence could not be found in given byte array int index of first occurrence of the sequence
423 public static int findByteSequence(final byte[] bytes, final byte[] sequence) {
424 if (bytes.length < sequence.length) {
425 throw new IllegalArgumentException("Sequence to be found is longer than the given byte array.");
427 if (bytes.length == sequence.length) {
428 if (Arrays.equals(bytes, sequence)) {
435 for (int i = 0; i < bytes.length; i++) {
436 if (bytes[i] == sequence[j]) {
438 if (j == sequence.length) {
448 private static final byte maskBits[] = new byte[] { 0, -128, -64, -32, -16, -8, -4, -2 };
450 public static final byte[] maskBytes(final byte[] original, final int bits) {
451 if (original.length * 8 < bits) {
452 throw new IllegalArgumentException("Attempted to apply invalid mask (too long)");
455 final int needbytes = (bits + 7) / 8;
456 // We need to have a new copy of the underlying byte array, so that
457 // the original bytes stay untouched
458 final byte[] bytes = Arrays.copyOf(original, original.length);
460 final int needmask = bits % 8;
462 bytes[needbytes - 1] &= maskBits[needmask];
465 // zero-out the rest of the bytes
466 for (int i = needbytes; i < bytes.length; i++) {