1 /*******************************************************************************.
2 * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
9 * Contributors: Matthew Khouzam - Initial Design and implementation
10 * Contributors: Francis Giraldeau - Initial API and implementation
11 * Contributors: Philippe Proulx - Some refinement and optimization
12 *******************************************************************************/
14 package org
.eclipse
.linuxtools
.internal
.ctf
.core
.event
.io
;
16 import java
.nio
.BufferOverflowException
;
17 import java
.nio
.ByteBuffer
;
18 import java
.nio
.ByteOrder
;
21 * <b><u>BitBuffer</u></b>
23 * A bitwise buffer capable of accessing fields with bit offsets.
25 public class BitBuffer
{
27 // ------------------------------------------------------------------------
29 // ------------------------------------------------------------------------
31 /* default bit width */
32 /** 8 bits to a char */
33 public static final int BIT_CHAR
= 8;
34 /** 16 bits to a short */
35 public static final int BIT_SHORT
= 16;
36 /** 32 bits to an int */
37 public static final int BIT_INT
= 32;
38 /** 32 bits to a float */
39 public static final int BIT_FLOAT
= 32;
40 /** 64 bits to a long */
41 public static final int BIT_LONG
= 64;
43 // ------------------------------------------------------------------------
45 // ------------------------------------------------------------------------
47 private ByteBuffer buf
;
49 private ByteOrder byteOrder
;
51 // ------------------------------------------------------------------------
53 // ------------------------------------------------------------------------
55 * Default constructor, makes a bigendian buffer
58 this(null, ByteOrder
.BIG_ENDIAN
);
62 * Constructor, makes a bigendian buffer
65 * the bytebuffer to read
67 public BitBuffer(ByteBuffer buf
) {
68 this(buf
, ByteOrder
.BIG_ENDIAN
);
72 * Constructor that is fully parametrisable
77 * the byte order (big endian, little endian, network?)
79 public BitBuffer(ByteBuffer buf
, ByteOrder order
) {
85 // ------------------------------------------------------------------------
86 // 'Get' operations on buffer
87 // ------------------------------------------------------------------------
90 * Relative <i>get</i> method for reading 32-bit integer.
92 * Reads next four bytes from the current bit position according to current
95 * @return The int value read from the buffer
98 int val
= getInt(BIT_INT
, true);
103 * Relative <i>get</i> method for reading integer of <i>length</i> bits.
105 * Reads <i>length</i> bits starting at the current position. The result is
106 * signed extended if <i>signed</i> is true. The current position is
107 * increased of <i>length</i> bits.
110 * The length in bits of this integer
112 * The sign extended flag
113 * @return The int value read from the buffer
115 public int getInt(int length
, boolean signed
) {
117 if (!canRead(length
)) {
118 throw new BufferOverflowException();
123 boolean gotIt
= false;
125 // Fall back to fast ByteBuffer reader if we want to read byte-aligned bytes
126 if (this.pos
% BitBuffer
.BIT_CHAR
== 0) {
128 case BitBuffer
.BIT_CHAR
:
131 val
= this.buf
.get(this.pos
/ 8);
133 val
= (this.buf
.get(this.pos
/ 8)) & 0xff;
138 case BitBuffer
.BIT_SHORT
:
141 val
= this.buf
.getShort(this.pos
/ 8);
143 short a
= this.buf
.getShort(this.pos
/ 8);
149 case BitBuffer
.BIT_INT
:
151 val
= this.buf
.getInt(this.pos
/ 8);
160 // Nothing read yet: use longer methods
161 if (this.byteOrder
== ByteOrder
.LITTLE_ENDIAN
) {
162 val
= getIntLE(this.pos
, length
, signed
);
164 val
= getIntBE(this.pos
, length
, signed
);
172 private int getIntBE(int index
, int length
, boolean signed
) {
173 assert ((length
> 0) && (length
<= BIT_INT
));
174 int end
= index
+ length
;
175 int startByte
= index
/ BIT_CHAR
;
176 int endByte
= (end
+ (BIT_CHAR
- 1)) / BIT_CHAR
;
177 int currByte
, lshift
, cshift
, mask
, cmask
, cache
;
180 currByte
= startByte
;
181 cache
= this.buf
.get(currByte
) & 0xFF;
182 boolean isNeg
= (cache
& (1 << (BIT_CHAR
- (index
% BIT_CHAR
) - 1))) != 0;
183 if (signed
&& isNeg
) {
186 if (startByte
== (endByte
- 1)) {
187 cmask
= cache
>>> ((BIT_CHAR
- (end
% BIT_CHAR
)) % BIT_CHAR
);
188 if (((length
) % BIT_CHAR
) > 0) {
189 mask
= ~
((~
0) << length
);
196 cshift
= index
% BIT_CHAR
;
198 mask
= ~
((~
0) << (BIT_CHAR
- cshift
));
199 cmask
= cache
& mask
;
200 lshift
= BIT_CHAR
- cshift
;
206 for (; currByte
< (endByte
- 1); currByte
++) {
208 value
|= this.buf
.get(currByte
) & 0xFF;
210 lshift
= end
% BIT_CHAR
;
212 mask
= ~
((~
0) << lshift
);
213 cmask
= this.buf
.get(currByte
) & 0xFF;
214 cmask
>>>= BIT_CHAR
- lshift
;
220 value
|= this.buf
.get(currByte
) & 0xFF;
225 private int getIntLE(int index
, int length
, boolean signed
) {
226 assert ((length
> 0) && (length
<= BIT_INT
));
227 int end
= index
+ length
;
228 int startByte
= index
/ BIT_CHAR
;
229 int endByte
= (end
+ (BIT_CHAR
- 1)) / BIT_CHAR
;
230 int currByte
, lshift
, cshift
, mask
, cmask
, cache
, mod
;
233 currByte
= endByte
- 1;
234 cache
= buf
.get(currByte
) & 0xFF;
235 mod
= end
% BIT_CHAR
;
236 lshift
= (mod
> 0) ? mod
: BIT_CHAR
;
237 boolean isNeg
= (cache
& (1 << (lshift
- 1))) != 0;
238 if (signed
&& isNeg
) {
241 if (startByte
== (endByte
- 1)) {
242 cmask
= cache
>>> (index
% BIT_CHAR
);
243 if (((length
) % BIT_CHAR
) > 0) {
244 mask
= ~
((~
0) << length
);
251 cshift
= end
% BIT_CHAR
;
253 mask
= ~
((~
0) << cshift
);
254 cmask
= cache
& mask
;
260 for (; currByte
>= (startByte
+ 1); currByte
--) {
262 value
|= buf
.get(currByte
) & 0xFF;
264 lshift
= index
% BIT_CHAR
;
266 mask
= ~
((~
0) << (BIT_CHAR
- lshift
));
267 cmask
= buf
.get(currByte
) & 0xFF;
270 value
<<= (BIT_CHAR
- lshift
);
274 value
|= buf
.get(currByte
) & 0xFF;
279 // ------------------------------------------------------------------------
280 // 'Put' operations on buffer
281 // ------------------------------------------------------------------------
284 * Relative <i>put</i> method to write signed 32-bit integer.
286 * Write four bytes starting from current bit position in the buffer
287 * according to the current byte order. The current position is increased of
288 * <i>length</i> bits.
291 * The int value to write
293 public void putInt(int value
) {
294 putInt(BIT_INT
, value
);
298 * Relative <i>put</i> method to write <i>length</i> bits integer.
300 * Writes <i>length</i> lower-order bits from the provided <i>value</i>,
301 * starting from current bit position in the buffer. Sequential bytes are
302 * written according to the current byte order. The sign bit is carried to
303 * the MSB if signed is true. The sign bit is included in <i>length</i>. The
304 * current position is increased of <i>length</i>.
307 * The number of bits to write
311 public void putInt(int length
, int value
) {
312 final int curPos
= this.pos
;
314 if (!canRead(length
)) {
315 throw new BufferOverflowException();
320 if (this.byteOrder
== ByteOrder
.LITTLE_ENDIAN
) {
321 putIntLE(curPos
, length
, value
);
323 putIntBE(curPos
, length
, value
);
328 private void putIntBE(int index
, int length
, int value
) {
329 assert ((length
> 0) && (length
<= BIT_INT
));
330 int end
= index
+ length
;
331 int startByte
= index
/ BIT_CHAR
;
332 int endByte
= (end
+ (BIT_CHAR
- 1)) / BIT_CHAR
;
333 int currByte
, lshift
, cshift
, mask
, cmask
;
334 int correctedValue
= value
;
337 * mask v high bits. Works for unsigned and two complement signed
338 * numbers which value do not overflow on length bits.
341 if (length
< BIT_INT
) {
342 correctedValue
&= ~
(~
0 << length
);
346 if (startByte
== (endByte
- 1)) {
347 lshift
= (BIT_CHAR
- (end
% BIT_CHAR
)) % BIT_CHAR
;
348 mask
= ~
((~
0) << lshift
);
349 if ((index
% BIT_CHAR
) > 0) {
350 mask
|= (~
(0)) << (BIT_CHAR
- (index
% BIT_CHAR
));
352 cmask
= correctedValue
<< lshift
;
354 * low bits are cleared because of lshift and high bits are already
358 int b
= this.buf
.get(startByte
) & 0xFF;
359 this.buf
.put(startByte
, (byte) ((b
& mask
) | cmask
));
363 /* head byte contains MSB */
364 currByte
= endByte
- 1;
365 cshift
= end
% BIT_CHAR
;
367 lshift
= BIT_CHAR
- cshift
;
368 mask
= ~
((~
0) << lshift
);
369 cmask
= correctedValue
<< lshift
;
371 int b
= this.buf
.get(currByte
) & 0xFF;
372 this.buf
.put(currByte
, (byte) ((b
& mask
) | cmask
));
373 correctedValue
>>>= cshift
;
379 for (; currByte
>= (startByte
+ 1); currByte
--) {
380 this.buf
.put(currByte
, (byte) correctedValue
);
381 correctedValue
>>>= BIT_CHAR
;
383 /* end byte contains LSB */
384 if ((index
% BIT_CHAR
) > 0) {
385 mask
= (~
0) << (BIT_CHAR
- (index
% BIT_CHAR
));
386 cmask
= correctedValue
& ~mask
;
387 int b
= this.buf
.get(currByte
) & 0xFF;
388 this.buf
.put(currByte
, (byte) ((b
& mask
) | cmask
));
390 this.buf
.put(currByte
, (byte) correctedValue
);
394 private void putIntLE(int index
, int length
, int value
) {
395 assert ((length
> 0) && (length
<= BIT_INT
));
396 int end
= index
+ length
;
397 int startByte
= index
/ BIT_CHAR
;
398 int endByte
= (end
+ (BIT_CHAR
- 1)) / BIT_CHAR
;
399 int currByte
, lshift
, cshift
, mask
, cmask
;
400 int correctedValue
= value
;
403 * mask v high bits. Works for unsigned and two complement signed
404 * numbers which value do not overflow on length bits.
407 if (length
< BIT_INT
) {
408 correctedValue
&= ~
(~
0 << length
);
412 if (startByte
== (endByte
- 1)) {
413 lshift
= index
% BIT_CHAR
;
414 mask
= ~
((~
0) << lshift
);
415 if ((end
% BIT_CHAR
) > 0) {
416 mask
|= (~
(0)) << (end
% BIT_CHAR
);
418 cmask
= correctedValue
<< lshift
;
420 * low bits are cleared because of lshift and high bits are already
424 int b
= this.buf
.get(startByte
) & 0xFF;
425 this.buf
.put(startByte
, (byte) ((b
& mask
) | cmask
));
430 currByte
= startByte
;
431 cshift
= index
% BIT_CHAR
;
433 mask
= ~
((~
0) << cshift
);
434 cmask
= correctedValue
<< cshift
;
436 int b
= this.buf
.get(currByte
) & 0xFF;
437 this.buf
.put(currByte
, (byte) ((b
& mask
) | cmask
));
438 correctedValue
>>>= BIT_CHAR
- cshift
;
439 // index += BIT_CHAR - cshift;
444 for (; currByte
< (endByte
- 1); currByte
++) {
445 this.buf
.put(currByte
, (byte) correctedValue
);
446 correctedValue
>>>= BIT_CHAR
;
449 if ((end
% BIT_CHAR
) > 0) {
450 mask
= (~
0) << (end
% BIT_CHAR
);
451 cmask
= correctedValue
& ~mask
;
452 int b
= this.buf
.get(currByte
) & 0xFF;
453 this.buf
.put(currByte
, (byte) ((b
& mask
) | cmask
));
455 this.buf
.put(currByte
, (byte) correctedValue
);
459 // ------------------------------------------------------------------------
460 // Buffer attributes handling
461 // ------------------------------------------------------------------------
464 * Can this buffer be read for thus amount of bits?
467 * the length in bits to read
468 * @return does the buffer have enough room to read the next "length"
470 public boolean canRead(int length
) {
471 if (this.buf
== null) {
475 if ((this.pos
+ length
) > (this.buf
.capacity() * BIT_CHAR
)) {
482 * Sets the order of the buffer.
485 * The order of the buffer.
487 public void setByteOrder(ByteOrder order
) {
488 this.byteOrder
= order
;
489 if (this.buf
!= null) {
490 this.buf
.order(order
);
495 * Sets the order of the buffer.
497 * @return The order of the buffer.
499 public ByteOrder
getByteOrder() {
500 return this.byteOrder
;
504 * Sets the position in the buffer.
507 * The new position of the buffer.
509 public void position(int newPosition
) {
510 this.pos
= newPosition
;
515 * Sets the position in the buffer.
517 * @return order The position of the buffer.
519 public int position() {
524 * Sets the byte buffer
529 public void setByteBuffer(ByteBuffer buf
) {
532 this.buf
.order(this.byteOrder
);
538 * Gets the byte buffer
540 * @return The byte buffer
542 public ByteBuffer
getByteBuffer() {
547 * resets the bitbuffer.
549 public void clear() {
552 if (this.buf
== null) {
This page took 0.043124 seconds and 6 git commands to generate.