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
10 package org.opendaylight.openflowjava.util;
12 import com.google.common.base.Preconditions;
13 import com.google.common.base.Splitter;
14 import com.google.common.collect.Lists;
15 import com.google.common.primitives.UnsignedBytes;
16 import io.netty.buffer.ByteBuf;
17 import io.netty.buffer.UnpooledByteBufAllocator;
18 import java.io.IOException;
19 import java.nio.ByteBuffer;
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;
31 /** Class for common operations on ByteBuf
32 * @author michal.polkorab
33 * @author timotej.kubas
35 public abstract class ByteBufUtils {
36 public static final Splitter DOT_SPLITTER = Splitter.on('.');
37 public static final Splitter COLON_SPLITTER = Splitter.on(':');
38 private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
39 private static final Splitter HEXSTRING_SPLITTER = Splitter.onPattern("\\s+").omitEmptyStrings();
40 private static final Splitter HEXSTRING_NOSPACE_SPLITTER = Splitter.onPattern("(?<=\\G.{2})").omitEmptyStrings();
42 private ByteBufUtils() {
47 * Converts ByteBuf into String
48 * @param bb input ByteBuf
51 public static String byteBufToHexString(final ByteBuf bb) {
52 StringBuilder sb = new StringBuilder();
53 for (int i = bb.readerIndex(); i < (bb.readerIndex() + bb.readableBytes()); i++) {
54 sb.append(String.format(" %02x", bb.getUnsignedByte(i)));
56 return sb.toString().trim();
60 * Converts String into byte[]
61 * @param hexSrc input String
62 * @return byte[] filled with input data
64 public static byte[] hexStringToBytes(final String hexSrc) {
65 return hexStringToBytes(hexSrc, true);
69 * Converts String into byte[]
70 * @param hexSrc input String
71 * @param withSpaces if there are spaces in string
72 * @return byte[] filled with input data
74 public static byte[] hexStringToBytes(final String hexSrc, final boolean withSpaces) {
75 final Splitter splitter = withSpaces ? HEXSTRING_SPLITTER : HEXSTRING_NOSPACE_SPLITTER;
76 List<String> byteChips = Lists.newArrayList(splitter.split(hexSrc));
77 byte[] result = new byte[byteChips.size()];
79 for (String chip : byteChips) {
80 result[i] = (byte) Short.parseShort(chip, 16);
87 * Creates ByteBuf filled with specified data
88 * @param hexSrc input String of bytes in hex format
89 * @return ByteBuf with specified hexString converted
91 public static ByteBuf hexStringToByteBuf(final String hexSrc) {
92 ByteBuf out = UnpooledByteBufAllocator.DEFAULT.buffer();
93 hexStringToByteBuf(hexSrc, out);
98 * Creates ByteBuf filled with specified data
99 * @param hexSrc input String of bytes in hex format
100 * @param out ByteBuf with specified hexString converted
102 public static void hexStringToByteBuf(final String hexSrc, final ByteBuf out) {
103 out.writeBytes(hexStringToBytes(hexSrc));
107 * Fills specified ByteBuf with 0 (zeros) of desired length, used for padding
109 * @param out ByteBuf to be padded
110 * @deprecated Use {@link ByteBuf#writeZero(int)} directly.
113 public static void padBuffer(final int length, final ByteBuf out) {
114 out.writeZero(length);
118 * Create standard OF header
119 * @param msgType message code
120 * @param message POJO
121 * @param out writing buffer
122 * @param length ofheader length
124 public static <E extends OfHeader> void writeOFHeader(final byte msgType, final E message, final ByteBuf out, final int length) {
125 out.writeByte(message.getVersion());
126 out.writeByte(msgType);
127 out.writeShort(length);
128 out.writeInt(message.getXid().intValue());
132 * Write length standard OF header
133 * @param out writing buffer
135 public static void updateOFHeaderLength(final ByteBuf out) {
136 out.setShort(EncodeConstants.OFHEADER_LENGTH_INDEX, out.readableBytes());
140 * Write length OF header
141 * @param out writing buffer
142 * @param index writing index
144 public static void updateOFHeaderLength(final ByteBuf out, int index) {
145 out.setShort(index + EncodeConstants.OFHEADER_LENGTH_INDEX, out.writerIndex() - index);
149 * Fills the bitmask from boolean map where key is bit position
150 * @param booleanMap bit to boolean mapping
153 public static int fillBitMaskFromMap(final Map<Integer, Boolean> booleanMap) {
156 for (Entry<Integer, Boolean> iterator : booleanMap.entrySet()) {
157 if (iterator.getValue() != null && iterator.getValue().booleanValue()) {
158 bitmask |= 1 << iterator.getKey();
165 * Fills the bitmask from a set of bit values, starting at specified offset.
167 * @param offset Bit offset to start at
168 * @param values boolean bit values to fill
169 * @return Filled-in bitmask
171 public static int fillBitMask(final int offset, final boolean... values) {
175 for (boolean v : values) {
186 * Fills the bitmask from boolean list where key is bit position
187 * @param booleanList bit to boolean mapping
190 public static int[] fillBitMaskFromList(final List<Boolean> booleanList) {
194 if ((booleanList.size() % Integer.SIZE) != 0) {
195 bitmask = new int[booleanList.size() / Integer.SIZE + 1];
197 bitmask = new int[booleanList.size() / Integer.SIZE];
199 for (Boolean currElement : booleanList) {
200 if (currElement != null && currElement.booleanValue()) {
201 bitmask[arrayIndex] |= 1 << index;
204 arrayIndex = index / Integer.SIZE;
210 * Converts byte array into String
211 * @param array input byte array
214 public static String bytesToHexString(final byte[] array) {
215 StringBuilder sb = new StringBuilder();
216 for (byte element : array) {
217 sb.append(String.format(" %02x", element));
219 return sb.toString().trim();
222 private static int hexValue(final char c) {
223 if (c >= '0' && c <= '9') {
226 if (c >= 'a' && c <= 'f') {
229 if (c >= 'A' && c <= 'F') {
233 throw new IllegalArgumentException(String.format("Invalid character '%s' encountered", c));
237 * Converts macAddress to byte array.
238 * See also {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress}.
241 * @return byte representation of mac address
243 public static byte[] macAddressToBytes(final String macAddress) {
244 final byte[] result = new byte[EncodeConstants.MAC_ADDRESS_LENGTH];
245 final char[] mac = macAddress.toCharArray();
249 for (int i = 0; i < EncodeConstants.MAC_ADDRESS_LENGTH - 1; ++i) {
250 if (mac[offset + EncodeConstants.SIZE_OF_BYTE_IN_BYTES] == ':') {
251 result[i] = UnsignedBytes.checkedCast(hexValue(mac[offset]));
254 result[i] = UnsignedBytes.checkedCast(
255 (hexValue(mac[offset]) << 4) | hexValue(mac[offset +1]));
258 Preconditions.checkArgument(mac[offset] == ':', "Invalid value: %s", macAddress);
262 if (offset == (mac.length - 1)) {
263 result[EncodeConstants.MAC_ADDRESS_LENGTH - 1] = UnsignedBytes.checkedCast(hexValue(mac[offset]));
265 result[EncodeConstants.MAC_ADDRESS_LENGTH - 1] =
266 UnsignedBytes.checkedCast(hexValue(mac[offset]) << 4 | hexValue(mac[offset +1]));
269 if (offset != (mac.length -1)) {
270 throw new IllegalArgumentException("Incorrect MAC address length");
272 } catch (Exception e) {
273 throw new IllegalArgumentException("Unable to serialize MAC address for input: " + macAddress
279 private static final void appendHexByte(final StringBuilder sb, final byte b) {
280 final int v = UnsignedBytes.toInt(b);
281 sb.append(HEX_CHARS[v >>> 4]);
282 sb.append(HEX_CHARS[v & 15]);
285 private static void appendHexUnsignedShort(final StringBuilder sb, final int val) {
286 sb.append(ByteBufUtils.HEX_CHARS[(val >>> 12) & 15]);
287 sb.append(ByteBufUtils.HEX_CHARS[(val >>> 8) & 15]);
288 sb.append(ByteBufUtils.HEX_CHARS[(val >>> 4) & 15]);
289 sb.append(ByteBufUtils.HEX_CHARS[ val & 15]);
293 * Converts a MAC address represented in bytes to String.
294 * See also {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress}.
297 * @return String representation of a MAC address
299 public static String macAddressToString(final byte[] address) {
300 Preconditions.checkArgument(address.length == EncodeConstants.MAC_ADDRESS_LENGTH);
302 final StringBuilder sb = new StringBuilder(17);
304 appendHexByte(sb, address[0]);
305 for (int i = 1; i < EncodeConstants.MAC_ADDRESS_LENGTH; i++) {
307 appendHexByte(sb, address[i]);
310 return sb.toString();
314 * Reads and parses null-terminated string from ByteBuf
316 * @param length maximal length of String
317 * @return String with name of port
319 public static String decodeNullTerminatedString(final ByteBuf rawMessage, final int length) {
320 byte[] name = new byte[length];
321 rawMessage.readBytes(name);
322 return new String(name).trim();
326 * Read an IPv4 address from a buffer and format it into dotted-quad string.
328 * @param buf Input buffer
329 * @return Dotted-quad string
331 public static String readIpv4Address(final ByteBuf buf) {
332 final StringBuilder sb = new StringBuilder(EncodeConstants.GROUPS_IN_IPV4_ADDRESS * 4 - 1);
334 sb.append(buf.readUnsignedByte());
335 for (int i = 1; i < EncodeConstants.GROUPS_IN_IPV4_ADDRESS; i++) {
337 sb.append(buf.readUnsignedByte());
340 return sb.toString();
345 * Read an IPv6 address from a buffer and format it into a string of eight groups of four
346 * hexadecimal digits separated by colons.
348 * @param buf Input buffer
349 * @return IPv6 address in string format
351 public static String readIpv6Address(final ByteBuf buf) {
352 final StringBuilder sb = new StringBuilder(EncodeConstants.GROUPS_IN_IPV6_ADDRESS * 5 - 1);
354 appendHexUnsignedShort(sb, buf.readUnsignedShort());
355 for (int i = 1; i < EncodeConstants.GROUPS_IN_IPV6_ADDRESS; i++) {
357 appendHexUnsignedShort(sb, buf.readUnsignedShort());
360 return sb.toString();
363 public static Ipv4Address readIetfIpv4Address(final ByteBuf buf) {
364 final byte[] tmp = new byte[4];
366 return IetfInetUtil.INSTANCE.ipv4AddressFor(tmp);
369 public static Ipv6Address readIetfIpv6Address(final ByteBuf buf) {
370 final byte[] tmp = new byte[16];
372 return IetfInetUtil.INSTANCE.ipv6AddressFor(tmp);
375 public static MacAddress readIetfMacAddress(final ByteBuf buf) {
376 final byte[] tmp = new byte[EncodeConstants.MAC_ADDRESS_LENGTH];
378 return IetfYangUtil.INSTANCE.macAddressFor(tmp);
381 public static byte[] serializeList(final List<Short> list) throws IOException{
382 ByteBuffer byteBuffer = ByteBuffer.allocate(list.size() * 2);
383 for (Short aShort : list) {
384 byteBuffer.putShort(aShort);
386 return byteBuffer.array();