90cfdaaf0fb19fb925ee0625ce088165784b58fa
[openflowplugin.git] / libraries / liblldp / src / main / java / org / opendaylight / openflowplugin / libraries / liblldp / BitBufferHelper.java
1 /*
2  * Copyright (c) 2013, 2017 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.openflowplugin.libraries.liblldp;
9
10 import java.util.Arrays;
11 import org.eclipse.jdt.annotation.NonNull;
12 import org.slf4j.Logger;
13 import org.slf4j.LoggerFactory;
14
15 /**
16  * BitBufferHelper class that provides utility methods to - fetch specific bits
17  * from a serialized stream of bits - convert bits to primitive data type - like
18  * short, int, long - store bits in specified location in stream of bits -
19  * convert primitive data types to stream of bits.
20  */
21 public abstract class BitBufferHelper {
22     private static final Logger LOG = LoggerFactory.getLogger(BitBufferHelper.class);
23
24     public static final long BYTE_MASK = 0xFF;
25
26     // Getters
27     // data: array where data are stored
28     // startOffset: bit from where to start reading
29     // numBits: number of bits to read
30     // All this function return an exception if overflow or underflow
31
32     /**
33      * Returns the first byte from the byte array.
34      *
35      * @return byte value
36      */
37     public static byte getByte(final byte[] data) {
38         if (data.length * NetUtils.NUM_BITS_IN_A_BYTE > Byte.SIZE) {
39             LOG.error("getByte", new BufferException("Container is too small for the number of requested bits"));
40         }
41         return data[0];
42     }
43
44     /**
45      * Returns the short value for the byte array passed. Size of byte array is
46      * restricted to Short.SIZE
47      *
48      * @return short value
49      */
50     public static short getShort(final byte[] data) {
51         if (data.length > Short.SIZE) {
52             LOG.error("getShort", new BufferException("Container is too small for the number of requested bits"));
53         }
54         return (short) toNumber(data);
55     }
56
57     /**
58      * Returns the short value for the last numBits of the byte array passed.
59      * Size of numBits is restricted to Short.SIZE
60      *
61      * @return short - the short value of byte array
62      */
63     public static short getShort(final byte[] data, final int numBits) {
64         if (numBits > Short.SIZE) {
65             LOG.error("getShort", new BufferException("Container is too small for the number of requested bits"));
66         }
67         int startOffset = data.length * NetUtils.NUM_BITS_IN_A_BYTE - numBits;
68         try {
69             byte[] bits = BitBufferHelper.getBits(data, startOffset, numBits);
70             return (short) toNumber(bits, numBits);
71         } catch (final BufferException e) {
72             LOG.error("getBits failed", e);
73         }
74         return 0;
75     }
76
77     /**
78      * Returns the int value for the byte array passed. Size of byte array is
79      * restricted to Integer.SIZE
80      *
81      * @return int - the integer value of byte array
82      */
83     public static int getInt(final byte[] data) {
84         if (data.length > Integer.SIZE) {
85             LOG.error("getInt", new BufferException("Container is too small for the number of requested bits"));
86         }
87         return (int) toNumber(data);
88     }
89
90     /**
91      * Returns the int value for the last numBits of the byte array passed. Size
92      * of numBits is restricted to Integer.SIZE
93      *
94      * @return int - the integer value of byte array
95      */
96     public static int getInt(final byte[] data, final int numBits) {
97         if (numBits > Integer.SIZE) {
98             LOG.error("getInt", new BufferException("Container is too small for the number of requested bits"));
99         }
100         int startOffset = data.length * NetUtils.NUM_BITS_IN_A_BYTE - numBits;
101         try {
102             byte[] bits = BitBufferHelper.getBits(data, startOffset, numBits);
103             return (int) toNumber(bits, numBits);
104         } catch (final BufferException e) {
105             LOG.error("getBits failed", e);
106         }
107         return 0;
108     }
109
110     /**
111      * Returns the long value for the byte array passed. Size of byte array is
112      * restricted to Long.SIZE
113      *
114      * @return long - the integer value of byte array
115      */
116     public static long getLong(final byte[] data) {
117         if (data.length > Long.SIZE) {
118             LOG.error("getLong", new BufferException("Container is too small for the number of requested bits"));
119         }
120         return toNumber(data);
121     }
122
123     /**
124      * Returns the long value for the last numBits of the byte array passed.
125      * Size of numBits is restricted to Long.SIZE
126      *
127      * @return long - the integer value of byte array
128      */
129     public static long getLong(final byte[] data, final int numBits) {
130         if (numBits > Long.SIZE) {
131             LOG.error("getLong", new BufferException("Container is too small for the number of requested bits"));
132         }
133         if (numBits > data.length * NetUtils.NUM_BITS_IN_A_BYTE) {
134             LOG.error("getLong", new BufferException("Trying to read more bits than contained in the data buffer"));
135         }
136         int startOffset = data.length * NetUtils.NUM_BITS_IN_A_BYTE - numBits;
137         try {
138             byte[] bits = BitBufferHelper.getBits(data, startOffset, numBits);
139             return toNumber(bits, numBits);
140         } catch (final BufferException e) {
141             LOG.error("getBits failed", e);
142         }
143         return 0;
144     }
145
146     /**
147      * Reads the specified number of bits from the passed byte array starting to
148      * read from the specified offset The bits read are stored in a byte array
149      * which size is dictated by the number of bits to be stored. The bits are
150      * stored in the byte array LSB aligned.
151      *
152      * <p>
153      * Ex. Read 7 bits at offset 10 0 9 10 16 17 0101000010 | 0000101 |
154      * 1111001010010101011 will be returned as {0,0,0,0,0,1,0,1}
155      *
156      * @param startOffset
157      *            - offset to start fetching bits from data from
158      * @param numBits
159      *            - number of bits to be fetched from data
160      * @return byte [] - LSB aligned bits
161      *
162      * @throws BufferException
163      *             when the startOffset and numBits parameters are not congruent
164      *             with the data buffer size
165      */
166     public static byte @NonNull [] getBits(final byte[] data, final int startOffset, final int numBits)
167             throws BufferException {
168         int startByteOffset;
169         int extranumBits = numBits % NetUtils.NUM_BITS_IN_A_BYTE;
170         final int extraOffsetBits = startOffset % NetUtils.NUM_BITS_IN_A_BYTE;
171         int numBytes = numBits % NetUtils.NUM_BITS_IN_A_BYTE != 0 ? 1 + numBits / NetUtils.NUM_BITS_IN_A_BYTE
172                 : numBits / NetUtils.NUM_BITS_IN_A_BYTE;
173         startByteOffset = startOffset / NetUtils.NUM_BITS_IN_A_BYTE;
174         byte[] bytes = new byte[numBytes];
175         if (numBits == 0) {
176             return bytes;
177         }
178
179         checkExceptions(data, startOffset, numBits);
180
181         if (extraOffsetBits == 0) {
182             if (extranumBits == 0) {
183                 System.arraycopy(data, startByteOffset, bytes, 0, numBytes);
184                 return bytes;
185             } else {
186                 System.arraycopy(data, startByteOffset, bytes, 0, numBytes - 1);
187                 bytes[numBytes - 1] = (byte) (data[startByteOffset + numBytes - 1] & getMSBMask(extranumBits));
188             }
189         } else {
190             int index;
191             int valfromcurr;
192             int valfromnext;
193             for (index = 0; index < numBits / NetUtils.NUM_BITS_IN_A_BYTE; index++) {
194                 // Reading numBytes starting from offset
195                 valfromcurr = data[startByteOffset + index] & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
196                 valfromnext = data[startByteOffset + index + 1] & getMSBMask(extraOffsetBits);
197                 bytes[index] = (byte) (valfromcurr << extraOffsetBits
198                         | valfromnext >> NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
199             }
200             // Now adding the rest of the bits if any
201             if (extranumBits != 0) {
202                 if (extranumBits < NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits) {
203                     valfromnext = (byte) (data[startByteOffset + index] & getMSBMask(extranumBits) >> extraOffsetBits);
204                     bytes[index] = (byte) (valfromnext << extraOffsetBits);
205                 } else if (extranumBits == NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits) {
206                     valfromcurr = data[startByteOffset + index]
207                             & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
208                     bytes[index] = (byte) (valfromcurr << extraOffsetBits);
209                 } else {
210                     valfromcurr = data[startByteOffset + index]
211                             & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
212                     valfromnext = data[startByteOffset + index + 1]
213                             & getMSBMask(extranumBits - (NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits));
214                     bytes[index] = (byte) (valfromcurr << extraOffsetBits
215                             | valfromnext >> NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
216                 }
217
218             }
219         }
220         // Aligns the bits to LSB
221         return shiftBitsToLSB(bytes, numBits);
222     }
223
224     /**
225      * Store a byte in {@code data}, starting at {@code startOffset} (in bits from MSB).
226      *
227      * @param data
228      *            to set the input byte
229      * @param input
230      *            byte to be inserted
231      * @param startOffset
232      *            offset of data[] to start inserting byte from
233      * @throws BufferException
234      *             when the input, startOffset and numBits are not congruent
235      *             with the data buffer size
236      */
237     static void setByte(final byte[] data, final byte input, final int startOffset)
238             throws BufferException {
239         copyBitsFromLsb(data, new byte[] { input }, startOffset, Byte.SIZE);
240     }
241
242     /**
243      * Bits are expected to be stored in the input byte array from LSB.
244      *
245      * @param data
246      *            to set the input byte
247      * @param input
248      *            bytes to be inserted
249      * @param startOffset
250      *            offset of data[] to start inserting byte from
251      * @param numBits
252      *            number of bits of input to be inserted into data[]
253      * @throws BufferException
254      *             when the startOffset and numBits parameters are not congruent
255      *             with data and input buffers' size
256      * @deprecated Use {@link #copyBitsFromLsb(byte[], byte[], int, int)} instead.
257      */
258     @Deprecated
259     public static void setBytes(final byte[] data, final byte[] input, final int startOffset, final int numBits)
260             throws BufferException {
261         copyBitsFromLsb(data, input, startOffset, numBits);
262     }
263
264     /**
265      * Copy {@code count} bits from {@code src} to {@code dest}, starting at {@code startOffset} in {@code dest}.
266      * Bits are copied from the low end of the source.
267      *
268      * @param dest The destination byte array.
269      * @param src The source byte array.
270      * @param startOffset The source offset (in bits, counted from the MSB) in the destination byte array.
271      * @param count The number of bits to copy.
272      *
273      * @throws BufferException if the destination byte array can't fit the requested number of bits at the requested
274      *     position.
275      */
276     static void copyBitsFromLsb(final byte[] dest, final byte[] src, final int startOffset, final int count)
277             throws BufferException {
278         checkExceptions(dest, startOffset, count);
279         copyBits(src, dest, count, src.length * Byte.SIZE - count, startOffset);
280     }
281
282     /**
283      * Copy {@code count} bits from {@code src} to {@code dest}, starting at {@code startOffset} in {@code dest}.
284      * Bits are copied from the low end of the source.
285      *
286      * @param dest The destination byte array.
287      * @param src The source byte array.
288      * @param startOffset The source offset (in bits, counted from the MSB) in the destination byte array.
289      * @param count The number of bits to copy.
290      *
291      * @throws BufferException if the destination byte array can't fit the requested number of bits at the requested
292      *     position.
293      */
294     static void copyBitsFromMsb(final byte[] dest, final byte[] src, final int startOffset, final int count)
295             throws BufferException {
296         checkExceptions(dest, startOffset, count);
297         copyBits(src, dest, count, 0, startOffset);
298     }
299
300     private static void copyBits(final byte[] src, final byte[] dest, final int count,
301             int srcBitIndex, int destBitIndex) {
302         int bitsRemaining = count;
303         while (bitsRemaining > 0) {
304             // How many bits can we, and do we need to, write, this time round?
305             int bitsToCopy = bitsRemaining % Byte.SIZE;
306             if (bitsToCopy == 0) {
307                 bitsToCopy = Byte.SIZE;
308             }
309             int targetByteIndex = destBitIndex / Byte.SIZE;
310             int targetBitIndexInByte = destBitIndex % Byte.SIZE;
311             if (targetBitIndexInByte > 0 && Byte.SIZE - targetBitIndexInByte < bitsToCopy) {
312                 // We can't write that many bits
313                 bitsToCopy = Byte.SIZE - targetBitIndexInByte;
314             }
315             int sourceByteIndex = srcBitIndex / Byte.SIZE;
316             int sourceBitIndexInByte = srcBitIndex % Byte.SIZE;
317             if (sourceBitIndexInByte > 0 && Byte.SIZE - sourceBitIndexInByte < bitsToCopy) {
318                 // We can't read that many bits
319                 bitsToCopy = Byte.SIZE - sourceBitIndexInByte;
320             }
321
322             // Check the indexes
323             if (sourceByteIndex >= src.length || targetByteIndex >= dest.length) {
324                 break;
325             }
326
327             if (bitsToCopy == Byte.SIZE) {
328                 // Fast path
329                 dest[targetByteIndex] = src[sourceByteIndex];
330             } else {
331                 // We need to mask and shift
332                 // Read the target *byte* and keep the bits we're not going to touch
333                 byte targetMask = 0;
334                 int sourceShift = 0;
335                 if (targetBitIndexInByte > 0) {
336                     targetMask |= getMSBMask(targetBitIndexInByte);
337                 }
338                 if (targetBitIndexInByte + bitsToCopy < Byte.SIZE) {
339                     targetMask |= getLSBMask(Byte.SIZE - (targetBitIndexInByte + bitsToCopy));
340                     // We'll need to shift left
341                     sourceShift = Byte.SIZE - (targetBitIndexInByte + bitsToCopy);
342                 }
343                 final byte target = (byte) (dest[targetByteIndex] & targetMask);
344
345                 // Read the source *byte* and keep the bits we need
346                 byte sourceMask = -1;
347                 if (sourceBitIndexInByte > 0) {
348                     sourceMask &= ~getMSBMask(sourceBitIndexInByte);
349                 }
350                 if (sourceBitIndexInByte + bitsToCopy < Byte.SIZE) {
351                     sourceMask &= ~getLSBMask(Byte.SIZE - (sourceBitIndexInByte + bitsToCopy));
352                     // We'll need to shift right
353                     sourceShift -= Byte.SIZE - (sourceBitIndexInByte + bitsToCopy);
354                 }
355                 byte source = (byte) (src[sourceByteIndex] & sourceMask);
356                 if (sourceShift < 0) {
357                     source = (byte) ((source & 0xFF) >>> -sourceShift);
358                 } else if (sourceShift > 0) {
359                     source <<= sourceShift;
360                 }
361
362                 // All good, copy
363                 dest[targetByteIndex] = (byte) (target | source);
364             }
365
366             // All done, update indexes
367             bitsRemaining -= bitsToCopy;
368             srcBitIndex += bitsToCopy;
369             destBitIndex += bitsToCopy;
370         }
371     }
372
373     /**
374      * Returns numBits 1's in the MSB position.
375      */
376     public static int getMSBMask(final int numBits) {
377         int mask = 0;
378         for (int i = 0; i < numBits; i++) {
379             mask = mask | 1 << 7 - i;
380         }
381         return mask;
382     }
383
384     /**
385      * Returns numBits 1's in the LSB position.
386      */
387     public static int getLSBMask(final int numBits) {
388         int mask = 0;
389         for (int i = 0; i < numBits; i++) {
390             mask = mask | 1 << i;
391         }
392         return mask;
393     }
394
395     /**
396      * Returns the numerical value of the byte array passed.
397      *
398      * @return long - numerical value of byte array passed
399      */
400     public static long toNumber(final byte[] array) {
401         long ret = 0;
402         for (byte anArray : array) {
403             int value = anArray;
404             if (value < 0) {
405                 value += 256;
406             }
407             ret = ret << Byte.SIZE | value;
408         }
409         return ret;
410     }
411
412     /**
413      * Returns the numerical value of the last numBits (LSB bits) of the byte array passed.
414      *
415      * @return long - numerical value of byte array passed
416      */
417     public static long toNumber(final byte[] array, final int numBits) {
418         int length = numBits / Byte.SIZE;
419         int bitsRest = numBits % Byte.SIZE;
420         int startOffset = array.length - length;
421         long ret = 0;
422
423         for (int i = Math.max(0, startOffset - 1); i < array.length; i++) {
424             int value = array[i];
425             if (i == startOffset - 1) {
426                 value &= getLSBMask(bitsRest);
427             }
428             if (value < 0) {
429                 value += 256;
430             }
431             ret = ret << Byte.SIZE | value;
432         }
433
434         return ret;
435     }
436
437     /**
438      * Accepts a number as input and returns its value in byte form in LSB
439      * aligned form example: input = 5000 [1001110001000] bytes = 19, -120
440      * [00010011] [10001000].
441      */
442     public static byte[] toByteArray(final Number input) {
443         Class<? extends Number> dataType = input.getClass();
444         short size;
445         long longValue = input.longValue();
446
447         if (dataType == Byte.class || dataType == byte.class) {
448             size = Byte.SIZE;
449         } else if (dataType == Short.class || dataType == short.class) {
450             size = Short.SIZE;
451         } else if (dataType == Integer.class || dataType == int.class) {
452             size = Integer.SIZE;
453         } else if (dataType == Long.class || dataType == long.class) {
454             size = Long.SIZE;
455         } else {
456             throw new IllegalArgumentException("Parameter must one of the following: Short/Int/Long\n");
457         }
458
459         int length = size / NetUtils.NUM_BITS_IN_A_BYTE;
460         byte[] bytes = new byte[length];
461
462         // Getting the bytes from input value
463         for (int i = 0; i < length; i++) {
464             bytes[i] = (byte) (longValue >> NetUtils.NUM_BITS_IN_A_BYTE * (length - i - 1) & BYTE_MASK);
465         }
466         return bytes;
467     }
468
469     /**
470      * Accepts a number as input and returns its value in byte form in MSB
471      * aligned form example: input = 5000 [1001110001000] bytes = -114, 64
472      * [10011100] [01000000].
473      *
474      * @param numBits
475      *            - the number of bits to be returned
476      * @return byte[]
477      *
478      */
479     public static byte[] toByteArray(final Number input, final int numBits) {
480         Class<? extends Number> dataType = input.getClass();
481         short size;
482         long longValue = input.longValue();
483
484         if (dataType == Short.class) {
485             size = Short.SIZE;
486         } else if (dataType == Integer.class) {
487             size = Integer.SIZE;
488         } else if (dataType == Long.class) {
489             size = Long.SIZE;
490         } else {
491             throw new IllegalArgumentException("Parameter must one of the following: Short/Int/Long\n");
492         }
493
494         int length = size / NetUtils.NUM_BITS_IN_A_BYTE;
495         byte[] bytes = new byte[length];
496         byte[] inputbytes = new byte[length];
497         byte[] shiftedBytes;
498
499         // Getting the bytes from input value
500         for (int i = 0; i < length; i++) {
501             bytes[i] = (byte) (longValue >> NetUtils.NUM_BITS_IN_A_BYTE * (length - i - 1) & BYTE_MASK);
502         }
503
504         if (bytes[0] == 0 && dataType == Long.class || bytes[0] == 0 && dataType == Integer.class) {
505             int index;
506             for (index = 0; index < length; ++index) {
507                 if (bytes[index] != 0) {
508                     bytes[0] = bytes[index];
509                     break;
510                 }
511             }
512             System.arraycopy(bytes, index, inputbytes, 0, length - index);
513             Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
514         } else {
515             System.arraycopy(bytes, 0, inputbytes, 0, length);
516         }
517
518         shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
519
520         return shiftedBytes;
521     }
522
523     /**
524      * Takes an LSB aligned byte array and returned the LSB numBits in a MSB
525      * aligned byte array.
526      *
527      * <p>
528      * It aligns the last numBits bits to the head of the byte array following
529      * them with numBits % 8 zero bits.
530      *
531      * <p>
532      * Example: For inputbytes = [00000111][01110001] and numBits = 12 it
533      * returns: shiftedBytes = [01110111][00010000]
534      *
535      * @param numBits
536      *            - number of bits to be left aligned
537      * @return byte[]
538      */
539     public static byte[] shiftBitsToMSB(final byte[] inputBytes, final int numBits) {
540         int numBitstoShiftBy;
541         int leadZeroesMSB = 8;
542         int numEndRestBits;
543         int size = inputBytes.length;
544         byte[] shiftedBytes = new byte[size];
545
546         for (int i = 0; i < Byte.SIZE; i++) {
547             if ((byte) (inputBytes[0] & getMSBMask(i + 1)) != 0) {
548                 leadZeroesMSB = i;
549                 break;
550             }
551         }
552
553         if (numBits % NetUtils.NUM_BITS_IN_A_BYTE == 0) {
554             numBitstoShiftBy = 0;
555         } else {
556             numBitstoShiftBy = NetUtils.NUM_BITS_IN_A_BYTE - numBits % NetUtils.NUM_BITS_IN_A_BYTE < leadZeroesMSB
557                     ? NetUtils.NUM_BITS_IN_A_BYTE - numBits % NetUtils.NUM_BITS_IN_A_BYTE : leadZeroesMSB;
558         }
559         if (numBitstoShiftBy == 0) {
560             return inputBytes;
561         }
562
563         if (numBits < NetUtils.NUM_BITS_IN_A_BYTE) {
564             // inputbytes.length = 1 OR read less than a byte
565             shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
566         } else {
567             // # of bits to read from last byte
568             numEndRestBits = NetUtils.NUM_BITS_IN_A_BYTE
569                     - (inputBytes.length * NetUtils.NUM_BITS_IN_A_BYTE - numBits - numBitstoShiftBy);
570
571             for (int i = 0; i < size - 1; i++) {
572                 if (i + 1 == size - 1) {
573                     if (numEndRestBits > numBitstoShiftBy) {
574                         shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
575                                 | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> numEndRestBits
576                                         - numBitstoShiftBy);
577                         shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1]
578                                 & getLSBMask(numEndRestBits - numBitstoShiftBy)) << numBitstoShiftBy);
579                     } else {
580                         shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
581                                 | (inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> NetUtils.NUM_BITS_IN_A_BYTE
582                                         - numEndRestBits);
583                     }
584                 }
585                 shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
586                         | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> NetUtils.NUM_BITS_IN_A_BYTE
587                                 - numBitstoShiftBy);
588             }
589
590         }
591         return shiftedBytes;
592     }
593
594     /**
595      * It aligns the first numBits bits to the right end of the byte array
596      * preceding them with numBits % 8 zero bits.
597      *
598      * <p>
599      * Example: For inputbytes = [01110111][00010000] and numBits = 12 it
600      * returns: shiftedBytes = [00000111][01110001]
601      *
602      * @param inputBytes input bytes
603      * @param numBits
604      *            - number of bits to be right aligned
605      * @return byte[]
606      */
607     public static byte[] shiftBitsToLSB(final byte[] inputBytes, final int numBits) {
608         int numBytes = inputBytes.length;
609         int numBitstoShift = numBits % NetUtils.NUM_BITS_IN_A_BYTE;
610         byte[] shiftedBytes = new byte[numBytes];
611         int inputLsb;
612         int inputMsb;
613
614         if (numBitstoShift == 0) {
615             return inputBytes;
616         }
617
618         for (int i = 1; i < numBytes; i++) {
619             inputLsb = inputBytes[i - 1] & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
620             inputLsb = inputLsb < 0 ? inputLsb + 256 : inputLsb;
621             inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
622             inputMsb = inputBytes[i] < 0 ? inputBytes[i] + 256 : inputBytes[i];
623             shiftedBytes[i] = (byte) (inputLsb << numBitstoShift
624                     | inputMsb >> NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
625         }
626         inputMsb = inputBytes[0] & getMSBMask(numBitstoShift);
627         inputMsb = inputMsb < 0 ? inputMsb + 256 : inputMsb;
628         shiftedBytes[0] = (byte) (inputMsb >> NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
629         return shiftedBytes;
630     }
631
632     /**
633      * Checks for overflow and underflow exceptions.
634      *
635      * @throws BufferException
636      *             when the startOffset and numBits parameters are not congruent
637      *             with the data buffer's size
638      */
639     public static void checkExceptions(final byte[] data, final int startOffset, final int numBits)
640             throws BufferException {
641         int endOffsetByte;
642         int startByteOffset;
643         endOffsetByte = startOffset / NetUtils.NUM_BITS_IN_A_BYTE + numBits / NetUtils.NUM_BITS_IN_A_BYTE
644                 + (numBits % NetUtils.NUM_BITS_IN_A_BYTE != 0 ? 1
645                         : startOffset % NetUtils.NUM_BITS_IN_A_BYTE != 0 ? 1 : 0);
646         startByteOffset = startOffset / NetUtils.NUM_BITS_IN_A_BYTE;
647
648         if (data == null) {
649             throw new BufferException("data[] is null\n");
650         }
651
652         if (startOffset < 0 || startByteOffset >= data.length || endOffsetByte > data.length || numBits < 0
653                 || numBits > NetUtils.NUM_BITS_IN_A_BYTE * data.length) {
654             throw new BufferException("Illegal arguement/out of bound exception - data.length = " + data.length
655                     + " startOffset = " + startOffset + " numBits " + numBits);
656         }
657     }
658 }