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