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.protocol.impl.util;
12 import io.netty.buffer.ByteBuf;
13 import io.netty.buffer.UnpooledByteBufAllocator;
15 import java.util.ArrayList;
16 import java.util.List;
18 import java.util.Map.Entry;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
23 import com.google.common.base.Preconditions;
24 import com.google.common.base.Splitter;
25 import com.google.common.collect.Lists;
26 import com.google.common.primitives.UnsignedBytes;
28 /** Class for common operations on ByteBuf
29 * @author michal.polkorab
30 * @author timotej.kubas
32 public abstract class ByteBufUtils {
33 public static final Splitter DOT_SPLITTER = Splitter.on('.');
34 public static final Splitter COLON_SPLITTER = Splitter.on(':');
35 private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
38 * Converts ByteBuf into String
39 * @param bb input ByteBuf
42 public static String byteBufToHexString(final ByteBuf bb) {
43 StringBuffer sb = new StringBuffer();
44 for (int i = bb.readerIndex(); i < (bb.readerIndex() + bb.readableBytes()); i++) {
45 sb.append(String.format(" %02x", bb.getUnsignedByte(i)));
47 return sb.toString().trim();
51 * Converts String into byte[]
52 * @param hexSrc input String
53 * @return byte[] filled with input data
55 public static byte[] hexStringToBytes(final String hexSrc) {
56 return hexStringToBytes(hexSrc, true);
60 * Converts String into byte[]
61 * @param hexSrc input String
62 * @param withSpaces if there are spaces in string
63 * @return byte[] filled with input data
65 public static byte[] hexStringToBytes(final String hexSrc, final boolean withSpaces ) {
66 String splitPattern = "\\s+";
68 splitPattern = "(?<=\\G.{2})";
70 Iterable<String> tmp = Splitter.onPattern(splitPattern)
71 .omitEmptyStrings().split(hexSrc);
72 ArrayList<String> byteChips = Lists.newArrayList(tmp);
73 byte[] result = new byte[byteChips.size()];
75 for (String chip : byteChips) {
76 result[i] = (byte) Short.parseShort(chip, 16);
83 * Creates ByteBuf filled with specified data
84 * @param hexSrc input String of bytes in hex format
85 * @return ByteBuf with specified hexString converted
87 public static ByteBuf hexStringToByteBuf(final String hexSrc) {
88 ByteBuf out = UnpooledByteBufAllocator.DEFAULT.buffer();
89 hexStringToByteBuf(hexSrc, out);
94 * Creates ByteBuf filled with specified data
95 * @param hexSrc input String of bytes in hex format
96 * @param out ByteBuf with specified hexString converted
98 public static void hexStringToByteBuf(final String hexSrc, final ByteBuf out) {
99 out.writeBytes(hexStringToBytes(hexSrc));
103 * Fills specified ByteBuf with 0 (zeros) of desired length, used for padding
105 * @param out ByteBuf to be padded
106 * @deprecated Use {@link ByteBuf#writeZero(int)} directly.
109 public static void padBuffer(final int length, final ByteBuf out) {
110 out.writeZero(length);
114 * Create standard OF header
115 * @param msgType message code
116 * @param message POJO
117 * @param out writing buffer
118 * @param length ofheader length
120 public static <E extends OfHeader> void writeOFHeader(final byte msgType, final E message, final ByteBuf out, final int length) {
121 out.writeByte(message.getVersion());
122 out.writeByte(msgType);
123 out.writeShort(length);
124 out.writeInt(message.getXid().intValue());
128 * Write length standard OF header
129 * @param out writing buffer
131 public static void updateOFHeaderLength(final ByteBuf out) {
132 out.setShort(EncodeConstants.OFHEADER_LENGTH_INDEX, out.readableBytes());
136 * Fills the bitmask from boolean map where key is bit position
137 * @param booleanMap bit to boolean mapping
140 public static int fillBitMaskFromMap(final Map<Integer, Boolean> booleanMap) {
143 for (Entry<Integer, Boolean> iterator : booleanMap.entrySet()) {
144 if (iterator.getValue() != null && iterator.getValue().booleanValue()) {
145 bitmask |= 1 << iterator.getKey();
152 * Fills the bitmask from a set of bit values, starting at specified offset.
154 * @param offset Bit offset to start at
155 * @param values boolean bit values to fill
156 * @return Filled-in bitmask
158 public static int fillBitMask(final int offset, final boolean... values) {
162 for (boolean v : values) {
173 * Fills the bitmask from boolean list where key is bit position
174 * @param booleanList bit to boolean mapping
177 public static int[] fillBitMaskFromList(final List<Boolean> booleanList) {
181 if ((booleanList.size() % Integer.SIZE) != 0) {
182 bitmask = new int[booleanList.size() / Integer.SIZE + 1];
184 bitmask = new int[booleanList.size() / Integer.SIZE];
186 for (Boolean currElement : booleanList) {
187 if (currElement != null && currElement.booleanValue()) {
188 bitmask[arrayIndex] |= 1 << index;
191 arrayIndex = index / Integer.SIZE;
197 * Converts byte array into String
198 * @param array input byte array
201 public static String bytesToHexString(final byte[] array) {
202 StringBuffer sb = new StringBuffer();
203 for (byte element : array) {
204 sb.append(String.format(" %02x", element));
206 return sb.toString().trim();
209 private static int hexValue(final char c) {
210 if (c >= '0' && c <= '9') {
213 if (c >= 'a' && c <= 'f') {
216 if (c >= 'A' && c <= 'F') {
220 throw new IllegalArgumentException(String.format("Invalid character '%s' encountered", c));
224 * Converts macAddress to byte array
226 * @return byte representation of mac address
227 * @see {@link MacAddress}
229 * FIXME: this method does not support shortened values, e.g.
230 * "0:1:2:3:4:5", only "00:11:22:33:44:55".
232 public static byte[] macAddressToBytes(final String macAddress) {
233 final byte[] result = new byte[EncodeConstants.MAC_ADDRESS_LENGTH];
234 final char[] mac = macAddress.toCharArray();
237 for (int i = 0; i < EncodeConstants.MAC_ADDRESS_LENGTH - 1; ++i) {
238 result[i] = UnsignedBytes.checkedCast(
239 (hexValue(mac[offset++]) << 4) | hexValue(mac[offset++]));
240 Preconditions.checkArgument(mac[offset] == ':', "Invalid value: %s", macAddress);
244 result[EncodeConstants.MAC_ADDRESS_LENGTH - 1] =
245 UnsignedBytes.checkedCast(hexValue(mac[offset++]) << 4 | hexValue(mac[offset]));
249 private static final void appendHexByte(final StringBuilder sb, final byte b) {
250 final int v = UnsignedBytes.toInt(b);
251 sb.append(HEX_CHARS[v >> 4]);
252 sb.append(HEX_CHARS[v & 15]);
255 private static void appendHexUnsignedShort(final StringBuilder sb, final int val) {
256 sb.append(ByteBufUtils.HEX_CHARS[(val >> 12) & 15]);
257 sb.append(ByteBufUtils.HEX_CHARS[(val >> 8) & 15]);
258 sb.append(ByteBufUtils.HEX_CHARS[(val >> 4) & 15]);
259 sb.append(ByteBufUtils.HEX_CHARS[ val & 15]);
263 * Converts a MAC address represented in bytes to String
265 * @return String representation of a MAC address
266 * @see {@link MacAddress}
268 public static String macAddressToString(final byte[] address) {
269 Preconditions.checkArgument(address.length == EncodeConstants.MAC_ADDRESS_LENGTH);
271 final StringBuilder sb = new StringBuilder(17);
273 appendHexByte(sb, address[0]);
274 for (int i = 1; i < EncodeConstants.MAC_ADDRESS_LENGTH; i++) {
276 appendHexByte(sb, address[i]);
279 return sb.toString();
283 * Reads and parses null-terminated string from ByteBuf
285 * @param length maximal length of String
286 * @return String with name of port
288 public static String decodeNullTerminatedString(final ByteBuf rawMessage, final int length) {
289 byte[] name = new byte[length];
290 rawMessage.readBytes(name);
291 return new String(name).trim();
295 * Read an IPv4 address from a buffer and format it into dotted-quad string.
297 * @param buf Input buffer
298 * @return Dotted-quad string
300 public static String readIpv4Address(final ByteBuf buf) {
301 final StringBuilder sb = new StringBuilder(EncodeConstants.GROUPS_IN_IPV4_ADDRESS * 4 - 1);
303 sb.append(buf.readUnsignedByte());
304 for (int i = 1; i < EncodeConstants.GROUPS_IN_IPV4_ADDRESS; i++) {
306 sb.append(buf.readUnsignedByte());
309 return sb.toString();
313 * Read an IPv6 address from a buffer and format it into a string of eight groups of four
314 * hexadecimal digits separated by colons.
316 * @param buf Input buffer
317 * @return IPv6 address in string format
319 public static String readIpv6Address(final ByteBuf buf) {
320 final StringBuilder sb = new StringBuilder(EncodeConstants.GROUPS_IN_IPV6_ADDRESS * 5 - 1);
322 appendHexUnsignedShort(sb, buf.readUnsignedShort());
323 for (int i = 1; i < EncodeConstants.GROUPS_IN_IPV6_ADDRESS; i++) {
325 appendHexUnsignedShort(sb, buf.readUnsignedShort());
328 return sb.toString();