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