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;
10 import com.google.common.base.Preconditions;
11 import com.google.common.io.BaseEncoding;
12 import io.netty.buffer.ByteBuf;
14 import java.io.FileInputStream;
15 import java.io.IOException;
16 import java.nio.ByteBuffer;
17 import java.nio.charset.CharacterCodingException;
18 import java.nio.charset.StandardCharsets;
19 import java.util.Arrays;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
24 * Util class for methods working with byte array.
26 public final class ByteArray {
28 private static final Logger LOG = LoggerFactory.getLogger(ByteArray.class);
31 throw new UnsupportedOperationException();
35 * Helper method missing from netty ByteBuf methods. Directly returns byte array part of the given buffer, starting
36 * at reader index, with given length. Increases reader index of the buffer by 'length'.
38 * @param buffer ByteBuf from which the bytes are going to be taken
39 * @param length length of the returned byte array
42 public static byte[] readBytes(final ByteBuf buffer, final int length) {
43 Preconditions.checkArgument(buffer != null && buffer.readableBytes() >= length,
44 "Buffer cannot be read for %s bytes.", length);
45 final byte[] result = new byte[length];
46 buffer.readBytes(result);
51 * Helper method missing from netty ByteBuf methods. Directly returns all readable bytes from buffer as byte array.
52 * Adjusts reader index of the buffer by length of readable bytes in the buffer.
54 * @param buffer byteBuf from which the bytes are going to be taken
57 public static byte[] readAllBytes(final ByteBuf buffer) {
58 return readBytes(buffer, buffer.readableBytes());
62 * Helper method missing from netty ByteBuf methods. Directly returns byte array part of the given buffer, starting
63 * at reader index, with given length. Does not modify reader or writer index of the buffer.
65 * @param buffer ByteBuf from which the bytes are going to be taken
66 * @param length length of the returned byte array
69 public static byte[] getBytes(final ByteBuf buffer, final int length) {
70 Preconditions.checkArgument(buffer != null && buffer.readableBytes() >= length,
71 "Buffer cannot be read for %s bytes.", length);
72 final byte[] result = new byte[length];
73 buffer.getBytes(buffer.readerIndex(), result);
78 * Helper method missing from netty ByteBuf methods. Directly returns all readable bytes from buffer as byte array.
79 * Does not modify writer or reader index of the buffer.
81 * @param buffer byteBuf from which the bytes are going to be taken
84 public static byte[] getAllBytes(final ByteBuf buffer) {
85 return getBytes(buffer, buffer.readableBytes());
89 * Returns a new byte array from given byte array, starting at start index with the size of the length parameter.
90 * Byte array given as parameter stays untouched.
92 * @param bytes original byte array
93 * @param startIndex beginning index, inclusive
94 * @param length how many bytes should be in the sub-array
95 * @return a new byte array that is a sub-array of the original
97 public static byte[] subByte(final byte[] bytes, final int startIndex, final int length) {
98 Preconditions.checkArgument(checkLength(bytes, length) && checkStartIndex(bytes, startIndex, length),
99 "Cannot create subByte, invalid arguments: Length: %s startIndex: %s", length, startIndex);
100 final byte[] res = new byte[length];
101 System.arraycopy(bytes, startIndex, res, 0, length);
105 private static boolean checkLength(final byte[] bytes, final int length) {
106 return length > 0 && bytes.length > 0 && length <= bytes.length;
109 private static boolean checkStartIndex(final byte[] bytes, final int startIndex, final int length) {
110 return startIndex >= 0 && startIndex < bytes.length && (startIndex + length <= bytes.length);
114 * Converts byte array to Integer. If there are less bytes in the array as required (4), the method will push
115 * adequate number of zero bytes prepending given byte array.
117 * @param bytes array to be converted to int
120 public static int bytesToInt(final byte[] bytes) {
121 Preconditions.checkArgument(bytes.length <= Integer.SIZE / Byte.SIZE,
122 "Cannot convert bytes to integer. Byte array too big.");
124 if (bytes.length != Integer.SIZE / Byte.SIZE) {
125 res = new byte[Integer.SIZE / Byte.SIZE];
126 System.arraycopy(bytes, 0, res, Integer.SIZE / Byte.SIZE - bytes.length, bytes.length);
130 return ByteBuffer.wrap(res).getInt();
134 * Converts byte array to long. If there are less bytes in the array as required (Long.Size), the method will push
135 * adequate number of zero bytes prepending given byte array.
137 * @param bytes array to be converted to long
140 public static long bytesToLong(final byte[] bytes) {
141 Preconditions.checkArgument(bytes.length <= Long.SIZE / Byte.SIZE,
142 "Cannot convert bytes to long.Byte array too big.");
144 if (bytes.length != Long.SIZE / Byte.SIZE) {
145 res = new byte[Long.SIZE / Byte.SIZE];
146 System.arraycopy(bytes, 0, res, Long.SIZE / Byte.SIZE - bytes.length, bytes.length);
150 return ByteBuffer.wrap(res).getLong();
154 * Cuts 'count' number of bytes from the beginning of given byte array.
156 * @param bytes array to be cut, cannot be null
157 * @param count how many bytes needed to be cut, needs to be greater than 0
158 * @return bytes array without first 'count' bytes
160 public static byte[] cutBytes(final byte[] bytes, final int count) {
161 Preconditions.checkArgument(bytes.length != 0 && count <= bytes.length && count > 0,
162 "Cannot cut bytes, invalid arguments: Count: %s bytes.length: %s", count, bytes.length);
163 return Arrays.copyOfRange(bytes, count, bytes.length);
167 * Parses file to array of bytes.
169 * @param name path to file to by parsed
170 * @return parsed array of bytes
172 public static byte[] fileToBytes(final String name) throws IOException {
173 final File file = new File(name);
177 if (file.length() > Integer.MAX_VALUE) {
178 throw new IOException("Too large file to load in byte array.");
180 final byte[] byteArray = new byte[(int) file.length()];
181 try (FileInputStream fin = new FileInputStream(file)) {
182 while (offset < byteArray.length) {
183 numRead = fin.read(byteArray, offset, byteArray.length - offset);
194 * Copies range of bits from passed byte and align to right.<br>
196 * @param src source byte to copy from
197 * @param fromBit bit from which will copy (inclusive) - numbered from 0
198 * @param length of bits to by copied, valid values are 1 through 8
199 * @return copied value aligned to right
201 public static byte copyBitsRange(final byte src, final int fromBit, final int length) {
202 Preconditions.checkArgument(fromBit >= 0 && fromBit <= Byte.SIZE - 1
203 && length >= 1 && length <= Byte.SIZE, "fromBit or toBit is out of range.");
204 Preconditions.checkArgument(fromBit + length <= Byte.SIZE, "Out of range.");
209 for (int i = fromBit + length - 1; i >= fromBit; i--) {
211 if ((src & 1 << (Byte.SIZE - i - 1)) != 0) {
212 retByte |= 1 << retI;
222 * Decodes bytes to human readable UTF-8 string. If bytes are not valid UTF-8, they are represented as raw binary.
224 * @param bytes bytes to be decoded to string
225 * @return String representation of passed bytes
227 public static String bytesToHRString(final byte[] bytes) {
229 return StandardCharsets.UTF_8.newDecoder().decode(ByteBuffer.wrap(bytes)).toString();
230 } catch (final CharacterCodingException e) {
231 LOG.debug("Could not apply UTF-8 encoding.", e);
232 return Arrays.toString(bytes);
237 * Encode input ByteBuf with Base64 to string format.
239 * @param buffer Input ByteBuf
240 * @return String representation of encoded ByteBuf.
242 public static String encodeBase64(final ByteBuf buffer) {
243 return BaseEncoding.base64().encode(ByteArray.readAllBytes(buffer));