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;
20 * BitBufferHelper class that provides utility methods to
21 * - fetch specific bits from a serialized stream of bits
22 * - convert bits to primitive data type - like short, int, long
23 * - store bits in specified location in stream of bits
24 * - convert primitive data types to stream of bits
28 public abstract class BitBufferHelper {
30 public static long ByteMask = 0xFF;
33 // data: array where data are stored
34 // startOffset: bit from where to start reading
35 // numBits: number of bits to read
36 // All this function return an exception if overflow or underflow
39 * Returns the first byte from the byte array
43 public static byte getByte(byte[] data) {
44 if ((data.length * NetUtils.NumBitsInAByte) > Byte.SIZE) {
47 "Container is too small for the number of requested bits");
48 } catch (Exception e) {
56 * Returns the short value for the byte array passed.
57 * Size of byte array is restricted to Short.SIZE
61 public static short getShort(byte[] data) {
62 if (data.length > Short.SIZE) {
65 "Container is too small for the number of requested bits");
66 } catch (Exception e) {
70 return (short) toNumber(data);
74 * Returns the int value for the byte array passed.
75 * Size of byte array is restricted to Integer.SIZE
77 * @return int - the integer value of byte array
79 public static int getInt(byte[] data) {
80 if (data.length > Integer.SIZE) {
83 "Container is too small for the number of requested bits");
84 } catch (Exception e) {
88 return (int) toNumber(data);
92 * Returns the long value for the byte array passed.
93 * Size of byte array is restricted to Long.SIZE
95 * @return long - the integer value of byte array
97 public static long getLong(byte[] data) {
98 if (data.length > Long.SIZE) {
101 "Container is too small for the number of requested bits");
102 } catch (Exception e) {
106 return (long) toNumber(data);
110 * Returns the short value for the last numBits of the byte array passed.
111 * Size of numBits is restricted to Short.SIZE
113 * @param int - numBits
114 * @return short - the short value of byte array
117 public static short getShort(byte[] data, int numBits) throws Exception {
118 if (numBits > Short.SIZE) {
121 "Container is too small for the number of requested bits");
122 } catch (Exception e) {
126 int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
127 return (short) toNumber(BitBufferHelper.getBits(data, startOffset,
132 * Returns the int value for the last numBits of the byte array passed.
133 * Size of numBits is restricted to Integer.SIZE
135 * @param int - numBits
136 * @return int - the integer value of byte array
139 public static int getInt(byte[] data, int numBits) throws Exception {
140 if (numBits > Integer.SIZE) {
143 "Container is too small for the number of requiested bits");
144 } catch (Exception e) {
148 int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
149 return (int) toNumber(BitBufferHelper.getBits(data, startOffset,
154 * Returns the long value for the last numBits of the byte array passed.
155 * Size of numBits is restricted to Long.SIZE
157 * @param int - numBits
158 * @return long - the integer value of byte array
162 public static long getLong(byte[] data, int numBits) throws Exception {
163 if (numBits > Long.SIZE) {
166 "Container is too small for the number of requested bits");
167 } catch (Exception e) {
171 if (numBits > data.length * NetUtils.NumBitsInAByte) {
174 "Trying to read more bits than contained in the data buffer");
175 } catch (Exception e) {
179 int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
180 return toNumber(BitBufferHelper.getBits(data, startOffset, numBits),
185 * Reads the specified number of bits from the passed byte array
186 * starting to read from the specified offset
187 * The bits read are stored in a byte array which size is dictated
188 * by the number of bits to be stored.
189 * The bits are stored in the byte array LSB aligned.
192 * Read 7 bits at offset 10
194 * 0101000010 | 0000101 | 1111001010010101011
195 * will be returned as {0,0,0,0,0,1,0,1}
198 * @param int startOffset - offset to start fetching bits from data from
199 * @param int numBits - number of bits to be fetched from data
200 * @return byte [] - LSB aligned bits
203 public static byte[] getBits(byte[] data, int startOffset, int numBits)
206 int startByteOffset = 0;
207 int valfromcurr, valfromnext;
208 int extranumBits = numBits % NetUtils.NumBitsInAByte;
209 int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
210 int numBytes = (numBits % NetUtils.NumBitsInAByte != 0) ? 1 + numBits
211 / NetUtils.NumBitsInAByte : numBits / NetUtils.NumBitsInAByte;
212 byte[] shiftedBytes = new byte[numBytes];
213 startByteOffset = startOffset / NetUtils.NumBitsInAByte;
214 byte[] bytes = new byte[numBytes];
218 checkExceptions(data, startOffset, numBits);
220 if (extraOffsetBits == 0) {
221 if (extranumBits == 0) {
222 System.arraycopy(data, startByteOffset, bytes, 0, numBytes);
225 System.arraycopy(data, startByteOffset, bytes, 0, numBytes - 1);
226 bytes[numBytes - 1] = (byte) ((int) data[startByteOffset
227 + numBytes - 1] & getMSBMask(extranumBits));
231 for (i = 0; i < numBits / NetUtils.NumBitsInAByte; i++) {
232 // Reading Numbytes starting from offset
233 valfromcurr = (data[startByteOffset + i])
234 & getLSBMask(NetUtils.NumBitsInAByte - extraOffsetBits);
235 valfromnext = (data[startByteOffset + i + 1])
236 & getMSBMask(extraOffsetBits);
237 bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits)));
239 // Now adding the rest of the bits if any
240 if (extranumBits != 0) {
241 if (extranumBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
242 valfromnext = (byte) (data[startByteOffset + i + 1] & ((getMSBMask(extranumBits)) >> extraOffsetBits));
243 bytes[i] = (byte) (valfromnext << extraOffsetBits);
244 } else if (extranumBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
245 valfromcurr = (data[startByteOffset + i])
246 & getLSBMask(NetUtils.NumBitsInAByte
248 bytes[i] = (byte) (valfromcurr << extraOffsetBits);
250 valfromcurr = (data[startByteOffset + i])
251 & getLSBMask(NetUtils.NumBitsInAByte
253 valfromnext = (data[startByteOffset + i + 1])
254 & (getMSBMask(extranumBits
255 - (NetUtils.NumBitsInAByte - extraOffsetBits)));
256 bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits)));
261 // Aligns the bits to LSB
262 shiftedBytes = shiftBitsToLSB(bytes, numBits);
267 // data: array where data will be stored
268 // input: the data that need to be stored in the data array
269 // startOffset: bit from where to start writing
270 // numBits: number of bits to read
273 * Bits are expected to be stored in the input byte array from LSB
274 * @param byte[] - data to set the input byte
275 * @param byte - input byte to be inserted
276 * @param startOffset - offset of data[] to start inserting byte from
277 * @param numBits - number of bits of input to be inserted into data[]
281 public static void setByte(byte[] data, byte input, int startOffset,
282 int numBits) throws Exception {
283 byte[] inputByteArray = new byte[1];
284 Arrays.fill(inputByteArray, 0, 1, input);
285 setBytes(data, inputByteArray, startOffset, numBits);
289 * Bits are expected to be stored in the input byte array from LSB
290 * @param byte[] - data to set the input byte
291 * @param byte[] - input bytes to be inserted
292 * @param startOffset - offset of data[] to start inserting byte from
293 * @param numBits - number of bits of input to be inserted into data[]
297 public static void setBytes(byte[] data, byte[] input, int startOffset,
298 int numBits) throws Exception {
299 checkExceptions(data, startOffset, numBits);
300 insertBits(data, input, startOffset, numBits);
304 * Returns numBits 1's in the MSB position
308 public static int getMSBMask(int numBits) {
310 for (int i = 0; i < numBits; i++) {
311 mask = mask | (1 << (7 - i));
317 * Returns numBits 1's in the LSB position
321 public static int getLSBMask(int numBits) {
323 for (int i = 0; i < numBits; i++) {
324 mask = mask | (1 << i);
330 * Returns the numerical value of the byte array passed
331 * @param byte[] - array
332 * @return long - numerical value of byte array passed
334 static public long toNumber(byte[] array) {
336 long length = array.length;
338 for (int i = 0; i < length; i++) {
343 | (long) ((long) value << ((length - i - 1) * NetUtils.NumBitsInAByte));
349 * Returns the numerical value of the last numBits (LSB bits)
350 * of the byte array passed
351 * @param byte[] - array
352 * @param int - numBits
353 * @return long - numerical value of byte array passed
355 static public long toNumber(byte[] array, int numBits) {
356 int length = numBits / NetUtils.NumBitsInAByte;
357 int bitsRest = numBits % NetUtils.NumBitsInAByte;
358 int startOffset = array.length - length;
362 value = array[startOffset - 1] & getLSBMask(bitsRest);
363 value = (array[startOffset - 1] < 0) ? (array[startOffset - 1] + 256)
364 : array[startOffset - 1];
366 | (value << ((array.length - startOffset) * NetUtils.NumBitsInAByte));
368 for (int i = startOffset; i < array.length; i++) {
373 | (long) ((long) value << ((array.length - i - 1) * NetUtils.NumBitsInAByte));
380 * Accepts a number as input and returns its value in byte form
381 * in LSB aligned form
382 * example: input = 5000 [1001110001000]
383 * bytes = 19, -120 [00010011] [10001000]
389 public static byte[] toByteArray(Number input) {
390 Class<? extends Number> dataType = input.getClass();
392 long Lvalue = input.longValue();
394 if (dataType == Byte.class || dataType == byte.class)
396 else if (dataType == Short.class || dataType == short.class)
398 else if (dataType == Integer.class || dataType == int.class)
400 else if (dataType == Long.class || dataType == long.class)
403 throw new IllegalArgumentException(
404 "Parameter must one of the following: Short/Int/Long\n");
406 int length = size / NetUtils.NumBitsInAByte;
407 byte bytes[] = new byte[length];
409 /*Getting the bytes from input value*/
410 for (int i = 0; i < length; i++) {
411 bytes[i] = (byte) ((Lvalue >> (NetUtils.NumBitsInAByte * (length
412 - i - 1))) & ByteMask);
418 * Accepts a number as input and returns its value in byte form
419 * in MSB aligned form
420 * example: input = 5000 [1001110001000]
421 * bytes = -114, 64 [10011100] [01000000]
422 * @param Number input
423 * @param int numBits - the number of bits to be returned
427 public static byte[] toByteArray(Number input, int numBits) {
428 Class<? extends Number> dataType = input.getClass();
430 long Lvalue = input.longValue();
432 if (dataType == Short.class) {
434 } else if (dataType == Integer.class) {
436 } else if (dataType == Long.class) {
439 throw new IllegalArgumentException(
440 "Parameter must one of the following: Short/Int/Long\n");
443 int length = size / NetUtils.NumBitsInAByte;
444 byte bytes[] = new byte[length];
445 byte[] inputbytes = new byte[length];
448 //Getting the bytes from input value
449 for (int i = 0; i < length; i++) {
450 bytes[i] = (byte) ((Lvalue >> (NetUtils.NumBitsInAByte * (length
451 - i - 1))) & ByteMask);
454 if ((bytes[0] == 0 && dataType == Long.class)
455 || (bytes[0] == 0 && dataType == Integer.class)) {
457 for (index = 0; index < length; ++index) {
458 if (bytes[index] != 0) {
459 bytes[0] = bytes[index];
463 System.arraycopy(bytes, index, inputbytes, 0, length - index);
464 Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
466 System.arraycopy(bytes, 0, inputbytes, 0, length);
469 shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
475 * Takes an LSB aligned byte array and returned the LSB numBits in a MSB aligned byte array
482 * It aligns the last numBits bits to the head of the byte array
483 * following them with numBits % 8 zero bits.
486 * For inputbytes = [00000111][01110001] and numBits = 12 it returns:
487 * shiftedBytes = [01110111][00010000]
489 * @param byte[] inputBytes
490 * @param int numBits - number of bits to be left aligned
493 public static byte[] shiftBitsToMSB(byte[] inputBytes, int numBits) {
494 int numBitstoShiftBy = 0, leadZeroesMSB = 8, numEndRestBits = 0;
495 int size = inputBytes.length;
496 byte[] shiftedBytes = new byte[size];
499 for (i = 0; i < Byte.SIZE; i++) {
500 if (((byte) (inputBytes[0] & getMSBMask(i + 1))) != 0) {
506 if (numBits % NetUtils.NumBitsInAByte == 0)
507 numBitstoShiftBy = 0;
509 numBitstoShiftBy = ((NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte)) < leadZeroesMSB) ? (NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte))
512 if (numBitstoShiftBy == 0)
515 if (numBits < NetUtils.NumBitsInAByte) { //inputbytes.length = 1 OR Read less than a byte
516 shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
518 numEndRestBits = NetUtils.NumBitsInAByte
519 - (inputBytes.length * NetUtils.NumBitsInAByte - numBits - numBitstoShiftBy); //# of bits to read from last byte
520 for (i = 0; i < (size - 1); i++) {
521 if ((i + 1) == (size - 1)) {
522 if (numEndRestBits > numBitstoShiftBy) {
523 shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (numEndRestBits - numBitstoShiftBy)));
524 shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1] & getLSBMask(numEndRestBits
525 - numBitstoShiftBy)) << numBitstoShiftBy);
527 shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> (NetUtils.NumBitsInAByte - numEndRestBits)));
529 shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (NetUtils.NumBitsInAByte - numBitstoShiftBy));
537 * It aligns the first numBits bits to the right end of the byte array
538 * preceding them with numBits % 8 zero bits.
541 * For inputbytes = [01110111][00010000] and numBits = 12 it returns:
542 * shiftedBytes = [00000111][01110001]
544 * @param byte[] inputBytes
545 * @param int numBits - number of bits to be right aligned
548 public static byte[] shiftBitsToLSB(byte[] inputBytes, int numBits) {
549 int numBytes = inputBytes.length;
550 int numBitstoShift = numBits % NetUtils.NumBitsInAByte;
551 byte[] shiftedBytes = new byte[numBytes];
552 int inputLsb = 0, inputMsb = 0;
554 if (numBitstoShift == 0)
557 for (int i = 1; i < numBytes; i++) {
558 inputLsb = inputBytes[i - 1]
559 & getLSBMask(NetUtils.NumBitsInAByte - numBitstoShift);
560 inputLsb = (inputLsb < 0) ? (inputLsb + 256) : inputLsb;
561 inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
562 inputMsb = (inputBytes[i] < 0) ? (inputBytes[i] + 256)
564 shiftedBytes[i] = (byte) ((inputLsb << numBitstoShift) | (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift)));
566 inputMsb = inputBytes[0] & (getMSBMask(numBitstoShift));
567 inputMsb = (inputMsb < 0) ? (inputMsb + 256) : inputMsb;
568 shiftedBytes[0] = (byte) (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift));
573 * Insert in the data buffer at position dictated by the offset the number
574 * of bits specified from the input data byte array.
575 * The input byte array has the bits stored starting from the LSB
578 * @param byte[] inputdata
579 * @param int startOffset
583 public static void insertBits(byte[] data, byte[] inputdataLSB,
584 int startOffset, int numBits) {
585 byte[] inputdata = shiftBitsToMSB(inputdataLSB, numBits); // Align to MSB the passed byte array
586 int numBytes = numBits / NetUtils.NumBitsInAByte;
587 int startByteOffset = startOffset / NetUtils.NumBitsInAByte;
588 int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
589 int extranumBits = numBits % NetUtils.NumBitsInAByte;
590 int RestBits = numBits % NetUtils.NumBitsInAByte;
591 int InputMSBbits = 0, InputLSBbits = 0;
597 if (extraOffsetBits == 0) {
598 if (extranumBits == 0) {
599 numBytes = numBits / NetUtils.NumBitsInAByte;
600 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
602 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
603 data[startByteOffset + numBytes] = (byte) (data[startByteOffset
604 + numBytes] | (inputdata[numBytes] & getMSBMask(extranumBits)));
607 for (i = 0; i < numBytes; i++) {
609 InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
610 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
611 - extraOffsetBits)));
612 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
613 : InputMSBbits + 256;
614 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
615 | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
616 InputMSBbits = InputLSBbits = 0;
618 if (RestBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
620 InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
621 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(RestBits)));
622 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
623 : InputMSBbits + 256;
624 data[startByteOffset + i] = (byte) ((data[startByteOffset + i])
625 | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
626 } else if (RestBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
628 InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
629 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
630 - extraOffsetBits)));
631 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
632 : InputMSBbits + 256;
633 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
634 | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
637 InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
638 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
639 - extraOffsetBits)));
640 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
641 : InputMSBbits + 256;
642 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
643 | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
645 InputLSBbits = (inputdata[i] & (getLSBMask(RestBits
646 - (NetUtils.NumBitsInAByte - extraOffsetBits)) << (NetUtils.NumBitsInAByte - RestBits)));
647 data[startByteOffset + i + 1] = (byte) (data[startByteOffset
648 + i + 1] | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)));
654 * Checks for overflow and underflow exceptions
660 public static void checkExceptions(byte[] data, int startOffset, int numBits)
664 endOffsetByte = startOffset
665 / NetUtils.NumBitsInAByte
667 / NetUtils.NumBitsInAByte
668 + ((numBits % NetUtils.NumBitsInAByte != 0) ? 1 : ((startOffset
669 % NetUtils.NumBitsInAByte != 0) ? 1 : 0));
670 startByteOffset = startOffset / NetUtils.NumBitsInAByte;
673 throw new Exception("data[] is null\n");
676 if ((startOffset < 0) || (startByteOffset >= data.length)
677 || (endOffsetByte > data.length) || (numBits < 0)
678 || (numBits > NetUtils.NumBitsInAByte * data.length)) {
680 "Illegal arguement/out of bound exception - data.length = "
681 + data.length + " startOffset = " + startOffset
682 + " numBits " + numBits);