fd0659990e58b4d0a246655f00c12d8c6a3adc40
[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      * @return byte value
41      */
42     public static byte getByte(byte[] data) {
43         if ((data.length * NetUtils.NumBitsInAByte) > Byte.SIZE) {
44             try {
45                 throw new BufferException(
46                         "Container is too small for the number of requested bits");
47             } catch (BufferException e) {
48                 logger.error("", e);
49             }
50         }
51         return (data[0]);
52     }
53
54     /**
55      * Returns the short value for the byte array passed.
56      * Size of byte array is restricted to Short.SIZE
57      * @return short value
58      */
59     public static short getShort(byte[] data) {
60         if (data.length > Short.SIZE) {
61             try {
62                 throw new BufferException(
63                         "Container is too small for the number of requested bits");
64             } catch (BufferException e) {
65                 logger.error("", e);
66             }
67         }
68         return (short) toNumber(data);
69     }
70
71     /**
72      * Returns the int value for the byte array passed.
73      * Size of byte array is restricted to Integer.SIZE
74      * @return int - the integer value of byte array
75      */
76     public static int getInt(byte[] data) {
77         if (data.length > Integer.SIZE) {
78             try {
79                 throw new BufferException(
80                         "Container is too small for the number of requested bits");
81             } catch (BufferException e) {
82                 logger.error("", e);
83             }
84         }
85         return (int) toNumber(data);
86     }
87
88     /**
89      * Returns the long value for the byte array passed.
90      * Size of byte array is restricted to Long.SIZE
91      * @return long - the integer value of byte array
92      */
93     public static long getLong(byte[] data) {
94         if (data.length > Long.SIZE) {
95             try {
96                 throw new BufferException(
97                         "Container is too small for the number of requested bits");
98             } catch (Exception e) {
99                 logger.error("", e);
100             }
101         }
102         return toNumber(data);
103     }
104
105     /**
106      * Returns the short value for the last numBits of the byte array passed.
107      * Size of numBits is restricted to Short.SIZE
108      * @return short - the short value of byte array
109      */
110     public static short getShort(byte[] data, int numBits) {
111         if (numBits > Short.SIZE) {
112             try {
113                 throw new BufferException(
114                         "Container is too small for the number of requested bits");
115             } catch (BufferException e) {
116                 logger.error("", e);
117             }
118         }
119         int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
120         byte[] bits = null;
121         try {
122             bits = BitBufferHelper.getBits(data, startOffset, numBits);
123         } catch (BufferException e) {
124             logger.error("", e);
125         }
126         return (short) toNumber(bits, numBits);
127     }
128
129     /**
130      * Returns the int value for the last numBits of the byte array passed.
131      * Size of numBits is restricted to Integer.SIZE
132      * @return int - the integer value of byte array
133      */
134     public static int getInt(byte[] data, int numBits) {
135         if (numBits > Integer.SIZE) {
136             try {
137                 throw new BufferException(
138                         "Container is too small for the number of requested bits");
139             } catch (BufferException e) {
140                 logger.error("", e);
141             }
142         }
143         int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
144         byte[] bits = null;
145         try {
146             bits = BitBufferHelper.getBits(data, startOffset, numBits);
147         } catch (BufferException e) {
148             logger.error("", e);
149         }
150         return (int) toNumber(bits, 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      * @return long - the integer value of byte array
157      */
158     public static long getLong(byte[] data, int numBits) {
159         if (numBits > Long.SIZE) {
160             try {
161                 throw new BufferException(
162                         "Container is too small for the number of requested bits");
163             } catch (BufferException e) {
164                 logger.error("", e);
165             }
166         }
167         if (numBits > data.length * NetUtils.NumBitsInAByte) {
168             try {
169                 throw new BufferException(
170                         "Trying to read more bits than contained in the data buffer");
171             } catch (BufferException e) {
172                 logger.error("", e);
173             }
174         }
175         int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
176         byte[] bits = null;
177         try {
178             bits = BitBufferHelper.getBits(data, startOffset, numBits);
179         } catch (BufferException e) {
180             logger.error("", e);
181         }
182         return toNumber(bits, numBits);
183     }
184
185     /**
186      * Reads the specified number of bits from the passed byte array
187      * starting to read from the specified offset
188      * The bits read are stored in a byte array which size is dictated
189      * by the number of bits to be stored.
190      * The bits are stored in the byte array LSB aligned.
191      *
192      * Ex.
193      * Read 7 bits at offset 10
194      * 0         9 10     16 17
195      * 0101000010 | 0000101 | 1111001010010101011
196      * will be returned as {0,0,0,0,0,1,0,1}
197      *
198      * @param startOffset - offset to start fetching bits from data from
199      * @param numBits - number of bits to be fetched from data
200      * @return byte [] - LSB aligned bits
201      *
202      * @throws BufferException
203      *             when the startOffset and numBits parameters are not congruent
204      *             with the data buffer size
205      */
206     public static byte[] getBits(byte[] data, int startOffset, int numBits)
207             throws BufferException {
208
209         int startByteOffset = 0;
210         int valfromcurr, valfromnext;
211         int extranumBits = numBits % NetUtils.NumBitsInAByte;
212         int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
213         int numBytes = (numBits % NetUtils.NumBitsInAByte != 0) ? 1 + numBits
214                 / NetUtils.NumBitsInAByte : numBits / NetUtils.NumBitsInAByte;
215         byte[] shiftedBytes = new byte[numBytes];
216         startByteOffset = startOffset / NetUtils.NumBitsInAByte;
217         byte[] bytes = new byte[numBytes];
218         if (numBits == 0) {
219             return bytes;
220         }
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) (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] & ((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 data to set the input byte
279      * @param 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      *
283      * @throws BufferException
284      *             when the input, startOffset and numBits are not congruent
285      *             with the data buffer size
286      */
287     public static void setByte(byte[] data, byte input, int startOffset,
288             int numBits) throws BufferException {
289         byte[] inputByteArray = new byte[1];
290         Arrays.fill(inputByteArray, 0, 1, input);
291         setBytes(data, inputByteArray, startOffset, numBits);
292     }
293
294     /**
295      * Bits are expected to be stored in the input byte array from LSB
296      * @param data to set the input byte
297      * @param input bytes to be inserted
298      * @param startOffset offset of data[] to start inserting byte from
299      * @param numBits number of bits of input to be inserted into data[]
300      * @throws BufferException
301      *             when the startOffset and numBits parameters are not congruent
302      *             with data and input buffers' size
303      */
304     public static void setBytes(byte[] data, byte[] input, int startOffset,
305             int numBits) throws BufferException {
306         checkExceptions(data, startOffset, numBits);
307         insertBits(data, input, startOffset, numBits);
308     }
309
310     /**
311      * Returns numBits 1's in the MSB position
312      */
313     public static int getMSBMask(int numBits) {
314         int mask = 0;
315         for (int i = 0; i < numBits; i++) {
316             mask = mask | (1 << (7 - i));
317         }
318         return mask;
319     }
320
321     /**
322      * Returns numBits 1's in the LSB position
323      */
324     public static int getLSBMask(int numBits) {
325         int mask = 0;
326         for (int i = 0; i < numBits; i++) {
327             mask = mask | (1 << i);
328         }
329         return mask;
330     }
331
332     /**
333      * Returns the numerical value of the byte array passed
334      *
335      * @return long - numerical value of byte array passed
336      */
337     static public long toNumber(byte[] array) {
338         long ret = 0;
339         long length = array.length;
340         int value = 0;
341         for (int i = 0; i < length; i++) {
342             value = array[i];
343             if (value < 0) {
344                 value += 256;
345             }
346             ret = ret
347                     | (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) of the byte
354      * array passed
355      *
356      * @return long - numerical value of byte array passed
357      */
358     static public long toNumber(byte[] array, int numBits) {
359         int length = numBits / NetUtils.NumBitsInAByte;
360         int bitsRest = numBits % NetUtils.NumBitsInAByte;
361         int startOffset = array.length - length;
362         long ret = 0;
363         int value = 0;
364
365         value = array[startOffset - 1] & getLSBMask(bitsRest);
366         value = (array[startOffset - 1] < 0) ? (array[startOffset - 1] + 256)
367                 : array[startOffset - 1];
368         ret = ret
369                 | (value << ((array.length - startOffset) * NetUtils.NumBitsInAByte));
370
371         for (int i = startOffset; i < array.length; i++) {
372             value = array[i];
373             if (value < 0) {
374                 value += 256;
375             }
376             ret = ret
377                     | (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 in LSB
385      * aligned form example: input = 5000 [1001110001000] bytes = 19, -120
386      * [00010011] [10001000]
387      */
388     public static byte[] toByteArray(Number input) {
389         Class<? extends Number> dataType = input.getClass();
390         short size = 0;
391         long longValue = input.longValue();
392
393         if (dataType == Byte.class || dataType == byte.class) {
394             size = Byte.SIZE;
395         } else if (dataType == Short.class || dataType == short.class) {
396             size = Short.SIZE;
397         } else if (dataType == Integer.class || dataType == int.class) {
398             size = Integer.SIZE;
399         } else if (dataType == Long.class || dataType == long.class) {
400             size = Long.SIZE;
401         } else {
402             throw new IllegalArgumentException(
403                     "Parameter must one of the following: Short/Int/Long\n");
404         }
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) ((longValue >> (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 in MSB
419      * aligned form example: input = 5000 [1001110001000] bytes = -114, 64
420      * [10011100] [01000000]
421      *
422      * @param numBits - the number of bits to be returned
423      * @return byte[]
424      *
425      */
426     public static byte[] toByteArray(Number input, int numBits) {
427         Class<? extends Number> dataType = input.getClass();
428         short size = 0;
429         long longValue = input.longValue();
430
431         if (dataType == Short.class) {
432             size = Short.SIZE;
433         } else if (dataType == Integer.class) {
434             size = Integer.SIZE;
435         } else if (dataType == Long.class) {
436             size = Long.SIZE;
437         } else {
438             throw new IllegalArgumentException(
439                     "Parameter must one of the following: Short/Int/Long\n");
440         }
441
442         int length = size / NetUtils.NumBitsInAByte;
443         byte bytes[] = new byte[length];
444         byte[] inputbytes = new byte[length];
445         byte shiftedBytes[];
446
447         // Getting the bytes from input value
448         for (int i = 0; i < length; i++) {
449             bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length
450                     - i - 1))) & ByteMask);
451         }
452
453         if ((bytes[0] == 0 && dataType == Long.class)
454                 || (bytes[0] == 0 && dataType == Integer.class)) {
455             int index = 0;
456             for (index = 0; index < length; ++index) {
457                 if (bytes[index] != 0) {
458                     bytes[0] = bytes[index];
459                     break;
460                 }
461             }
462             System.arraycopy(bytes, index, inputbytes, 0, length - index);
463             Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
464         } else {
465             System.arraycopy(bytes, 0, inputbytes, 0, length);
466         }
467
468         shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
469
470         return shiftedBytes;
471     }
472
473     /**
474      * Takes an LSB aligned byte array and returned the LSB numBits in a MSB
475      * aligned byte array.
476      * <p>
477      * It aligns the last numBits bits to the head of the byte array following
478      * them with numBits % 8 zero bits.
479      *
480      * Example: For inputbytes = [00000111][01110001] and numBits = 12 it
481      * returns: shiftedBytes = [01110111][00010000]
482      *
483      * @param numBits - number of bits to be left aligned
484      * @return byte[]
485      */
486     public static byte[] shiftBitsToMSB(byte[] inputBytes, int numBits) {
487         int numBitstoShiftBy = 0, leadZeroesMSB = 8, numEndRestBits = 0;
488         int size = inputBytes.length;
489         byte[] shiftedBytes = new byte[size];
490         int i;
491
492         for (i = 0; i < Byte.SIZE; i++) {
493             if (((byte) (inputBytes[0] & getMSBMask(i + 1))) != 0) {
494                 leadZeroesMSB = i;
495                 break;
496             }
497         }
498
499         if (numBits % NetUtils.NumBitsInAByte == 0) {
500             numBitstoShiftBy = 0;
501         } else {
502             numBitstoShiftBy = ((NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte)) < leadZeroesMSB) ? (NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte))
503                     : leadZeroesMSB;
504         }
505         if (numBitstoShiftBy == 0) {
506             return inputBytes;
507         }
508
509         if (numBits < NetUtils.NumBitsInAByte) {
510             // inputbytes.length = 1 OR read less than a byte
511             shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
512         } else {
513             // # of bits to read from last byte
514             numEndRestBits = NetUtils.NumBitsInAByte
515                     - (inputBytes.length * NetUtils.NumBitsInAByte - numBits - numBitstoShiftBy);
516
517             for (i = 0; i < (size - 1); i++) {
518                 if ((i + 1) == (size - 1)) {
519                     if (numEndRestBits > numBitstoShiftBy) {
520                         shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (numEndRestBits - numBitstoShiftBy)));
521                         shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1] & getLSBMask(numEndRestBits
522                                 - numBitstoShiftBy)) << numBitstoShiftBy);
523                     } else
524                         shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> (NetUtils.NumBitsInAByte - numEndRestBits)));
525                 }
526                 shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (NetUtils.NumBitsInAByte - numBitstoShiftBy));
527             }
528
529         }
530         return shiftedBytes;
531     }
532
533     /**
534      * It aligns the first numBits bits to the right end of the byte array
535      * preceding them with numBits % 8 zero bits.
536      *
537      * Example: For inputbytes = [01110111][00010000] and numBits = 12 it
538      * returns: shiftedBytes = [00000111][01110001]
539      *
540      * @param inputBytes
541      * @param numBits - number of bits to be right aligned
542      * @return byte[]
543      */
544     public static byte[] shiftBitsToLSB(byte[] inputBytes, int numBits) {
545         int numBytes = inputBytes.length;
546         int numBitstoShift = numBits % NetUtils.NumBitsInAByte;
547         byte[] shiftedBytes = new byte[numBytes];
548         int inputLsb = 0, inputMsb = 0;
549
550         if (numBitstoShift == 0) {
551             return inputBytes;
552         }
553
554         for (int i = 1; i < numBytes; i++) {
555             inputLsb = inputBytes[i - 1]
556                     & getLSBMask(NetUtils.NumBitsInAByte - numBitstoShift);
557             inputLsb = (inputLsb < 0) ? (inputLsb + 256) : inputLsb;
558             inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
559             inputMsb = (inputBytes[i] < 0) ? (inputBytes[i] + 256)
560                     : inputBytes[i];
561             shiftedBytes[i] = (byte) ((inputLsb << numBitstoShift) | (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift)));
562         }
563         inputMsb = inputBytes[0] & (getMSBMask(numBitstoShift));
564         inputMsb = (inputMsb < 0) ? (inputMsb + 256) : inputMsb;
565         shiftedBytes[0] = (byte) (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift));
566         return shiftedBytes;
567     }
568
569     /**
570      * Insert in the data buffer at position dictated by the offset the number
571      * of bits specified from the input data byte array. The input byte array
572      * has the bits stored starting from the LSB
573      */
574     public static void insertBits(byte[] data, byte[] inputdataLSB,
575             int startOffset, int numBits) {
576         byte[] inputdata = shiftBitsToMSB(inputdataLSB, numBits); // Align to
577                                                                   // MSB the
578                                                                   // passed byte
579                                                                   // array
580         int numBytes = numBits / NetUtils.NumBitsInAByte;
581         int startByteOffset = startOffset / NetUtils.NumBitsInAByte;
582         int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
583         int extranumBits = numBits % NetUtils.NumBitsInAByte;
584         int RestBits = numBits % NetUtils.NumBitsInAByte;
585         int InputMSBbits = 0, InputLSBbits = 0;
586         int i;
587
588         if (numBits == 0) {
589             return;
590         }
591
592         if (extraOffsetBits == 0) {
593             if (extranumBits == 0) {
594                 numBytes = numBits / NetUtils.NumBitsInAByte;
595                 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
596             } else {
597                 System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
598                 data[startByteOffset + numBytes] = (byte) (data[startByteOffset
599                         + numBytes] | (inputdata[numBytes] & getMSBMask(extranumBits)));
600             }
601         } else {
602             for (i = 0; i < numBytes; i++) {
603                 if (i != 0) {
604                     InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
605                 }
606                 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
607                         - extraOffsetBits)));
608                 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
609                         : InputMSBbits + 256;
610                 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
611                         | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
612                 InputMSBbits = InputLSBbits = 0;
613             }
614             if (RestBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
615                 if (numBytes != 0) {
616                     InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
617                 }
618                 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(RestBits)));
619                 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
620                         : InputMSBbits + 256;
621                 data[startByteOffset + i] = (byte) ((data[startByteOffset + i])
622                         | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
623             } else if (RestBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
624                 if (numBytes != 0) {
625                     InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
626                 }
627                 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
628                         - extraOffsetBits)));
629                 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
630                         : InputMSBbits + 256;
631                 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
632                         | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
633             } else {
634                 if (numBytes != 0) {
635                     InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
636                 }
637                 InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
638                         - extraOffsetBits)));
639                 InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
640                         : InputMSBbits + 256;
641                 data[startByteOffset + i] = (byte) (data[startByteOffset + i]
642                         | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
643
644                 InputLSBbits = (inputdata[i] & (getLSBMask(RestBits
645                         - (NetUtils.NumBitsInAByte - extraOffsetBits)) << (NetUtils.NumBitsInAByte - RestBits)));
646                 data[startByteOffset + i + 1] = (byte) (data[startByteOffset
647                         + i + 1] | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)));
648             }
649         }
650     }
651
652     /**
653      * Checks for overflow and underflow exceptions
654      * @throws BufferException when the startOffset and numBits parameters
655      *                    are not congruent with the data buffer's size
656      */
657     public static void checkExceptions(byte[] data, int startOffset, int numBits)
658             throws BufferException {
659         int endOffsetByte;
660         int startByteOffset;
661         endOffsetByte = startOffset
662                 / NetUtils.NumBitsInAByte
663                 + numBits
664                 / NetUtils.NumBitsInAByte
665                 + ((numBits % NetUtils.NumBitsInAByte != 0) ? 1 : ((startOffset
666                         % NetUtils.NumBitsInAByte != 0) ? 1 : 0));
667         startByteOffset = startOffset / NetUtils.NumBitsInAByte;
668
669         if (data == null) {
670             throw new BufferException("data[] is null\n");
671         }
672
673         if ((startOffset < 0) || (startByteOffset >= data.length)
674                 || (endOffsetByte > data.length) || (numBits < 0)
675                 || (numBits > NetUtils.NumBitsInAByte * data.length)) {
676             throw new BufferException(
677                     "Illegal arguement/out of bound exception - data.length = "
678                             + data.length + " startOffset = " + startOffset
679                             + " numBits " + numBits);
680         }
681     }
682 }