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