Merge "BUG-2475: Do not issue garbage collection on when pushing configurations"
[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             }
365             ret = ret
366                     | (long) ((long) value << ((length - i - 1) * NetUtils.NumBitsInAByte));
367         }
368         return ret;
369     }
370
371     /**
372      * Returns the numerical value of the last numBits (LSB bits) of the byte
373      * array passed
374      *
375      * @param byte[] - array
376      * @param int - numBits
377      * @return long - numerical value of byte array passed
378      */
379     static public long toNumber(byte[] array, int numBits) {
380         int length = numBits / NetUtils.NumBitsInAByte;
381         int bitsRest = numBits % NetUtils.NumBitsInAByte;
382         int startOffset = array.length - length;
383         long ret = 0;
384         int value = 0;
385
386         value = array[startOffset - 1] & getLSBMask(bitsRest);
387         value = (array[startOffset - 1] < 0) ? (array[startOffset - 1] + 256)
388                 : array[startOffset - 1];
389         ret = ret
390                 | (value << ((array.length - startOffset) * NetUtils.NumBitsInAByte));
391
392         for (int i = startOffset; i < array.length; i++) {
393             value = array[i];
394             if (value < 0) {
395                 value += 256;
396             }
397             ret = ret
398                     | (long) ((long) value << ((array.length - i - 1) * NetUtils.NumBitsInAByte));
399         }
400
401         return ret;
402     }
403
404     /**
405      * Accepts a number as input and returns its value in byte form in LSB
406      * aligned form example: input = 5000 [1001110001000] bytes = 19, -120
407      * [00010011] [10001000]
408      *
409      * @param Number
410      * @return byte[]
411      *
412      */
413
414     public static byte[] toByteArray(Number input) {
415         Class<? extends Number> dataType = input.getClass();
416         short size = 0;
417         long longValue = input.longValue();
418
419         if (dataType == Byte.class || dataType == byte.class) {
420             size = Byte.SIZE;
421         } else if (dataType == Short.class || dataType == short.class) {
422             size = Short.SIZE;
423         } else if (dataType == Integer.class || dataType == int.class) {
424             size = Integer.SIZE;
425         } else if (dataType == Long.class || dataType == long.class) {
426             size = Long.SIZE;
427         } else {
428             throw new IllegalArgumentException(
429                     "Parameter must one of the following: Short/Int/Long\n");
430         }
431
432         int length = size / NetUtils.NumBitsInAByte;
433         byte bytes[] = new byte[length];
434
435         // Getting the bytes from input value
436         for (int i = 0; i < length; i++) {
437             bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length
438                     - i - 1))) & ByteMask);
439         }
440         return bytes;
441     }
442
443     /**
444      * Accepts a number as input and returns its value in byte form in MSB
445      * aligned form example: input = 5000 [1001110001000] bytes = -114, 64
446      * [10011100] [01000000]
447      *
448      * @param Number
449      *            input
450      * @param int numBits - the number of bits to be returned
451      * @return byte[]
452      *
453      */
454     public static byte[] toByteArray(Number input, int numBits) {
455         Class<? extends Number> dataType = input.getClass();
456         short size = 0;
457         long longValue = input.longValue();
458
459         if (dataType == Short.class) {
460             size = Short.SIZE;
461         } else if (dataType == Integer.class) {
462             size = Integer.SIZE;
463         } else if (dataType == Long.class) {
464             size = Long.SIZE;
465         } else {
466             throw new IllegalArgumentException(
467                     "Parameter must one of the following: Short/Int/Long\n");
468         }
469
470         int length = size / NetUtils.NumBitsInAByte;
471         byte bytes[] = new byte[length];
472         byte[] inputbytes = new byte[length];
473         byte shiftedBytes[];
474
475         // Getting the bytes from input value
476         for (int i = 0; i < length; i++) {
477             bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length
478                     - i - 1))) & ByteMask);
479         }
480
481         if ((bytes[0] == 0 && dataType == Long.class)
482                 || (bytes[0] == 0 && dataType == Integer.class)) {
483             int index = 0;
484             for (index = 0; index < length; ++index) {
485                 if (bytes[index] != 0) {
486                     bytes[0] = bytes[index];
487                     break;
488                 }
489             }
490             System.arraycopy(bytes, index, inputbytes, 0, length - index);
491             Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
492         } else {
493             System.arraycopy(bytes, 0, inputbytes, 0, length);
494         }
495
496         shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
497
498         return shiftedBytes;
499     }
500
501     /**
502      * Takes an LSB aligned byte array and returned the LSB numBits in a MSB
503      * aligned byte array
504      *
505      * @param inputbytes
506      * @param numBits
507      * @return
508      */
509     /**
510      * It aligns the last numBits bits to the head of the byte array following
511      * them with numBits % 8 zero bits.
512      *
513      * Example: For inputbytes = [00000111][01110001] and numBits = 12 it
514      * returns: shiftedBytes = [01110111][00010000]
515      *
516      * @param byte[] inputBytes
517      * @param int numBits - number of bits to be left aligned
518      * @return byte[]
519      */
520     public static byte[] shiftBitsToMSB(byte[] inputBytes, int numBits) {
521         int numBitstoShiftBy = 0, leadZeroesMSB = 8, numEndRestBits = 0;
522         int size = inputBytes.length;
523         byte[] shiftedBytes = new byte[size];
524         int i;
525
526         for (i = 0; i < Byte.SIZE; i++) {
527             if (((byte) (inputBytes[0] & getMSBMask(i + 1))) != 0) {
528                 leadZeroesMSB = i;
529                 break;
530             }
531         }
532
533         if (numBits % NetUtils.NumBitsInAByte == 0) {
534             numBitstoShiftBy = 0;
535         } else {
536             numBitstoShiftBy = ((NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte)) < leadZeroesMSB) ? (NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte))
537                     : leadZeroesMSB;
538         }
539         if (numBitstoShiftBy == 0) {
540             return inputBytes;
541         }
542
543         if (numBits < NetUtils.NumBitsInAByte) {
544             // inputbytes.length = 1 OR read less than a byte
545             shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
546         } else {
547             // # of bits to read from last byte
548             numEndRestBits = NetUtils.NumBitsInAByte
549                     - (inputBytes.length * NetUtils.NumBitsInAByte - numBits - numBitstoShiftBy);
550
551             for (i = 0; i < (size - 1); i++) {
552                 if ((i + 1) == (size - 1)) {
553                     if (numEndRestBits > numBitstoShiftBy) {
554                         shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (numEndRestBits - numBitstoShiftBy)));
555                         shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1] & getLSBMask(numEndRestBits
556                                 - numBitstoShiftBy)) << numBitstoShiftBy);
557                     } else
558                         shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> (NetUtils.NumBitsInAByte - numEndRestBits)));
559                 }
560                 shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (NetUtils.NumBitsInAByte - numBitstoShiftBy));
561             }
562
563         }
564         return shiftedBytes;
565     }
566
567     /**
568      * It aligns the first numBits bits to the right end of the byte array
569      * preceding them with numBits % 8 zero bits.
570      *
571      * Example: For inputbytes = [01110111][00010000] and numBits = 12 it
572      * returns: shiftedBytes = [00000111][01110001]
573      *
574      * @param byte[] inputBytes
575      * @param int numBits - number of bits to be right aligned
576      * @return byte[]
577      */
578     public static byte[] shiftBitsToLSB(byte[] inputBytes, int numBits) {
579         int numBytes = inputBytes.length;
580         int numBitstoShift = numBits % NetUtils.NumBitsInAByte;
581         byte[] shiftedBytes = new byte[numBytes];
582         int inputLsb = 0, inputMsb = 0;
583
584         if (numBitstoShift == 0) {
585             return inputBytes;
586         }
587
588         for (int i = 1; i < numBytes; i++) {
589             inputLsb = inputBytes[i - 1]
590                     & getLSBMask(NetUtils.NumBitsInAByte - numBitstoShift);
591             inputLsb = (inputLsb < 0) ? (inputLsb + 256) : inputLsb;
592             inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
593             inputMsb = (inputBytes[i] < 0) ? (inputBytes[i] + 256)
594                     : inputBytes[i];
595             shiftedBytes[i] = (byte) ((inputLsb << numBitstoShift) | (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift)));
596         }
597         inputMsb = inputBytes[0] & (getMSBMask(numBitstoShift));
598         inputMsb = (inputMsb < 0) ? (inputMsb + 256) : inputMsb;
599         shiftedBytes[0] = (byte) (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift));
600         return shiftedBytes;
601     }
602
603     /**
604      * Insert in the data buffer at position dictated by the offset the number
605      * of bits specified from the input data byte array. The input byte array
606      * has the bits stored starting from the LSB
607      *
608      * @param byte[] data
609      * @param byte[] inputdata
610      * @param int startOffset
611      * @param int numBits
612      */
613     public static void insertBits(byte[] data, byte[] inputdataLSB,
614             int startOffset, int numBits) {
615         byte[] inputdata = shiftBitsToMSB(inputdataLSB, numBits); // Align to
616                                                                   // MSB the
617                                                                   // passed byte
618                                                                   // array
619         int numBytes = numBits / NetUtils.NumBitsInAByte;
620         int startByteOffset = startOffset / NetUtils.NumBitsInAByte;
621         int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
622         int extranumBits = numBits % NetUtils.NumBitsInAByte;
623         int RestBits = numBits % NetUtils.NumBitsInAByte;
624         int InputMSBbits = 0, InputLSBbits = 0;
625         int i;
626
627         if (numBits == 0) {
628             return;
629         }
630
631         if (extraOffsetBits == 0) {
632             if (extranumBits == 0) {
633                 numBytes = numBits / NetUtils.NumBitsInAByte;
634                 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
635             } else {
636                 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
637                 data[startByteOffset + numBytes] = (byte) (data[startByteOffset
638                         + numBytes] | (inputdata[numBytes] & getMSBMask(extranumBits)));
639             }
640         } else {
641             for (i = 0; i < numBytes; i++) {
642                 if (i != 0) {
643                     InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
644                 }
645                 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
646                         - extraOffsetBits)));
647                 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
648                         : InputMSBbits + 256;
649                 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
650                         | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
651                 InputMSBbits = InputLSBbits = 0;
652             }
653             if (RestBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
654                 if (numBytes != 0) {
655                     InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
656                 }
657                 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(RestBits)));
658                 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
659                         : InputMSBbits + 256;
660                 data[startByteOffset + i] = (byte) ((data[startByteOffset + i])
661                         | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
662             } else if (RestBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
663                 if (numBytes != 0) {
664                     InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
665                 }
666                 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
667                         - extraOffsetBits)));
668                 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
669                         : InputMSBbits + 256;
670                 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
671                         | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
672             } else {
673                 if (numBytes != 0) {
674                     InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
675                 }
676                 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
677                         - extraOffsetBits)));
678                 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
679                         : InputMSBbits + 256;
680                 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
681                         | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
682
683                 InputLSBbits = (inputdata[i] & (getLSBMask(RestBits
684                         - (NetUtils.NumBitsInAByte - extraOffsetBits)) << (NetUtils.NumBitsInAByte - RestBits)));
685                 data[startByteOffset + i + 1] = (byte) (data[startByteOffset
686                         + i + 1] | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)));
687             }
688         }
689     }
690
691     /**
692      * Checks for overflow and underflow exceptions
693      * @param data
694      * @param startOffset
695      * @param numBits
696      * @throws PacketException when the startOffset and numBits parameters
697      *                    are not congruent with the data buffer's size
698      */
699     public static void checkExceptions(byte[] data, int startOffset, int numBits)
700             throws BufferException {
701         int endOffsetByte;
702         int startByteOffset;
703         endOffsetByte = startOffset
704                 / NetUtils.NumBitsInAByte
705                 + numBits
706                 / NetUtils.NumBitsInAByte
707                 + ((numBits % NetUtils.NumBitsInAByte != 0) ? 1 : ((startOffset
708                         % NetUtils.NumBitsInAByte != 0) ? 1 : 0));
709         startByteOffset = startOffset / NetUtils.NumBitsInAByte;
710
711         if (data == null) {
712             throw new BufferException("data[] is null\n");
713         }
714
715         if ((startOffset < 0) || (startByteOffset >= data.length)
716                 || (endOffsetByte > data.length) || (numBits < 0)
717                 || (numBits > NetUtils.NumBitsInAByte * data.length)) {
718             throw new BufferException(
719                     "Illegal arguement/out of bound exception - data.length = "
720                             + data.length + " startOffset = " + startOffset
721                             + " numBits " + numBits);
722         }
723     }
724 }