OPNFLWPLUG-1071 : Removal of javax.annotation.Nonnnull and replacement of javax.annot...
[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     @NonNull
167     public static byte[] getBits(final byte[] data, final int startOffset, final int numBits) 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(byte[] src, byte[] dest, int count, int srcBitIndex, int destBitIndex) {
301         int bitsRemaining = count;
302         while (bitsRemaining > 0) {
303             // How many bits can we, and do we need to, write, this time round?
304             int bitsToCopy = bitsRemaining % Byte.SIZE;
305             if (bitsToCopy == 0) {
306                 bitsToCopy = Byte.SIZE;
307             }
308             int targetByteIndex = destBitIndex / Byte.SIZE;
309             int targetBitIndexInByte = destBitIndex % Byte.SIZE;
310             if (targetBitIndexInByte > 0 && (Byte.SIZE - targetBitIndexInByte) < bitsToCopy) {
311                 // We can't write that many bits
312                 bitsToCopy = Byte.SIZE - targetBitIndexInByte;
313             }
314             int sourceByteIndex = srcBitIndex / Byte.SIZE;
315             int sourceBitIndexInByte = srcBitIndex % Byte.SIZE;
316             if (sourceBitIndexInByte > 0 && (Byte.SIZE - sourceBitIndexInByte) < bitsToCopy) {
317                 // We can't read that many bits
318                 bitsToCopy = Byte.SIZE - sourceBitIndexInByte;
319             }
320
321             // Check the indexes
322             if (sourceByteIndex >= src.length || targetByteIndex >= dest.length) {
323                 break;
324             }
325
326             if (bitsToCopy == Byte.SIZE) {
327                 // Fast path
328                 dest[targetByteIndex] = src[sourceByteIndex];
329             } else {
330                 // We need to mask and shift
331                 // Read the target *byte* and keep the bits we're not going to touch
332                 byte targetMask = 0;
333                 int sourceShift = 0;
334                 if (targetBitIndexInByte > 0) {
335                     targetMask |= getMSBMask(targetBitIndexInByte);
336                 }
337                 if (targetBitIndexInByte + bitsToCopy < Byte.SIZE) {
338                     targetMask |= getLSBMask(Byte.SIZE - (targetBitIndexInByte + bitsToCopy));
339                     // We'll need to shift left
340                     sourceShift = Byte.SIZE - (targetBitIndexInByte + bitsToCopy);
341                 }
342                 final byte target = (byte) (dest[targetByteIndex] & targetMask);
343
344                 // Read the source *byte* and keep the bits we need
345                 byte sourceMask = -1;
346                 if (sourceBitIndexInByte > 0) {
347                     sourceMask &= ~getMSBMask(sourceBitIndexInByte);
348                 }
349                 if (sourceBitIndexInByte + bitsToCopy < Byte.SIZE) {
350                     sourceMask &= ~getLSBMask(Byte.SIZE - (sourceBitIndexInByte + bitsToCopy));
351                     // We'll need to shift right
352                     sourceShift -= Byte.SIZE - (sourceBitIndexInByte + bitsToCopy);
353                 }
354                 byte source = (byte) (src[sourceByteIndex] & sourceMask);
355                 if (sourceShift < 0) {
356                     source = (byte) ((source & 0xFF) >>> -sourceShift);
357                 } else if (sourceShift > 0) {
358                     source <<= sourceShift;
359                 }
360
361                 // All good, copy
362                 dest[targetByteIndex] = (byte) (target | source);
363             }
364
365             // All done, update indexes
366             bitsRemaining -= bitsToCopy;
367             srcBitIndex += bitsToCopy;
368             destBitIndex += bitsToCopy;
369         }
370     }
371
372     /**
373      * Returns numBits 1's in the MSB position.
374      */
375     public static int getMSBMask(final int numBits) {
376         int mask = 0;
377         for (int i = 0; i < numBits; i++) {
378             mask = mask | 1 << 7 - i;
379         }
380         return mask;
381     }
382
383     /**
384      * Returns numBits 1's in the LSB position.
385      */
386     public static int getLSBMask(final int numBits) {
387         int mask = 0;
388         for (int i = 0; i < numBits; i++) {
389             mask = mask | 1 << i;
390         }
391         return mask;
392     }
393
394     /**
395      * Returns the numerical value of the byte array passed.
396      *
397      * @return long - numerical value of byte array passed
398      */
399     public static long toNumber(final byte[] array) {
400         long ret = 0;
401         for (byte anArray : array) {
402             int value = anArray;
403             if (value < 0) {
404                 value += 256;
405             }
406             ret = ret << Byte.SIZE | value;
407         }
408         return ret;
409     }
410
411     /**
412      * Returns the numerical value of the last numBits (LSB bits) of the byte array passed.
413      *
414      * @return long - numerical value of byte array passed
415      */
416     public static long toNumber(final byte[] array, final int numBits) {
417         int length = numBits / Byte.SIZE;
418         int bitsRest = numBits % Byte.SIZE;
419         int startOffset = array.length - length;
420         long ret = 0;
421
422         for (int i = Math.max(0, startOffset - 1); i < array.length; i++) {
423             int value = array[i];
424             if (i == startOffset - 1) {
425                 value &= getLSBMask(bitsRest);
426             }
427             if (value < 0) {
428                 value += 256;
429             }
430             ret = ret << Byte.SIZE | value;
431         }
432
433         return ret;
434     }
435
436     /**
437      * Accepts a number as input and returns its value in byte form in LSB
438      * aligned form example: input = 5000 [1001110001000] bytes = 19, -120
439      * [00010011] [10001000].
440      */
441     public static byte[] toByteArray(final Number input) {
442         Class<? extends Number> dataType = input.getClass();
443         short size;
444         long longValue = input.longValue();
445
446         if (dataType == Byte.class || dataType == byte.class) {
447             size = Byte.SIZE;
448         } else if (dataType == Short.class || dataType == short.class) {
449             size = Short.SIZE;
450         } else if (dataType == Integer.class || dataType == int.class) {
451             size = Integer.SIZE;
452         } else if (dataType == Long.class || dataType == long.class) {
453             size = Long.SIZE;
454         } else {
455             throw new IllegalArgumentException("Parameter must one of the following: Short/Int/Long\n");
456         }
457
458         int length = size / NetUtils.NUM_BITS_IN_A_BYTE;
459         byte[] bytes = new byte[length];
460
461         // Getting the bytes from input value
462         for (int i = 0; i < length; i++) {
463             bytes[i] = (byte) (longValue >> NetUtils.NUM_BITS_IN_A_BYTE * (length - i - 1) & BYTE_MASK);
464         }
465         return bytes;
466     }
467
468     /**
469      * Accepts a number as input and returns its value in byte form in MSB
470      * aligned form example: input = 5000 [1001110001000] bytes = -114, 64
471      * [10011100] [01000000].
472      *
473      * @param numBits
474      *            - the number of bits to be returned
475      * @return byte[]
476      *
477      */
478     public static byte[] toByteArray(final Number input, final int numBits) {
479         Class<? extends Number> dataType = input.getClass();
480         short size;
481         long longValue = input.longValue();
482
483         if (dataType == Short.class) {
484             size = Short.SIZE;
485         } else if (dataType == Integer.class) {
486             size = Integer.SIZE;
487         } else if (dataType == Long.class) {
488             size = Long.SIZE;
489         } else {
490             throw new IllegalArgumentException("Parameter must one of the following: Short/Int/Long\n");
491         }
492
493         int length = size / NetUtils.NUM_BITS_IN_A_BYTE;
494         byte[] bytes = new byte[length];
495         byte[] inputbytes = new byte[length];
496         byte[] shiftedBytes;
497
498         // Getting the bytes from input value
499         for (int i = 0; i < length; i++) {
500             bytes[i] = (byte) (longValue >> NetUtils.NUM_BITS_IN_A_BYTE * (length - i - 1) & BYTE_MASK);
501         }
502
503         if (bytes[0] == 0 && dataType == Long.class || bytes[0] == 0 && dataType == Integer.class) {
504             int index;
505             for (index = 0; index < length; ++index) {
506                 if (bytes[index] != 0) {
507                     bytes[0] = bytes[index];
508                     break;
509                 }
510             }
511             System.arraycopy(bytes, index, inputbytes, 0, length - index);
512             Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
513         } else {
514             System.arraycopy(bytes, 0, inputbytes, 0, length);
515         }
516
517         shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
518
519         return shiftedBytes;
520     }
521
522     /**
523      * Takes an LSB aligned byte array and returned the LSB numBits in a MSB
524      * aligned byte array.
525      *
526      * <p>
527      * It aligns the last numBits bits to the head of the byte array following
528      * them with numBits % 8 zero bits.
529      *
530      * <p>
531      * Example: For inputbytes = [00000111][01110001] and numBits = 12 it
532      * returns: shiftedBytes = [01110111][00010000]
533      *
534      * @param numBits
535      *            - number of bits to be left aligned
536      * @return byte[]
537      */
538     public static byte[] shiftBitsToMSB(final byte[] inputBytes, final int numBits) {
539         int numBitstoShiftBy;
540         int leadZeroesMSB = 8;
541         int numEndRestBits;
542         int size = inputBytes.length;
543         byte[] shiftedBytes = new byte[size];
544
545         for (int i = 0; i < Byte.SIZE; i++) {
546             if ((byte) (inputBytes[0] & getMSBMask(i + 1)) != 0) {
547                 leadZeroesMSB = i;
548                 break;
549             }
550         }
551
552         if (numBits % NetUtils.NUM_BITS_IN_A_BYTE == 0) {
553             numBitstoShiftBy = 0;
554         } else {
555             numBitstoShiftBy = NetUtils.NUM_BITS_IN_A_BYTE - numBits % NetUtils.NUM_BITS_IN_A_BYTE < leadZeroesMSB
556                     ? NetUtils.NUM_BITS_IN_A_BYTE - numBits % NetUtils.NUM_BITS_IN_A_BYTE : leadZeroesMSB;
557         }
558         if (numBitstoShiftBy == 0) {
559             return inputBytes;
560         }
561
562         if (numBits < NetUtils.NUM_BITS_IN_A_BYTE) {
563             // inputbytes.length = 1 OR read less than a byte
564             shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
565         } else {
566             // # of bits to read from last byte
567             numEndRestBits = NetUtils.NUM_BITS_IN_A_BYTE
568                     - (inputBytes.length * NetUtils.NUM_BITS_IN_A_BYTE - numBits - numBitstoShiftBy);
569
570             for (int i = 0; i < size - 1; i++) {
571                 if (i + 1 == size - 1) {
572                     if (numEndRestBits > numBitstoShiftBy) {
573                         shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
574                                 | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> numEndRestBits
575                                         - numBitstoShiftBy);
576                         shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1]
577                                 & getLSBMask(numEndRestBits - numBitstoShiftBy)) << numBitstoShiftBy);
578                     } else {
579                         shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
580                                 | (inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> NetUtils.NUM_BITS_IN_A_BYTE
581                                         - numEndRestBits);
582                     }
583                 }
584                 shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
585                         | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> NetUtils.NUM_BITS_IN_A_BYTE
586                                 - numBitstoShiftBy);
587             }
588
589         }
590         return shiftedBytes;
591     }
592
593     /**
594      * It aligns the first numBits bits to the right end of the byte array
595      * preceding them with numBits % 8 zero bits.
596      *
597      * <p>
598      * Example: For inputbytes = [01110111][00010000] and numBits = 12 it
599      * returns: shiftedBytes = [00000111][01110001]
600      *
601      * @param inputBytes input bytes
602      * @param numBits
603      *            - number of bits to be right aligned
604      * @return byte[]
605      */
606     public static byte[] shiftBitsToLSB(final byte[] inputBytes, final int numBits) {
607         int numBytes = inputBytes.length;
608         int numBitstoShift = numBits % NetUtils.NUM_BITS_IN_A_BYTE;
609         byte[] shiftedBytes = new byte[numBytes];
610         int inputLsb;
611         int inputMsb;
612
613         if (numBitstoShift == 0) {
614             return inputBytes;
615         }
616
617         for (int i = 1; i < numBytes; i++) {
618             inputLsb = inputBytes[i - 1] & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
619             inputLsb = inputLsb < 0 ? inputLsb + 256 : inputLsb;
620             inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
621             inputMsb = inputBytes[i] < 0 ? inputBytes[i] + 256 : inputBytes[i];
622             shiftedBytes[i] = (byte) (inputLsb << numBitstoShift
623                     | inputMsb >> NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
624         }
625         inputMsb = inputBytes[0] & getMSBMask(numBitstoShift);
626         inputMsb = inputMsb < 0 ? inputMsb + 256 : inputMsb;
627         shiftedBytes[0] = (byte) (inputMsb >> NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
628         return shiftedBytes;
629     }
630
631     /**
632      * Checks for overflow and underflow exceptions.
633      *
634      * @throws BufferException
635      *             when the startOffset and numBits parameters are not congruent
636      *             with the data buffer's size
637      */
638     public static void checkExceptions(final byte[] data, final int startOffset, final int numBits)
639             throws BufferException {
640         int endOffsetByte;
641         int startByteOffset;
642         endOffsetByte = startOffset / NetUtils.NUM_BITS_IN_A_BYTE + numBits / NetUtils.NUM_BITS_IN_A_BYTE
643                 + (numBits % NetUtils.NUM_BITS_IN_A_BYTE != 0 ? 1
644                         : startOffset % NetUtils.NUM_BITS_IN_A_BYTE != 0 ? 1 : 0);
645         startByteOffset = startOffset / NetUtils.NUM_BITS_IN_A_BYTE;
646
647         if (data == null) {
648             throw new BufferException("data[] is null\n");
649         }
650
651         if (startOffset < 0 || startByteOffset >= data.length || endOffsetByte > data.length || numBits < 0
652                 || numBits > NetUtils.NUM_BITS_IN_A_BYTE * data.length) {
653             throw new BufferException("Illegal arguement/out of bound exception - data.length = " + data.length
654                     + " startOffset = " + startOffset + " numBits " + numBits);
655         }
656     }
657 }