2 * Copyright (c) 2013 Pantheon Technologies s.r.o. 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
9 package org.opendaylight.openflowjava.util;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Splitter;
13 import com.google.common.collect.Lists;
14 import com.google.common.primitives.UnsignedBytes;
15 import io.netty.buffer.ByteBuf;
16 import io.netty.buffer.UnpooledByteBufAllocator;
17 import java.io.IOException;
18 import java.nio.ByteBuffer;
19 import java.nio.charset.StandardCharsets;
20 import java.util.List;
22 import java.util.Map.Entry;
23 import org.opendaylight.openflowjava.protocol.api.util.EncodeConstants;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.IetfYangUtil;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
32 * Class for common operations on ByteBuf.
34 * @author michal.polkorab
35 * @author timotej.kubas
37 public abstract class ByteBufUtils {
38 public static final Splitter DOT_SPLITTER = Splitter.on('.');
39 public static final Splitter COLON_SPLITTER = Splitter.on(':');
40 private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
41 private static final Splitter HEXSTRING_SPLITTER = Splitter.onPattern("\\s+").omitEmptyStrings();
42 private static final Splitter HEXSTRING_NOSPACE_SPLITTER = Splitter.onPattern("(?<=\\G.{2})").omitEmptyStrings();
44 private ByteBufUtils() {
49 * Converts ByteBuf into String.
51 * @param bb input ByteBuf
54 public static String byteBufToHexString(final ByteBuf bb) {
55 StringBuilder sb = new StringBuilder();
56 for (int i = bb.readerIndex(); i < bb.readerIndex() + bb.readableBytes(); i++) {
57 sb.append(String.format(" %02x", bb.getUnsignedByte(i)));
59 return sb.toString().trim();
63 * Converts String into byte[].
65 * @param hexSrc input String
66 * @return byte[] filled with input data
68 public static byte[] hexStringToBytes(final String hexSrc) {
69 return hexStringToBytes(hexSrc, true);
73 * Converts String into byte[].
75 * @param hexSrc input String
76 * @param withSpaces if there are spaces in string
77 * @return byte[] filled with input data
79 public static byte[] hexStringToBytes(final String hexSrc, final boolean withSpaces) {
80 final Splitter splitter = withSpaces ? HEXSTRING_SPLITTER : HEXSTRING_NOSPACE_SPLITTER;
81 List<String> byteChips = Lists.newArrayList(splitter.split(hexSrc));
82 byte[] result = new byte[byteChips.size()];
84 for (String chip : byteChips) {
85 result[index] = (byte) Short.parseShort(chip, 16);
92 * Creates ByteBuf filled with specified data.
94 * @param hexSrc input String of bytes in hex format
95 * @return ByteBuf with specified hexString converted
97 public static ByteBuf hexStringToByteBuf(final String hexSrc) {
98 ByteBuf out = UnpooledByteBufAllocator.DEFAULT.buffer();
99 hexStringToByteBuf(hexSrc, out);
104 * Creates ByteBuf filled with specified data.
106 * @param hexSrc input String of bytes in hex format
107 * @param out ByteBuf with specified hexString converted
109 public static void hexStringToByteBuf(final String hexSrc, final ByteBuf out) {
110 out.writeBytes(hexStringToBytes(hexSrc));
114 * Fills specified ByteBuf with 0 (zeros) of desired length, used for padding.
116 * @param length the desired length
117 * @param out ByteBuf to be padded
118 * @deprecated Use {@link ByteBuf#writeZero(int)} directly.
121 public static void padBuffer(final int length, final ByteBuf out) {
122 out.writeZero(length);
126 * Create standard OF header.
128 * @param msgType message code
129 * @param message POJO
130 * @param out writing buffer
131 * @param length ofheader length
133 public static <E extends OfHeader> void writeOFHeader(final byte msgType, final E message, final ByteBuf out,
135 out.writeByte(message.getVersion());
136 out.writeByte(msgType);
137 out.writeShort(length);
138 out.writeInt(message.getXid().intValue());
142 * Write length standard OF header.
144 * @param out writing buffer
146 public static void updateOFHeaderLength(final ByteBuf out) {
147 out.setShort(EncodeConstants.OFHEADER_LENGTH_INDEX, out.readableBytes());
151 * Write length OF header.
153 * @param out writing buffer
154 * @param index writing index
156 public static void updateOFHeaderLength(final ByteBuf out, int index) {
157 out.setShort(index + EncodeConstants.OFHEADER_LENGTH_INDEX, out.writerIndex() - index);
161 * Fills the bitmask from boolean map where key is bit position.
163 * @param booleanMap bit to boolean mapping
166 public static int fillBitMaskFromMap(final Map<Integer, Boolean> booleanMap) {
169 for (Entry<Integer, Boolean> iterator : booleanMap.entrySet()) {
170 if (iterator.getValue() != null && iterator.getValue().booleanValue()) {
171 bitmask |= 1 << iterator.getKey();
178 * Fills the bitmask from a set of bit values, starting at specified offset.
180 * @param offset Bit offset to start at
181 * @param values boolean bit values to fill
182 * @return Filled-in bitmask
184 public static int fillBitMask(final int offset, final boolean... values) {
188 for (boolean v : values) {
190 bitmask |= 1 << index;
199 * Fills the bitmask from boolean list where key is bit position.
201 * @param booleanList bit to boolean mapping
204 public static int[] fillBitMaskFromList(final List<Boolean> booleanList) {
208 if (booleanList.size() % Integer.SIZE != 0) {
209 bitmask = new int[booleanList.size() / Integer.SIZE + 1];
211 bitmask = new int[booleanList.size() / Integer.SIZE];
213 for (Boolean currElement : booleanList) {
214 if (currElement != null && currElement.booleanValue()) {
215 bitmask[arrayIndex] |= 1 << index;
218 arrayIndex = index / Integer.SIZE;
224 * Converts byte array into String.
226 * @param array input byte array
229 public static String bytesToHexString(final byte[] array) {
230 StringBuilder sb = new StringBuilder();
231 for (byte element : array) {
232 sb.append(String.format(" %02x", element));
234 return sb.toString().trim();
237 private static int hexValue(final char ch) {
238 if (ch >= '0' && ch <= '9') {
241 if (ch >= 'a' && ch <= 'f') {
242 return ch - 'a' + 10;
244 if (ch >= 'A' && ch <= 'F') {
245 return ch - 'A' + 10;
248 throw new IllegalArgumentException(String.format("Invalid character '%s' encountered", ch));
252 * Converts macAddress to byte array.
253 * See also {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress}.
255 * @param macAddress the mac address to convert
256 * @return byte representation of mac address
258 @SuppressWarnings("checkstyle:IllegalCatch")
259 public static byte[] macAddressToBytes(final String macAddress) {
260 final byte[] result = new byte[EncodeConstants.MAC_ADDRESS_LENGTH];
261 final char[] mac = macAddress.toCharArray();
265 for (int i = 0; i < EncodeConstants.MAC_ADDRESS_LENGTH - 1; ++i) {
266 if (mac[offset + EncodeConstants.SIZE_OF_BYTE_IN_BYTES] == ':') {
267 result[i] = UnsignedBytes.checkedCast(hexValue(mac[offset]));
270 result[i] = UnsignedBytes.checkedCast(
271 hexValue(mac[offset]) << 4 | hexValue(mac[offset + 1]));
274 Preconditions.checkArgument(mac[offset] == ':', "Invalid value: %s", macAddress);
278 if (offset == mac.length - 1) {
279 result[EncodeConstants.MAC_ADDRESS_LENGTH - 1] = UnsignedBytes.checkedCast(hexValue(mac[offset]));
281 result[EncodeConstants.MAC_ADDRESS_LENGTH - 1] =
282 UnsignedBytes.checkedCast(hexValue(mac[offset]) << 4 | hexValue(mac[offset + 1]));
285 if (offset != mac.length - 1) {
286 throw new IllegalArgumentException("Incorrect MAC address length");
288 } catch (RuntimeException e) {
289 throw new IllegalArgumentException("Unable to serialize MAC address for input: " + macAddress
295 private static void appendHexByte(final StringBuilder sb, final byte value) {
296 final int v = UnsignedBytes.toInt(value);
297 sb.append(HEX_CHARS[v >>> 4]);
298 sb.append(HEX_CHARS[v & 15]);
301 private static void appendHexUnsignedShort(final StringBuilder sb, final int val) {
302 sb.append(ByteBufUtils.HEX_CHARS[val >>> 12 & 15]);
303 sb.append(ByteBufUtils.HEX_CHARS[val >>> 8 & 15]);
304 sb.append(ByteBufUtils.HEX_CHARS[val >>> 4 & 15]);
305 sb.append(ByteBufUtils.HEX_CHARS[ val & 15]);
309 * Converts a MAC address represented in bytes to String.
310 * See also {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress}.
312 * @param address the MAC address to convert
313 * @return String representation of a MAC address
315 public static String macAddressToString(final byte[] address) {
316 Preconditions.checkArgument(address.length == EncodeConstants.MAC_ADDRESS_LENGTH);
318 final StringBuilder sb = new StringBuilder(17);
320 appendHexByte(sb, address[0]);
321 for (int i = 1; i < EncodeConstants.MAC_ADDRESS_LENGTH; i++) {
323 appendHexByte(sb, address[i]);
326 return sb.toString();
330 * Reads and parses null-terminated string from ByteBuf.
332 * @param rawMessage the message to parse
333 * @param length maximal length of String
334 * @return String with name of port
336 public static String decodeNullTerminatedString(final ByteBuf rawMessage, final int length) {
337 byte[] name = new byte[length];
338 rawMessage.readBytes(name);
339 return new String(name, StandardCharsets.UTF_8).trim();
343 * Read an IPv4 address from a buffer and format it into dotted-quad string.
345 * @param buf Input buffer
346 * @return Dotted-quad string
348 public static String readIpv4Address(final ByteBuf buf) {
349 final StringBuilder sb = new StringBuilder(EncodeConstants.GROUPS_IN_IPV4_ADDRESS * 4 - 1);
351 sb.append(buf.readUnsignedByte());
352 for (int i = 1; i < EncodeConstants.GROUPS_IN_IPV4_ADDRESS; i++) {
354 sb.append(buf.readUnsignedByte());
357 return sb.toString();
362 * Read an IPv6 address from a buffer and format it into a string of eight groups of four
363 * hexadecimal digits separated by colons.
365 * @param buf Input buffer
366 * @return IPv6 address in string format
368 public static String readIpv6Address(final ByteBuf buf) {
369 final StringBuilder sb = new StringBuilder(EncodeConstants.GROUPS_IN_IPV6_ADDRESS * 5 - 1);
371 appendHexUnsignedShort(sb, buf.readUnsignedShort());
372 for (int i = 1; i < EncodeConstants.GROUPS_IN_IPV6_ADDRESS; i++) {
374 appendHexUnsignedShort(sb, buf.readUnsignedShort());
377 return sb.toString();
380 public static Ipv4Address readIetfIpv4Address(final ByteBuf buf) {
381 final byte[] tmp = new byte[4];
383 return IetfInetUtil.INSTANCE.ipv4AddressFor(tmp);
386 public static Ipv6Address readIetfIpv6Address(final ByteBuf buf) {
387 final byte[] tmp = new byte[16];
389 return IetfInetUtil.INSTANCE.ipv6AddressFor(tmp);
392 public static MacAddress readIetfMacAddress(final ByteBuf buf) {
393 final byte[] tmp = new byte[EncodeConstants.MAC_ADDRESS_LENGTH];
395 return IetfYangUtil.INSTANCE.macAddressFor(tmp);
398 public static byte[] serializeList(final List<Short> list) throws IOException {
399 ByteBuffer byteBuffer = ByteBuffer.allocate(list.size() * 2);
400 for (Short shortValue : list) {
401 byteBuffer.putShort(shortValue);
403 return byteBuffer.array();