3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
13 package org.opendaylight.controller.sal.packet;
15 import java.util.Arrays;
17 import org.opendaylight.controller.sal.utils.NetUtils;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
22 * BitBufferHelper class that provides utility methods to
23 * - fetch specific bits from a serialized stream of bits
24 * - convert bits to primitive data type - like short, int, long
25 * - store bits in specified location in stream of bits
26 * - convert primitive data types to stream of bits
30 public abstract class BitBufferHelper {
31 protected static final Logger logger = LoggerFactory
32 .getLogger(BitBufferHelper.class);
34 public static long ByteMask = 0xFF;
37 // data: array where data are stored
38 // startOffset: bit from where to start reading
39 // numBits: number of bits to read
40 // All this function return an exception if overflow or underflow
43 * Returns the first byte from the byte array
47 public static byte getByte(byte[] data) {
48 if ((data.length * NetUtils.NumBitsInAByte) > Byte.SIZE) {
51 "Container is too small for the number of requested bits");
52 } catch (Exception e) {
60 * Returns the short value for the byte array passed.
61 * Size of byte array is restricted to Short.SIZE
65 public static short getShort(byte[] data) {
66 if (data.length > Short.SIZE) {
69 "Container is too small for the number of requested bits");
70 } catch (Exception e) {
74 return (short) toNumber(data);
78 * Returns the int value for the byte array passed.
79 * Size of byte array is restricted to Integer.SIZE
81 * @return int - the integer value of byte array
83 public static int getInt(byte[] data) {
84 if (data.length > Integer.SIZE) {
87 "Container is too small for the number of requested bits");
88 } catch (Exception e) {
92 return (int) toNumber(data);
96 * Returns the long value for the byte array passed.
97 * Size of byte array is restricted to Long.SIZE
99 * @return long - the integer value of byte array
101 public static long getLong(byte[] data) {
102 if (data.length > Long.SIZE) {
105 "Container is too small for the number of requested bits");
106 } catch (Exception e) {
110 return (long) toNumber(data);
114 * Returns the short value for the last numBits of the byte array passed.
115 * Size of numBits is restricted to Short.SIZE
117 * @param int - numBits
118 * @return short - the short value of byte array
121 public static short getShort(byte[] data, int numBits) throws Exception {
122 if (numBits > Short.SIZE) {
125 "Container is too small for the number of requested bits");
126 } catch (Exception e) {
130 int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
131 return (short) toNumber(BitBufferHelper.getBits(data, startOffset,
136 * Returns the int value for the last numBits of the byte array passed.
137 * Size of numBits is restricted to Integer.SIZE
139 * @param int - numBits
140 * @return int - the integer value of byte array
143 public static int getInt(byte[] data, int numBits) throws Exception {
144 if (numBits > Integer.SIZE) {
147 "Container is too small for the number of requiested bits");
148 } catch (Exception e) {
152 int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
153 return (int) toNumber(BitBufferHelper.getBits(data, startOffset,
158 * Returns the long value for the last numBits of the byte array passed.
159 * Size of numBits is restricted to Long.SIZE
161 * @param int - numBits
162 * @return long - the integer value of byte array
166 public static long getLong(byte[] data, int numBits) throws Exception {
167 if (numBits > Long.SIZE) {
170 "Container is too small for the number of requested bits");
171 } catch (Exception e) {
175 if (numBits > data.length * NetUtils.NumBitsInAByte) {
178 "Trying to read more bits than contained in the data buffer");
179 } catch (Exception e) {
183 int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
184 return toNumber(BitBufferHelper.getBits(data, startOffset, numBits),
189 * Reads the specified number of bits from the passed byte array
190 * starting to read from the specified offset
191 * The bits read are stored in a byte array which size is dictated
192 * by the number of bits to be stored.
193 * The bits are stored in the byte array LSB aligned.
196 * Read 7 bits at offset 10
198 * 0101000010 | 0000101 | 1111001010010101011
199 * will be returned as {0,0,0,0,0,1,0,1}
202 * @param int startOffset - offset to start fetching bits from data from
203 * @param int numBits - number of bits to be fetched from data
204 * @return byte [] - LSB aligned bits
207 public static byte[] getBits(byte[] data, int startOffset, int numBits)
210 int startByteOffset = 0;
211 int valfromcurr, valfromnext;
212 int extranumBits = numBits % NetUtils.NumBitsInAByte;
213 int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
214 int numBytes = (numBits % NetUtils.NumBitsInAByte != 0) ? 1 + numBits
215 / NetUtils.NumBitsInAByte : numBits / NetUtils.NumBitsInAByte;
216 byte[] shiftedBytes = new byte[numBytes];
217 startByteOffset = startOffset / NetUtils.NumBitsInAByte;
218 byte[] bytes = new byte[numBytes];
222 checkExceptions(data, startOffset, numBits);
224 if (extraOffsetBits == 0) {
225 if (extranumBits == 0) {
226 System.arraycopy(data, startByteOffset, bytes, 0, numBytes);
229 System.arraycopy(data, startByteOffset, bytes, 0, numBytes - 1);
230 bytes[numBytes - 1] = (byte) ((int) data[startByteOffset
231 + numBytes - 1] & getMSBMask(extranumBits));
235 for (i = 0; i < numBits / NetUtils.NumBitsInAByte; i++) {
236 // Reading Numbytes starting from offset
237 valfromcurr = (data[startByteOffset + i])
238 & getLSBMask(NetUtils.NumBitsInAByte - extraOffsetBits);
239 valfromnext = (data[startByteOffset + i + 1])
240 & getMSBMask(extraOffsetBits);
241 bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits)));
243 // Now adding the rest of the bits if any
244 if (extranumBits != 0) {
245 if (extranumBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
246 valfromnext = (byte) (data[startByteOffset + i + 1] & ((getMSBMask(extranumBits)) >> extraOffsetBits));
247 bytes[i] = (byte) (valfromnext << extraOffsetBits);
248 } else if (extranumBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
249 valfromcurr = (data[startByteOffset + i])
250 & getLSBMask(NetUtils.NumBitsInAByte
252 bytes[i] = (byte) (valfromcurr << extraOffsetBits);
254 valfromcurr = (data[startByteOffset + i])
255 & getLSBMask(NetUtils.NumBitsInAByte
257 valfromnext = (data[startByteOffset + i + 1])
258 & (getMSBMask(extranumBits
259 - (NetUtils.NumBitsInAByte - extraOffsetBits)));
260 bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits)));
265 // Aligns the bits to LSB
266 shiftedBytes = shiftBitsToLSB(bytes, numBits);
271 // data: array where data will be stored
272 // input: the data that need to be stored in the data array
273 // startOffset: bit from where to start writing
274 // numBits: number of bits to read
277 * Bits are expected to be stored in the input byte array from LSB
278 * @param byte[] - data to set the input byte
279 * @param byte - input byte to be inserted
280 * @param startOffset - offset of data[] to start inserting byte from
281 * @param numBits - number of bits of input to be inserted into data[]
285 public static void setByte(byte[] data, byte input, int startOffset,
286 int numBits) throws Exception {
287 byte[] inputByteArray = new byte[1];
288 Arrays.fill(inputByteArray, 0, 1, input);
289 setBytes(data, inputByteArray, startOffset, numBits);
293 * Bits are expected to be stored in the input byte array from LSB
294 * @param byte[] - data to set the input byte
295 * @param byte[] - input bytes to be inserted
296 * @param startOffset - offset of data[] to start inserting byte from
297 * @param numBits - number of bits of input to be inserted into data[]
301 public static void setBytes(byte[] data, byte[] input, int startOffset,
302 int numBits) throws Exception {
303 checkExceptions(data, startOffset, numBits);
304 insertBits(data, input, startOffset, numBits);
308 * Returns numBits 1's in the MSB position
312 public static int getMSBMask(int numBits) {
314 for (int i = 0; i < numBits; i++) {
315 mask = mask | (1 << (7 - i));
321 * Returns numBits 1's in the LSB position
325 public static int getLSBMask(int numBits) {
327 for (int i = 0; i < numBits; i++) {
328 mask = mask | (1 << i);
334 * Returns the numerical value of the byte array passed
335 * @param byte[] - array
336 * @return long - numerical value of byte array passed
338 static public long toNumber(byte[] array) {
340 long length = array.length;
342 for (int i = 0; i < length; i++) {
347 | (long) ((long) value << ((length - i - 1) * NetUtils.NumBitsInAByte));
353 * Returns the numerical value of the last numBits (LSB bits)
354 * of the byte array passed
355 * @param byte[] - array
356 * @param int - numBits
357 * @return long - numerical value of byte array passed
359 static public long toNumber(byte[] array, int numBits) {
360 int length = numBits / NetUtils.NumBitsInAByte;
361 int bitsRest = numBits % NetUtils.NumBitsInAByte;
362 int startOffset = array.length - length;
366 value = array[startOffset - 1] & getLSBMask(bitsRest);
367 value = (array[startOffset - 1] < 0) ? (array[startOffset - 1] + 256)
368 : array[startOffset - 1];
370 | (value << ((array.length - startOffset) * NetUtils.NumBitsInAByte));
372 for (int i = startOffset; i < array.length; i++) {
377 | (long) ((long) value << ((array.length - i - 1) * NetUtils.NumBitsInAByte));
384 * Accepts a number as input and returns its value in byte form
385 * in LSB aligned form
386 * example: input = 5000 [1001110001000]
387 * bytes = 19, -120 [00010011] [10001000]
393 public static byte[] toByteArray(Number input) {
394 Class<? extends Number> dataType = input.getClass();
396 long Lvalue = input.longValue();
398 if (dataType == Byte.class || dataType == byte.class)
400 else if (dataType == Short.class || dataType == short.class)
402 else if (dataType == Integer.class || dataType == int.class)
404 else if (dataType == Long.class || dataType == long.class)
407 throw new IllegalArgumentException(
408 "Parameter must one of the following: Short/Int/Long\n");
410 int length = size / NetUtils.NumBitsInAByte;
411 byte bytes[] = new byte[length];
413 /*Getting the bytes from input value*/
414 for (int i = 0; i < length; i++) {
415 bytes[i] = (byte) ((Lvalue >> (NetUtils.NumBitsInAByte * (length
416 - i - 1))) & ByteMask);
422 * Accepts a number as input and returns its value in byte form
423 * in MSB aligned form
424 * example: input = 5000 [1001110001000]
425 * bytes = -114, 64 [10011100] [01000000]
426 * @param Number input
427 * @param int numBits - the number of bits to be returned
431 public static byte[] toByteArray(Number input, int numBits) {
432 Class<? extends Number> dataType = input.getClass();
434 long Lvalue = input.longValue();
436 if (dataType == Short.class) {
438 } else if (dataType == Integer.class) {
440 } else if (dataType == Long.class) {
443 throw new IllegalArgumentException(
444 "Parameter must one of the following: Short/Int/Long\n");
447 int length = size / NetUtils.NumBitsInAByte;
448 byte bytes[] = new byte[length];
449 byte[] inputbytes = new byte[length];
452 //Getting the bytes from input value
453 for (int i = 0; i < length; i++) {
454 bytes[i] = (byte) ((Lvalue >> (NetUtils.NumBitsInAByte * (length
455 - i - 1))) & ByteMask);
458 if ((bytes[0] == 0 && dataType == Long.class)
459 || (bytes[0] == 0 && dataType == Integer.class)) {
461 for (index = 0; index < length; ++index) {
462 if (bytes[index] != 0) {
463 bytes[0] = bytes[index];
467 System.arraycopy(bytes, index, inputbytes, 0, length - index);
468 Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
470 System.arraycopy(bytes, 0, inputbytes, 0, length);
473 shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
479 * Takes an LSB aligned byte array and returned the LSB numBits in a MSB aligned byte array
486 * It aligns the last numBits bits to the head of the byte array
487 * following them with numBits % 8 zero bits.
490 * For inputbytes = [00000111][01110001] and numBits = 12 it returns:
491 * shiftedBytes = [01110111][00010000]
493 * @param byte[] inputBytes
494 * @param int numBits - number of bits to be left aligned
497 public static byte[] shiftBitsToMSB(byte[] inputBytes, int numBits) {
498 int numBitstoShiftBy = 0, leadZeroesMSB = 8, numEndRestBits = 0;
499 int size = inputBytes.length;
500 byte[] shiftedBytes = new byte[size];
503 for (i = 0; i < Byte.SIZE; i++) {
504 if (((byte) (inputBytes[0] & getMSBMask(i + 1))) != 0) {
510 if (numBits % NetUtils.NumBitsInAByte == 0)
511 numBitstoShiftBy = 0;
513 numBitstoShiftBy = ((NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte)) < leadZeroesMSB) ? (NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte))
516 if (numBitstoShiftBy == 0)
519 if (numBits < NetUtils.NumBitsInAByte) { //inputbytes.length = 1 OR Read less than a byte
520 shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
522 numEndRestBits = NetUtils.NumBitsInAByte
523 - (inputBytes.length * NetUtils.NumBitsInAByte - numBits - numBitstoShiftBy); //# of bits to read from last byte
524 for (i = 0; i < (size - 1); i++) {
525 if ((i + 1) == (size - 1)) {
526 if (numEndRestBits > numBitstoShiftBy) {
527 shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (numEndRestBits - numBitstoShiftBy)));
528 shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1] & getLSBMask(numEndRestBits
529 - numBitstoShiftBy)) << numBitstoShiftBy);
531 shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> (NetUtils.NumBitsInAByte - numEndRestBits)));
533 shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (NetUtils.NumBitsInAByte - numBitstoShiftBy));
541 * It aligns the first numBits bits to the right end of the byte array
542 * preceding them with numBits % 8 zero bits.
545 * For inputbytes = [01110111][00010000] and numBits = 12 it returns:
546 * shiftedBytes = [00000111][01110001]
548 * @param byte[] inputBytes
549 * @param int numBits - number of bits to be right aligned
552 public static byte[] shiftBitsToLSB(byte[] inputBytes, int numBits) {
553 int numBytes = inputBytes.length;
554 int numBitstoShift = numBits % NetUtils.NumBitsInAByte;
555 byte[] shiftedBytes = new byte[numBytes];
556 int inputLsb = 0, inputMsb = 0;
558 if (numBitstoShift == 0)
561 for (int i = 1; i < numBytes; i++) {
562 inputLsb = inputBytes[i - 1]
563 & getLSBMask(NetUtils.NumBitsInAByte - numBitstoShift);
564 inputLsb = (inputLsb < 0) ? (inputLsb + 256) : inputLsb;
565 inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
566 inputMsb = (inputBytes[i] < 0) ? (inputBytes[i] + 256)
568 shiftedBytes[i] = (byte) ((inputLsb << numBitstoShift) | (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift)));
570 inputMsb = inputBytes[0] & (getMSBMask(numBitstoShift));
571 inputMsb = (inputMsb < 0) ? (inputMsb + 256) : inputMsb;
572 shiftedBytes[0] = (byte) (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift));
577 * Insert in the data buffer at position dictated by the offset the number
578 * of bits specified from the input data byte array.
579 * The input byte array has the bits stored starting from the LSB
582 * @param byte[] inputdata
583 * @param int startOffset
587 public static void insertBits(byte[] data, byte[] inputdataLSB,
588 int startOffset, int numBits) {
589 byte[] inputdata = shiftBitsToMSB(inputdataLSB, numBits); // Align to MSB the passed byte array
590 int numBytes = numBits / NetUtils.NumBitsInAByte;
591 int startByteOffset = startOffset / NetUtils.NumBitsInAByte;
592 int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
593 int extranumBits = numBits % NetUtils.NumBitsInAByte;
594 int RestBits = numBits % NetUtils.NumBitsInAByte;
595 int InputMSBbits = 0, InputLSBbits = 0;
601 if (extraOffsetBits == 0) {
602 if (extranumBits == 0) {
603 numBytes = numBits / NetUtils.NumBitsInAByte;
604 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
606 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
607 data[startByteOffset + numBytes] = (byte) (data[startByteOffset
608 + numBytes] | (inputdata[numBytes] & getMSBMask(extranumBits)));
611 for (i = 0; i < numBytes; i++) {
613 InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
614 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
615 - extraOffsetBits)));
616 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
617 : InputMSBbits + 256;
618 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
619 | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
620 InputMSBbits = InputLSBbits = 0;
622 if (RestBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
624 InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
625 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(RestBits)));
626 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
627 : InputMSBbits + 256;
628 data[startByteOffset + i] = (byte) ((data[startByteOffset + i])
629 | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
630 } else if (RestBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
632 InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
633 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
634 - extraOffsetBits)));
635 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
636 : InputMSBbits + 256;
637 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
638 | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
641 InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
642 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
643 - extraOffsetBits)));
644 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
645 : InputMSBbits + 256;
646 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
647 | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
649 InputLSBbits = (inputdata[i] & (getLSBMask(RestBits
650 - (NetUtils.NumBitsInAByte - extraOffsetBits)) << (NetUtils.NumBitsInAByte - RestBits)));
651 data[startByteOffset + i + 1] = (byte) (data[startByteOffset
652 + i + 1] | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)));
658 * Checks for overflow and underflow exceptions
664 public static void checkExceptions(byte[] data, int startOffset, int numBits)
668 endOffsetByte = startOffset
669 / NetUtils.NumBitsInAByte
671 / NetUtils.NumBitsInAByte
672 + ((numBits % NetUtils.NumBitsInAByte != 0) ? 1 : ((startOffset
673 % NetUtils.NumBitsInAByte != 0) ? 1 : 0));
674 startByteOffset = startOffset / NetUtils.NumBitsInAByte;
677 throw new Exception("data[] is null\n");
680 if ((startOffset < 0) || (startByteOffset >= data.length)
681 || (endOffsetByte > data.length) || (numBits < 0)
682 || (numBits > NetUtils.NumBitsInAByte * data.length)) {
684 "Illegal arguement/out of bound exception - data.length = "
685 + data.length + " startOffset = " + startOffset
686 + " numBits " + numBits);