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