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
10 * Matthew Khouzam - Initial Design and implementation + overhaul
11 * Francis Giraldeau - Initial API and implementation
12 * Philippe Proulx - Some refinement and optimization
13 * Etienne Bergeron <Etienne.Bergeron@gmail.com> - fix zero size read + cleanup
14 *******************************************************************************/
16 package org
.eclipse
.linuxtools
.ctf
.core
.event
.io
;
18 import java
.nio
.ByteBuffer
;
19 import java
.nio
.ByteOrder
;
21 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFReaderException
;
24 * <b><u>BitBuffer</u></b>
26 * A bitwise buffer capable of accessing fields with bit offsets.
30 public final class BitBuffer
{
32 // ------------------------------------------------------------------------
34 // ------------------------------------------------------------------------
36 /* default bit width */
37 /** 8 bits to a char */
38 public static final int BIT_CHAR
= 8;
39 /** 16 bits to a short */
40 public static final int BIT_SHORT
= 16;
41 /** 32 bits to an int */
42 public static final int BIT_INT
= 32;
43 /** 32 bits to a float */
44 public static final int BIT_FLOAT
= 32;
45 /** 64 bits to a long */
46 public static final int BIT_LONG
= 64;
48 // ------------------------------------------------------------------------
50 // ------------------------------------------------------------------------
52 private ByteBuffer fBuffer
;
53 private long fPosition
;
54 private ByteOrder fByteOrder
;
56 // ------------------------------------------------------------------------
58 // ------------------------------------------------------------------------
60 * Default constructor, makes a big-endian buffer
63 this(null, ByteOrder
.BIG_ENDIAN
);
67 * Constructor, makes a big-endian buffer
70 * the bytebuffer to read
72 public BitBuffer(ByteBuffer buf
) {
73 this(buf
, ByteOrder
.BIG_ENDIAN
);
77 * Constructor that is fully parameterizable
82 * the byte order (big-endian, little-endian, network?)
84 public BitBuffer(ByteBuffer buf
, ByteOrder order
) {
90 private void resetPosition() {
94 // ------------------------------------------------------------------------
95 // 'Get' operations on buffer
96 // ------------------------------------------------------------------------
99 * Relative <i>get</i> method for reading 32-bit integer.
101 * Reads next four bytes from the current bit position according to current
104 * @return The int value (signed) read from the buffer
105 * @throws CTFReaderException
106 * An error occurred reading the long. This exception can be
107 * raised if the buffer tries to read out of bounds
109 public int getInt() throws CTFReaderException
{
110 return getInt(BIT_INT
, true);
114 * Relative <i>get</i> method for reading 64-bit integer.
116 * Reads next eight bytes from the current bit position according to current
119 * @return The long value (signed) read from the buffer
120 * @throws CTFReaderException
121 * An error occurred reading the long. This exception can be
122 * raised if the buffer tries to read out of bounds
124 public long getLong() throws CTFReaderException
{
125 return get(BIT_LONG
, true);
129 * Relative <i>get</i> method for reading long of <i>length</i> bits.
131 * Reads <i>length</i> bits starting at the current position. The result is
132 * signed extended if <i>signed</i> is true. The current position is
133 * increased of <i>length</i> bits.
136 * The length in bits of this integer
138 * The sign extended flag
139 * @return The long value read from the buffer
140 * @throws CTFReaderException
141 * An error occurred reading the data. If more than 64 bits at a
142 * time are read, or the buffer is read beyond its end, this
143 * exception will be raised.
145 public long get(int length
, boolean signed
) throws CTFReaderException
{
146 if (length
> BIT_LONG
) {
147 throw new CTFReaderException("Cannot read a long longer than 64 bits. Rquested: " + length
); //$NON-NLS-1$
149 if (length
> BIT_INT
) {
150 final int highShift
= length
- BIT_INT
;
152 long b
= getInt(highShift
, false);
154 /* Cast the signed-extended int into a unsigned int. */
156 b
&= (1L << highShift
) - 1L;
158 retVal
= (fByteOrder
== ByteOrder
.BIG_ENDIAN
) ?
((a
<< highShift
) | b
) : ((b
<< BIT_INT
) | a
);
161 int signExtendBits
= BIT_LONG
- length
;
162 retVal
= (retVal
<< signExtendBits
) >> signExtendBits
;
166 long retVal
= getInt(length
, signed
);
167 return (signed ? retVal
: (retVal
& 0xFFFFFFFFL
));
171 * Relative <i>get</i> method for reading integer of <i>length</i> bits.
173 * Reads <i>length</i> bits starting at the current position. The result is
174 * signed extended if <i>signed</i> is true. The current position is
175 * increased of <i>length</i> bits.
178 * The length in bits of this integer
180 * The sign extended flag
181 * @return The int value read from the buffer
182 * @throws CTFReaderException
183 * An error occurred reading the data. When the buffer is read
184 * beyond its end, this exception will be raised.
186 private int getInt(int length
, boolean signed
) throws CTFReaderException
{
188 /* Nothing to read. */
193 /* Validate that the buffer has enough bits. */
194 if (!canRead(length
)) {
195 throw new CTFReaderException("Cannot read the integer, " + //$NON-NLS-1$
196 "the buffer does not have enough remaining space. " + //$NON-NLS-1$
197 "Requested:" + length
); //$NON-NLS-1$
200 /* Get the value from the byte buffer. */
202 boolean gotIt
= false;
205 * Try a fast read when the position is byte-aligned by using
206 * java.nio.ByteBuffer's native methods
209 * A faster alignment detection as the compiler cannot guaranty that pos
210 * is always positive.
212 if ((fPosition
& (BitBuffer
.BIT_CHAR
- 1)) == 0) {
214 case BitBuffer
.BIT_CHAR
:
216 val
= fBuffer
.get((int) (fPosition
/ 8));
223 case BitBuffer
.BIT_SHORT
:
225 val
= fBuffer
.getShort((int) (fPosition
/ 8));
232 case BitBuffer
.BIT_INT
:
234 val
= fBuffer
.getInt((int) (fPosition
/ 8));
243 /* When not byte-aligned, fall-back to a general decoder. */
245 // Nothing read yet: use longer methods
246 if (fByteOrder
== ByteOrder
.LITTLE_ENDIAN
) {
247 val
= getIntLE(fPosition
, length
, signed
);
249 val
= getIntBE(fPosition
, length
, signed
);
257 private int getIntBE(long index
, int length
, boolean signed
) {
258 assert ((length
> 0) && (length
<= BIT_INT
));
259 long end
= index
+ length
;
260 int startByte
= (int) (index
/ BIT_CHAR
);
261 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
262 int currByte
, lshift
, cshift
, mask
, cmask
, cache
;
265 currByte
= startByte
;
266 cache
= fBuffer
.get(currByte
) & 0xFF;
267 boolean isNeg
= (cache
& (1 << (BIT_CHAR
- (index
% BIT_CHAR
) - 1))) != 0;
268 if (signed
&& isNeg
) {
271 if (startByte
== (endByte
- 1)) {
272 cmask
= cache
>>> ((BIT_CHAR
- (end
% BIT_CHAR
)) % BIT_CHAR
);
273 if (((length
) % BIT_CHAR
) > 0) {
274 mask
= ~
((~
0) << length
);
281 cshift
= (int) (index
% BIT_CHAR
);
283 mask
= ~
((~
0) << (BIT_CHAR
- cshift
));
284 cmask
= cache
& mask
;
285 lshift
= BIT_CHAR
- cshift
;
290 for (; currByte
< (endByte
- 1); currByte
++) {
292 value
|= fBuffer
.get(currByte
) & 0xFF;
294 lshift
= (int) (end
% BIT_CHAR
);
296 mask
= ~
((~
0) << lshift
);
297 cmask
= fBuffer
.get(currByte
) & 0xFF;
298 cmask
>>>= BIT_CHAR
- lshift
;
304 value
|= fBuffer
.get(currByte
) & 0xFF;
309 private int getIntLE(long index
, int length
, boolean signed
) {
310 assert ((length
> 0) && (length
<= BIT_INT
));
311 long end
= index
+ length
;
312 int startByte
= (int) (index
/ BIT_CHAR
);
313 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
314 int currByte
, lshift
, cshift
, mask
, cmask
, cache
, mod
;
317 currByte
= endByte
- 1;
318 cache
= fBuffer
.get(currByte
) & 0xFF;
319 mod
= (int) (end
% BIT_CHAR
);
320 lshift
= (mod
> 0) ? mod
: BIT_CHAR
;
321 boolean isNeg
= (cache
& (1 << (lshift
- 1))) != 0;
322 if (signed
&& isNeg
) {
325 if (startByte
== (endByte
- 1)) {
326 cmask
= cache
>>> (index
% BIT_CHAR
);
327 if (((length
) % BIT_CHAR
) > 0) {
328 mask
= ~
((~
0) << length
);
335 cshift
= (int) (end
% BIT_CHAR
);
337 mask
= ~
((~
0) << cshift
);
338 cmask
= cache
& mask
;
343 for (; currByte
>= (startByte
+ 1); currByte
--) {
345 value
|= fBuffer
.get(currByte
) & 0xFF;
347 lshift
= (int) (index
% BIT_CHAR
);
349 mask
= ~
((~
0) << (BIT_CHAR
- lshift
));
350 cmask
= fBuffer
.get(currByte
) & 0xFF;
353 value
<<= (BIT_CHAR
- lshift
);
357 value
|= fBuffer
.get(currByte
) & 0xFF;
362 // ------------------------------------------------------------------------
363 // 'Put' operations on buffer
364 // ------------------------------------------------------------------------
367 * Relative <i>put</i> method to write signed 32-bit integer.
369 * Write four bytes starting from current bit position in the buffer
370 * according to the current byte order. The current position is increased of
371 * <i>length</i> bits.
374 * The int value to write
375 * @throws CTFReaderException
376 * An error occurred writing the data. If the buffer is written
377 * beyond its end, this exception will be raised.
379 public void putInt(int value
) throws CTFReaderException
{
380 putInt(BIT_INT
, value
);
384 * Relative <i>put</i> method to write <i>length</i> bits integer.
386 * Writes <i>length</i> lower-order bits from the provided <i>value</i>,
387 * starting from current bit position in the buffer. Sequential bytes are
388 * written according to the current byte order. The sign bit is carried to
389 * the MSB if signed is true. The sign bit is included in <i>length</i>. The
390 * current position is increased of <i>length</i>.
393 * The number of bits to write
396 * @throws CTFReaderException
397 * An error occurred writing the data. If the buffer is written
398 * beyond its end, this exception will be raised.
400 public void putInt(int length
, int value
) throws CTFReaderException
{
401 final long curPos
= fPosition
;
403 if (!canRead(length
)) {
404 throw new CTFReaderException("Cannot write to bitbuffer, " //$NON-NLS-1$
405 + "insufficient space. Requested: " + length
); //$NON-NLS-1$
410 if (fByteOrder
== ByteOrder
.LITTLE_ENDIAN
) {
411 putIntLE(curPos
, length
, value
);
413 putIntBE(curPos
, length
, value
);
418 private void putIntBE(long index
, int length
, int value
) {
419 assert ((length
> 0) && (length
<= BIT_INT
));
420 long end
= index
+ length
;
421 int startByte
= (int) (index
/ BIT_CHAR
);
422 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
423 int currByte
, lshift
, cshift
, mask
, cmask
;
424 int correctedValue
= value
;
427 * mask v high bits. Works for unsigned and two complement signed
428 * numbers which value do not overflow on length bits.
431 if (length
< BIT_INT
) {
432 correctedValue
&= ~
(~
0 << length
);
436 if (startByte
== (endByte
- 1)) {
437 lshift
= (int) ((BIT_CHAR
- (end
% BIT_CHAR
)) % BIT_CHAR
);
438 mask
= ~
((~
0) << lshift
);
439 if ((index
% BIT_CHAR
) > 0) {
440 mask
|= (~
(0)) << (BIT_CHAR
- (index
% BIT_CHAR
));
442 cmask
= correctedValue
<< lshift
;
444 * low bits are cleared because of left-shift and high bits are
448 int b
= fBuffer
.get(startByte
) & 0xFF;
449 fBuffer
.put(startByte
, (byte) ((b
& mask
) | cmask
));
453 /* head byte contains MSB */
454 currByte
= endByte
- 1;
455 cshift
= (int) (end
% BIT_CHAR
);
457 lshift
= BIT_CHAR
- cshift
;
458 mask
= ~
((~
0) << lshift
);
459 cmask
= correctedValue
<< lshift
;
461 int b
= fBuffer
.get(currByte
) & 0xFF;
462 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
463 correctedValue
>>>= cshift
;
468 for (; currByte
>= (startByte
+ 1); currByte
--) {
469 fBuffer
.put(currByte
, (byte) correctedValue
);
470 correctedValue
>>>= BIT_CHAR
;
472 /* end byte contains LSB */
473 if ((index
% BIT_CHAR
) > 0) {
474 mask
= (~
0) << (BIT_CHAR
- (index
% BIT_CHAR
));
475 cmask
= correctedValue
& ~mask
;
476 int b
= fBuffer
.get(currByte
) & 0xFF;
477 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
479 fBuffer
.put(currByte
, (byte) correctedValue
);
483 private void putIntLE(long index
, int length
, int value
) {
484 assert ((length
> 0) && (length
<= BIT_INT
));
485 long end
= index
+ length
;
486 int startByte
= (int) (index
/ BIT_CHAR
);
487 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
488 int currByte
, lshift
, cshift
, mask
, cmask
;
489 int correctedValue
= value
;
492 * mask v high bits. Works for unsigned and two complement signed
493 * numbers which value do not overflow on length bits.
496 if (length
< BIT_INT
) {
497 correctedValue
&= ~
(~
0 << length
);
501 if (startByte
== (endByte
- 1)) {
502 lshift
= (int) (index
% BIT_CHAR
);
503 mask
= ~
((~
0) << lshift
);
504 if ((end
% BIT_CHAR
) > 0) {
505 mask
|= (~
(0)) << (end
% BIT_CHAR
);
507 cmask
= correctedValue
<< lshift
;
509 * low bits are cleared because of left-shift and high bits are
513 int b
= fBuffer
.get(startByte
) & 0xFF;
514 fBuffer
.put(startByte
, (byte) ((b
& mask
) | cmask
));
519 currByte
= startByte
;
520 cshift
= (int) (index
% BIT_CHAR
);
522 mask
= ~
((~
0) << cshift
);
523 cmask
= correctedValue
<< cshift
;
525 int b
= fBuffer
.get(currByte
) & 0xFF;
526 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
527 correctedValue
>>>= BIT_CHAR
- cshift
;
532 for (; currByte
< (endByte
- 1); currByte
++) {
533 fBuffer
.put(currByte
, (byte) correctedValue
);
534 correctedValue
>>>= BIT_CHAR
;
537 if ((end
% BIT_CHAR
) > 0) {
538 mask
= (~
0) << (end
% BIT_CHAR
);
539 cmask
= correctedValue
& ~mask
;
540 int b
= fBuffer
.get(currByte
) & 0xFF;
541 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
543 fBuffer
.put(currByte
, (byte) correctedValue
);
547 // ------------------------------------------------------------------------
548 // Buffer attributes handling
549 // ------------------------------------------------------------------------
552 * Can this buffer be read for thus amount of bits?
555 * the length in bits to read
556 * @return does the buffer have enough room to read the next "length"
558 public boolean canRead(int length
) {
559 if (fBuffer
== null) {
563 if ((fPosition
+ length
) > (((long) fBuffer
.capacity()) * BIT_CHAR
)) {
570 * Sets the order of the buffer.
573 * The order of the buffer.
575 public void setByteOrder(ByteOrder order
) {
577 if (fBuffer
!= null) {
578 fBuffer
.order(order
);
583 * Sets the order of the buffer.
585 * @return The order of the buffer.
587 public ByteOrder
getByteOrder() {
592 * Sets the position in the buffer.
595 * The new position of the buffer.
596 * @throws CTFReaderException
597 * Thrown on out of bounds exceptions
599 public void position(long newPosition
) throws CTFReaderException
{
601 if ((fBuffer
!= null) && (newPosition
/ 8) > fBuffer
.capacity()) {
602 throw new CTFReaderException("Out of bounds exception on a position move, attempting to access position: " + newPosition
); //$NON-NLS-1$
604 fPosition
= newPosition
;
609 * Sets the position in the buffer.
611 * @return order The position of the buffer.
613 public long position() {
618 * Sets the byte buffer
623 public void setByteBuffer(ByteBuffer buf
) {
626 fBuffer
.order(fByteOrder
);
632 * Gets the byte buffer
634 * @return The byte buffer
636 public ByteBuffer
getByteBuffer() {
641 * Resets the bitbuffer.
643 public void clear() {
645 if (fBuffer
== null) {
This page took 0.044559 seconds and 6 git commands to generate.