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