6d9ff899c7534cb44b939fc20ad91c0690514b3a
[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 javax.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     protected 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             try {
135                 throw new BufferException("Trying to read more bits than contained in the data buffer");
136             } catch (final BufferException e) {
137                 LOG.error("", e);
138             }
139         }
140         int startOffset = data.length * NetUtils.NUM_BITS_IN_A_BYTE - numBits;
141         try {
142             byte[] bits = BitBufferHelper.getBits(data, startOffset, numBits);
143             return toNumber(bits, numBits);
144         } catch (final BufferException e) {
145             LOG.error("getBits failed", e);
146         }
147         return 0;
148     }
149
150     /**
151      * Reads the specified number of bits from the passed byte array starting to
152      * read from the specified offset The bits read are stored in a byte array
153      * which size is dictated by the number of bits to be stored. The bits are
154      * stored in the byte array LSB aligned.
155      *
156      * <p>
157      * Ex. Read 7 bits at offset 10 0 9 10 16 17 0101000010 | 0000101 |
158      * 1111001010010101011 will be returned as {0,0,0,0,0,1,0,1}
159      *
160      * @param startOffset
161      *            - offset to start fetching bits from data from
162      * @param numBits
163      *            - number of bits to be fetched from data
164      * @return byte [] - LSB aligned bits
165      *
166      * @throws BufferException
167      *             when the startOffset and numBits parameters are not congruent
168      *             with the data buffer size
169      */
170     @Nonnull
171     public static byte[] getBits(final byte[] data, final int startOffset, final int numBits) throws BufferException {
172         int startByteOffset;
173         int extranumBits = numBits % NetUtils.NUM_BITS_IN_A_BYTE;
174         final int extraOffsetBits = startOffset % NetUtils.NUM_BITS_IN_A_BYTE;
175         int numBytes = numBits % NetUtils.NUM_BITS_IN_A_BYTE != 0 ? 1 + numBits / NetUtils.NUM_BITS_IN_A_BYTE
176                 : numBits / NetUtils.NUM_BITS_IN_A_BYTE;
177         startByteOffset = startOffset / NetUtils.NUM_BITS_IN_A_BYTE;
178         byte[] bytes = new byte[numBytes];
179         if (numBits == 0) {
180             return bytes;
181         }
182
183         checkExceptions(data, startOffset, numBits);
184
185         if (extraOffsetBits == 0) {
186             if (extranumBits == 0) {
187                 System.arraycopy(data, startByteOffset, bytes, 0, numBytes);
188                 return bytes;
189             } else {
190                 System.arraycopy(data, startByteOffset, bytes, 0, numBytes - 1);
191                 bytes[numBytes - 1] = (byte) (data[startByteOffset + numBytes - 1] & getMSBMask(extranumBits));
192             }
193         } else {
194             int index;
195             int valfromcurr;
196             int valfromnext;
197             for (index = 0; index < numBits / NetUtils.NUM_BITS_IN_A_BYTE; index++) {
198                 // Reading numBytes starting from offset
199                 valfromcurr = data[startByteOffset + index] & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
200                 valfromnext = data[startByteOffset + index + 1] & getMSBMask(extraOffsetBits);
201                 bytes[index] = (byte) (valfromcurr << extraOffsetBits
202                         | valfromnext >> NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
203             }
204             // Now adding the rest of the bits if any
205             if (extranumBits != 0) {
206                 if (extranumBits < NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits) {
207                     valfromnext = (byte) (data[startByteOffset + index] & getMSBMask(extranumBits) >> extraOffsetBits);
208                     bytes[index] = (byte) (valfromnext << extraOffsetBits);
209                 } else if (extranumBits == NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits) {
210                     valfromcurr = data[startByteOffset + index]
211                             & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
212                     bytes[index] = (byte) (valfromcurr << extraOffsetBits);
213                 } else {
214                     valfromcurr = data[startByteOffset + index]
215                             & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
216                     valfromnext = data[startByteOffset + index + 1]
217                             & getMSBMask(extranumBits - (NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits));
218                     bytes[index] = (byte) (valfromcurr << extraOffsetBits
219                             | valfromnext >> NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
220                 }
221
222             }
223         }
224         // Aligns the bits to LSB
225         return shiftBitsToLSB(bytes, numBits);
226     }
227
228     // Setters
229     // data: array where data will be stored
230     // input: the data that need to be stored in the data array
231     // startOffset: bit from where to start writing
232     // numBits: number of bits to read
233
234     /**
235      * Bits are expected to be stored in the input byte array from LSB.
236      *
237      * @param data
238      *            to set the input byte
239      * @param input
240      *            byte to be inserted
241      * @param startOffset
242      *            offset of data[] to start inserting byte from
243      * @param numBits
244      *            number of bits of input to be inserted into data[]
245      *
246      * @throws BufferException
247      *             when the input, startOffset and numBits are not congruent
248      *             with the data buffer size
249      */
250     public static void setByte(final byte[] data, final byte input, final int startOffset, final int numBits)
251             throws BufferException {
252         byte[] inputByteArray = new byte[1];
253         Arrays.fill(inputByteArray, 0, 1, input);
254         setBytes(data, inputByteArray, startOffset, numBits);
255     }
256
257     /**
258      * Bits are expected to be stored in the input byte array from LSB.
259      *
260      * @param data
261      *            to set the input byte
262      * @param input
263      *            bytes to be inserted
264      * @param startOffset
265      *            offset of data[] to start inserting byte from
266      * @param numBits
267      *            number of bits of input to be inserted into data[]
268      * @throws BufferException
269      *             when the startOffset and numBits parameters are not congruent
270      *             with data and input buffers' size
271      */
272     public static void setBytes(final byte[] data, final byte[] input, final int startOffset, final int numBits)
273             throws BufferException {
274         checkExceptions(data, startOffset, numBits);
275         insertBits(data, input, startOffset, numBits);
276     }
277
278     /**
279      * Returns numBits 1's in the MSB position.
280      */
281     public static int getMSBMask(final int numBits) {
282         int mask = 0;
283         for (int i = 0; i < numBits; i++) {
284             mask = mask | 1 << 7 - i;
285         }
286         return mask;
287     }
288
289     /**
290      * Returns numBits 1's in the LSB position.
291      */
292     public static int getLSBMask(final int numBits) {
293         int mask = 0;
294         for (int i = 0; i < numBits; i++) {
295             mask = mask | 1 << i;
296         }
297         return mask;
298     }
299
300     /**
301      * Returns the numerical value of the byte array passed.
302      *
303      * @return long - numerical value of byte array passed
304      */
305     public static long toNumber(final byte[] array) {
306         long ret = 0;
307         long length = array.length;
308         int value;
309         for (int i = 0; i < length; i++) {
310             value = array[i];
311             if (value < 0) {
312                 value += 256;
313             }
314             ret = ret | (long) value << (length - i - 1) * NetUtils.NUM_BITS_IN_A_BYTE;
315         }
316         return ret;
317     }
318
319     /**
320      * Returns the numerical value of the last numBits (LSB bits) of the byte array passed.
321      *
322      * @return long - numerical value of byte array passed
323      */
324     public static long toNumber(final byte[] array, final int numBits) {
325         int length = numBits / NetUtils.NUM_BITS_IN_A_BYTE;
326         int bitsRest = numBits % NetUtils.NUM_BITS_IN_A_BYTE;
327         int startOffset = array.length - length;
328         long ret = 0;
329         int value;
330
331         value = array[startOffset - 1] & getLSBMask(bitsRest);
332         value = array[startOffset - 1] < 0 ? array[startOffset - 1] + 256 : array[startOffset - 1];
333         ret = ret | value << (array.length - startOffset) * NetUtils.NUM_BITS_IN_A_BYTE;
334
335         for (int i = startOffset; i < array.length; i++) {
336             value = array[i];
337             if (value < 0) {
338                 value += 256;
339             }
340             ret = ret | (long) value << (array.length - i - 1) * NetUtils.NUM_BITS_IN_A_BYTE;
341         }
342
343         return ret;
344     }
345
346     /**
347      * Accepts a number as input and returns its value in byte form in LSB
348      * aligned form example: input = 5000 [1001110001000] bytes = 19, -120
349      * [00010011] [10001000].
350      */
351     public static byte[] toByteArray(final Number input) {
352         Class<? extends Number> dataType = input.getClass();
353         short size;
354         long longValue = input.longValue();
355
356         if (dataType == Byte.class || dataType == byte.class) {
357             size = Byte.SIZE;
358         } else if (dataType == Short.class || dataType == short.class) {
359             size = Short.SIZE;
360         } else if (dataType == Integer.class || dataType == int.class) {
361             size = Integer.SIZE;
362         } else if (dataType == Long.class || dataType == long.class) {
363             size = Long.SIZE;
364         } else {
365             throw new IllegalArgumentException("Parameter must one of the following: Short/Int/Long\n");
366         }
367
368         int length = size / NetUtils.NUM_BITS_IN_A_BYTE;
369         byte[] bytes = new byte[length];
370
371         // Getting the bytes from input value
372         for (int i = 0; i < length; i++) {
373             bytes[i] = (byte) (longValue >> NetUtils.NUM_BITS_IN_A_BYTE * (length - i - 1) & BYTE_MASK);
374         }
375         return bytes;
376     }
377
378     /**
379      * Accepts a number as input and returns its value in byte form in MSB
380      * aligned form example: input = 5000 [1001110001000] bytes = -114, 64
381      * [10011100] [01000000].
382      *
383      * @param numBits
384      *            - the number of bits to be returned
385      * @return byte[]
386      *
387      */
388     public static byte[] toByteArray(final Number input, final int numBits) {
389         Class<? extends Number> dataType = input.getClass();
390         short size;
391         long longValue = input.longValue();
392
393         if (dataType == Short.class) {
394             size = Short.SIZE;
395         } else if (dataType == Integer.class) {
396             size = Integer.SIZE;
397         } else if (dataType == Long.class) {
398             size = Long.SIZE;
399         } else {
400             throw new IllegalArgumentException("Parameter must one of the following: Short/Int/Long\n");
401         }
402
403         int length = size / NetUtils.NUM_BITS_IN_A_BYTE;
404         byte[] bytes = new byte[length];
405         byte[] inputbytes = new byte[length];
406         byte[] shiftedBytes;
407
408         // Getting the bytes from input value
409         for (int i = 0; i < length; i++) {
410             bytes[i] = (byte) (longValue >> NetUtils.NUM_BITS_IN_A_BYTE * (length - i - 1) & BYTE_MASK);
411         }
412
413         if (bytes[0] == 0 && dataType == Long.class || bytes[0] == 0 && dataType == Integer.class) {
414             int index;
415             for (index = 0; index < length; ++index) {
416                 if (bytes[index] != 0) {
417                     bytes[0] = bytes[index];
418                     break;
419                 }
420             }
421             System.arraycopy(bytes, index, inputbytes, 0, length - index);
422             Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
423         } else {
424             System.arraycopy(bytes, 0, inputbytes, 0, length);
425         }
426
427         shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
428
429         return shiftedBytes;
430     }
431
432     /**
433      * Takes an LSB aligned byte array and returned the LSB numBits in a MSB
434      * aligned byte array.
435      *
436      * <p>
437      * It aligns the last numBits bits to the head of the byte array following
438      * them with numBits % 8 zero bits.
439      *
440      * <p>
441      * Example: For inputbytes = [00000111][01110001] and numBits = 12 it
442      * returns: shiftedBytes = [01110111][00010000]
443      *
444      * @param numBits
445      *            - number of bits to be left aligned
446      * @return byte[]
447      */
448     public static byte[] shiftBitsToMSB(final byte[] inputBytes, final int numBits) {
449         int numBitstoShiftBy;
450         int leadZeroesMSB = 8;
451         int numEndRestBits;
452         int size = inputBytes.length;
453         byte[] shiftedBytes = new byte[size];
454
455         for (int i = 0; i < Byte.SIZE; i++) {
456             if ((byte) (inputBytes[0] & getMSBMask(i + 1)) != 0) {
457                 leadZeroesMSB = i;
458                 break;
459             }
460         }
461
462         if (numBits % NetUtils.NUM_BITS_IN_A_BYTE == 0) {
463             numBitstoShiftBy = 0;
464         } else {
465             numBitstoShiftBy = NetUtils.NUM_BITS_IN_A_BYTE - numBits % NetUtils.NUM_BITS_IN_A_BYTE < leadZeroesMSB
466                     ? NetUtils.NUM_BITS_IN_A_BYTE - numBits % NetUtils.NUM_BITS_IN_A_BYTE : leadZeroesMSB;
467         }
468         if (numBitstoShiftBy == 0) {
469             return inputBytes;
470         }
471
472         if (numBits < NetUtils.NUM_BITS_IN_A_BYTE) {
473             // inputbytes.length = 1 OR read less than a byte
474             shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
475         } else {
476             // # of bits to read from last byte
477             numEndRestBits = NetUtils.NUM_BITS_IN_A_BYTE
478                     - (inputBytes.length * NetUtils.NUM_BITS_IN_A_BYTE - numBits - numBitstoShiftBy);
479
480             for (int i = 0; i < size - 1; i++) {
481                 if (i + 1 == size - 1) {
482                     if (numEndRestBits > numBitstoShiftBy) {
483                         shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
484                                 | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> numEndRestBits
485                                         - numBitstoShiftBy);
486                         shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1]
487                                 & getLSBMask(numEndRestBits - numBitstoShiftBy)) << numBitstoShiftBy);
488                     } else {
489                         shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
490                                 | (inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> NetUtils.NUM_BITS_IN_A_BYTE
491                                         - numEndRestBits);
492                     }
493                 }
494                 shiftedBytes[i] = (byte) (inputBytes[i] << numBitstoShiftBy
495                         | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> NetUtils.NUM_BITS_IN_A_BYTE
496                                 - numBitstoShiftBy);
497             }
498
499         }
500         return shiftedBytes;
501     }
502
503     /**
504      * It aligns the first numBits bits to the right end of the byte array
505      * preceding them with numBits % 8 zero bits.
506      *
507      * <p>
508      * Example: For inputbytes = [01110111][00010000] and numBits = 12 it
509      * returns: shiftedBytes = [00000111][01110001]
510      *
511      * @param inputBytes input bytes
512      * @param numBits
513      *            - number of bits to be right aligned
514      * @return byte[]
515      */
516     public static byte[] shiftBitsToLSB(final byte[] inputBytes, final int numBits) {
517         int numBytes = inputBytes.length;
518         int numBitstoShift = numBits % NetUtils.NUM_BITS_IN_A_BYTE;
519         byte[] shiftedBytes = new byte[numBytes];
520         int inputLsb;
521         int inputMsb;
522
523         if (numBitstoShift == 0) {
524             return inputBytes;
525         }
526
527         for (int i = 1; i < numBytes; i++) {
528             inputLsb = inputBytes[i - 1] & getLSBMask(NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
529             inputLsb = inputLsb < 0 ? inputLsb + 256 : inputLsb;
530             inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
531             inputMsb = inputBytes[i] < 0 ? inputBytes[i] + 256 : inputBytes[i];
532             shiftedBytes[i] = (byte) (inputLsb << numBitstoShift
533                     | inputMsb >> NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
534         }
535         inputMsb = inputBytes[0] & getMSBMask(numBitstoShift);
536         inputMsb = inputMsb < 0 ? inputMsb + 256 : inputMsb;
537         shiftedBytes[0] = (byte) (inputMsb >> NetUtils.NUM_BITS_IN_A_BYTE - numBitstoShift);
538         return shiftedBytes;
539     }
540
541     /**
542      * Insert in the data buffer at position dictated by the offset the number
543      * of bits specified from the input data byte array. The input byte array
544      * has the bits stored starting from the LSB
545      */
546     public static void insertBits(final byte[] data, final byte[] inputdataLSB, final int startOffset,
547             final int numBits) {
548         byte[] inputdata = shiftBitsToMSB(inputdataLSB, numBits); // Align to
549                                                                     // MSB the
550                                                                     // passed
551                                                                     // byte
552                                                                     // array
553         int numBytes = numBits / NetUtils.NUM_BITS_IN_A_BYTE;
554         int startByteOffset = startOffset / NetUtils.NUM_BITS_IN_A_BYTE;
555         int extraOffsetBits = startOffset % NetUtils.NUM_BITS_IN_A_BYTE;
556         int extranumBits = numBits % NetUtils.NUM_BITS_IN_A_BYTE;
557         int restBits = numBits % NetUtils.NUM_BITS_IN_A_BYTE;
558         int inputMSBbits;
559         int inputLSBbits = 0;
560
561         if (numBits == 0) {
562             return;
563         }
564
565         if (extraOffsetBits == 0) {
566             if (extranumBits == 0) {
567                 numBytes = numBits / NetUtils.NUM_BITS_IN_A_BYTE;
568                 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
569             } else {
570                 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
571                 data[startByteOffset + numBytes] = (byte) (data[startByteOffset + numBytes]
572                         | inputdata[numBytes] & getMSBMask(extranumBits));
573             }
574         } else {
575             int index;
576             for (index = 0; index < numBytes; index++) {
577                 if (index != 0) {
578                     inputLSBbits = inputdata[index - 1] & getLSBMask(extraOffsetBits);
579                 }
580                 inputMSBbits = (byte) (inputdata[index] & getMSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits));
581                 inputMSBbits = inputMSBbits >= 0 ? inputMSBbits : inputMSBbits + 256;
582                 data[startByteOffset + index] = (byte) (data[startByteOffset + index]
583                         | inputLSBbits << NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits
584                         | inputMSBbits >> extraOffsetBits);
585                 inputMSBbits = inputLSBbits = 0;
586             }
587             if (restBits < NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits) {
588                 if (numBytes != 0) {
589                     inputLSBbits = inputdata[index - 1] & getLSBMask(extraOffsetBits);
590                 }
591                 inputMSBbits = (byte) (inputdata[index] & getMSBMask(restBits));
592                 inputMSBbits = inputMSBbits >= 0 ? inputMSBbits : inputMSBbits + 256;
593                 data[startByteOffset + index] = (byte) (data[startByteOffset + index]
594                         | inputLSBbits << NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits
595                         | inputMSBbits >> extraOffsetBits);
596             } else if (restBits == NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits) {
597                 if (numBytes != 0) {
598                     inputLSBbits = inputdata[index - 1] & getLSBMask(extraOffsetBits);
599                 }
600                 inputMSBbits = (byte) (inputdata[index] & getMSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits));
601                 inputMSBbits = inputMSBbits >= 0 ? inputMSBbits : inputMSBbits + 256;
602                 data[startByteOffset + index] = (byte) (data[startByteOffset + index]
603                         | inputLSBbits << NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits
604                         | inputMSBbits >> extraOffsetBits);
605             } else {
606                 if (numBytes != 0) {
607                     inputLSBbits = inputdata[index - 1] & getLSBMask(extraOffsetBits);
608                 }
609                 inputMSBbits = (byte) (inputdata[index] & getMSBMask(NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits));
610                 inputMSBbits = inputMSBbits >= 0 ? inputMSBbits : inputMSBbits + 256;
611                 data[startByteOffset + index] = (byte) (data[startByteOffset + index]
612                         | inputLSBbits << NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits
613                         | inputMSBbits >> extraOffsetBits);
614
615                 inputLSBbits = inputdata[index]
616                         & getLSBMask(restBits - (NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits))
617                         << NetUtils.NUM_BITS_IN_A_BYTE
618                                 - restBits;
619                 data[startByteOffset + index + 1] = (byte) (data[startByteOffset + index + 1]
620                         | inputLSBbits << NetUtils.NUM_BITS_IN_A_BYTE - extraOffsetBits);
621             }
622         }
623     }
624
625     /**
626      * Checks for overflow and underflow exceptions.
627      *
628      * @throws BufferException
629      *             when the startOffset and numBits parameters are not congruent
630      *             with the data buffer's size
631      */
632     public static void checkExceptions(final byte[] data, final int startOffset, final int numBits)
633             throws BufferException {
634         int endOffsetByte;
635         int startByteOffset;
636         endOffsetByte = startOffset / NetUtils.NUM_BITS_IN_A_BYTE + numBits / NetUtils.NUM_BITS_IN_A_BYTE
637                 + (numBits % NetUtils.NUM_BITS_IN_A_BYTE != 0 ? 1
638                         : startOffset % NetUtils.NUM_BITS_IN_A_BYTE != 0 ? 1 : 0);
639         startByteOffset = startOffset / NetUtils.NUM_BITS_IN_A_BYTE;
640
641         if (data == null) {
642             throw new BufferException("data[] is null\n");
643         }
644
645         if (startOffset < 0 || startByteOffset >= data.length || endOffsetByte > data.length || numBits < 0
646                 || numBits > NetUtils.NUM_BITS_IN_A_BYTE * data.length) {
647             throw new BufferException("Illegal arguement/out of bound exception - data.length = " + data.length
648                     + " startOffset = " + startOffset + " numBits " + numBits);
649         }
650     }
651 }