1 /*******************************************************************************.
2 * Copyright (c) 2011, 2014 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
.BufferUnderflowException
;
19 import java
.nio
.ByteBuffer
;
20 import java
.nio
.ByteOrder
;
22 import org
.eclipse
.jdt
.annotation
.NonNull
;
23 import org
.eclipse
.linuxtools
.ctf
.core
.trace
.CTFReaderException
;
26 * <b><u>BitBuffer</u></b>
28 * A bitwise buffer capable of accessing fields with bit offsets.
32 public final class BitBuffer
{
34 // ------------------------------------------------------------------------
36 // ------------------------------------------------------------------------
38 /* default bit width */
39 /** 8 bits to a char */
40 public static final int BIT_CHAR
= 8;
41 /** 16 bits to a short */
42 public static final int BIT_SHORT
= 16;
43 /** 32 bits to an int */
44 public static final int BIT_INT
= 32;
45 /** 32 bits to a float */
46 public static final int BIT_FLOAT
= 32;
47 /** 64 bits to a long */
48 public static final int BIT_LONG
= 64;
50 // ------------------------------------------------------------------------
52 // ------------------------------------------------------------------------
54 private final @NonNull ByteBuffer fBuffer
;
55 private final long fBitCapacity
;
58 * Bit-buffer's position, maximum value = Integer.MAX_VALUE * 8
60 private long fPosition
;
61 private ByteOrder fByteOrder
;
63 // ------------------------------------------------------------------------
65 // ------------------------------------------------------------------------
67 * Default constructor, makes a big-endian buffer
69 @SuppressWarnings("null")
71 this(ByteBuffer
.allocateDirect(0), ByteOrder
.BIG_ENDIAN
);
75 * Constructor, makes a big-endian buffer
78 * the bytebuffer to read
80 public BitBuffer(@NonNull ByteBuffer buf
) {
81 this(buf
, ByteOrder
.BIG_ENDIAN
);
85 * Constructor that is fully parameterizable
90 * the byte order (big-endian, little-endian, network?)
92 public BitBuffer(@NonNull ByteBuffer buf
, ByteOrder order
) {
96 fBitCapacity
= fBuffer
.capacity() * BIT_CHAR
;
99 private void resetPosition() {
103 // ------------------------------------------------------------------------
104 // 'Get' operations on buffer
105 // ------------------------------------------------------------------------
108 * Relative <i>get</i> method for reading 32-bit integer.
110 * Reads next four bytes from the current bit position according to current
113 * @return The int value (signed) read from the buffer
114 * @throws CTFReaderException
115 * An error occurred reading the long. This exception can be
116 * raised if the buffer tries to read out of bounds
118 public int getInt() throws CTFReaderException
{
119 return getInt(BIT_INT
, true);
123 * Relative <i>get</i> method for reading 64-bit integer.
125 * Reads next eight bytes from the current bit position according to current
128 * @return The long value (signed) read from the buffer
129 * @throws CTFReaderException
130 * An error occurred reading the long. This exception can be
131 * raised if the buffer tries to read out of bounds
134 public long getLong() throws CTFReaderException
{
135 return get(BIT_LONG
, true);
139 * Relative <i>get</i> method for reading long of <i>length</i> bits.
141 * Reads <i>length</i> bits starting at the current position. The result is
142 * signed extended if <i>signed</i> is true. The current position is
143 * increased of <i>length</i> bits.
146 * The length in bits of this integer
148 * The sign extended flag
149 * @return The long value read from the buffer
150 * @throws CTFReaderException
151 * An error occurred reading the data. If more than 64 bits at a
152 * time are read, or the buffer is read beyond its end, this
153 * exception will be raised.
156 public long get(int length
, boolean signed
) throws CTFReaderException
{
157 if (length
> BIT_LONG
) {
158 throw new CTFReaderException("Cannot read a long longer than 64 bits. Rquested: " + length
); //$NON-NLS-1$
160 if (length
> BIT_INT
) {
161 final int highShift
= length
- BIT_INT
;
163 long b
= getInt(highShift
, false);
165 /* Cast the signed-extended int into a unsigned int. */
167 b
&= (1L << highShift
) - 1L;
169 retVal
= (fByteOrder
== ByteOrder
.BIG_ENDIAN
) ?
((a
<< highShift
) | b
) : ((b
<< BIT_INT
) | a
);
172 int signExtendBits
= BIT_LONG
- length
;
173 retVal
= (retVal
<< signExtendBits
) >> signExtendBits
;
177 long retVal
= getInt(length
, signed
);
178 return (signed ? retVal
: (retVal
& 0xFFFFFFFFL
));
182 * Relative bulk <i>get</i> method.
185 * This method transfers <strong>bytes</strong> from this buffer into the
186 * given destination array. This method currently only supports reads
187 * aligned to 8 bytes. It is up to the developer to shift the bits in
188 * post-processing to do unaligned reads.
191 * the bytes to write to
192 * @throws BufferUnderflowException
193 * - If there are fewer than length bytes remaining in this
197 public void get(@NonNull byte[] dst
) {
198 fBuffer
.position((int) (fPosition
/ 8));
200 fPosition
+= dst
.length
* 8;
204 * Relative <i>get</i> method for reading integer of <i>length</i> bits.
206 * Reads <i>length</i> bits starting at the current position. The result is
207 * signed extended if <i>signed</i> is true. The current position is
208 * increased of <i>length</i> bits.
211 * The length in bits of this integer
213 * The sign extended flag
214 * @return The int value read from the buffer
215 * @throws CTFReaderException
216 * An error occurred reading the data. When the buffer is read
217 * beyond its end, this exception will be raised.
219 private int getInt(int length
, boolean signed
) throws CTFReaderException
{
221 /* Nothing to read. */
226 /* Validate that the buffer has enough bits. */
227 if (!canRead(length
)) {
228 throw new CTFReaderException("Cannot read the integer, " + //$NON-NLS-1$
229 "the buffer does not have enough remaining space. " + //$NON-NLS-1$
230 "Requested:" + length
); //$NON-NLS-1$
233 /* Get the value from the byte buffer. */
235 boolean gotIt
= false;
238 * Try a fast read when the position is byte-aligned by using
239 * java.nio.ByteBuffer's native methods
242 * A faster alignment detection as the compiler cannot guaranty that pos
243 * is always positive.
245 if ((fPosition
& (BitBuffer
.BIT_CHAR
- 1)) == 0) {
247 case BitBuffer
.BIT_CHAR
:
249 val
= fBuffer
.get((int) (fPosition
/ 8));
256 case BitBuffer
.BIT_SHORT
:
258 val
= fBuffer
.getShort((int) (fPosition
/ 8));
265 case BitBuffer
.BIT_INT
:
267 val
= fBuffer
.getInt((int) (fPosition
/ 8));
276 /* When not byte-aligned, fall-back to a general decoder. */
278 // Nothing read yet: use longer methods
279 if (fByteOrder
== ByteOrder
.LITTLE_ENDIAN
) {
280 val
= getIntLE(fPosition
, length
, signed
);
282 val
= getIntBE(fPosition
, length
, signed
);
290 private int getIntBE(long index
, int length
, boolean signed
) {
291 if ((length
<= 0) || (length
> BIT_INT
)) {
292 throw new IllegalArgumentException("Length must be between 1-32 bits"); //$NON-NLS-1$
294 long end
= index
+ length
;
295 int startByte
= (int) (index
/ BIT_CHAR
);
296 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
297 int currByte
, lshift
, cshift
, mask
, cmask
, cache
;
300 currByte
= startByte
;
301 cache
= fBuffer
.get(currByte
) & 0xFF;
302 boolean isNeg
= (cache
& (1 << (BIT_CHAR
- (index
% BIT_CHAR
) - 1))) != 0;
303 if (signed
&& isNeg
) {
306 if (startByte
== (endByte
- 1)) {
307 cmask
= cache
>>> ((BIT_CHAR
- (end
% BIT_CHAR
)) % BIT_CHAR
);
308 if (((length
) % BIT_CHAR
) > 0) {
309 mask
= ~
((~
0) << length
);
316 cshift
= (int) (index
% BIT_CHAR
);
318 mask
= ~
((~
0) << (BIT_CHAR
- cshift
));
319 cmask
= cache
& mask
;
320 lshift
= BIT_CHAR
- cshift
;
325 for (; currByte
< (endByte
- 1); currByte
++) {
327 value
|= fBuffer
.get(currByte
) & 0xFF;
329 lshift
= (int) (end
% BIT_CHAR
);
331 mask
= ~
((~
0) << lshift
);
332 cmask
= fBuffer
.get(currByte
) & 0xFF;
333 cmask
>>>= BIT_CHAR
- lshift
;
339 value
|= fBuffer
.get(currByte
) & 0xFF;
344 private int getIntLE(long index
, int length
, boolean signed
) {
345 if ((length
<= 0) || (length
> BIT_INT
)) {
346 throw new IllegalArgumentException("Length must be between 1-32 bits"); //$NON-NLS-1$
348 long end
= index
+ length
;
349 int startByte
= (int) (index
/ BIT_CHAR
);
350 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
351 int currByte
, lshift
, cshift
, mask
, cmask
, cache
, mod
;
354 currByte
= endByte
- 1;
355 cache
= fBuffer
.get(currByte
) & 0xFF;
356 mod
= (int) (end
% BIT_CHAR
);
357 lshift
= (mod
> 0) ? mod
: BIT_CHAR
;
358 boolean isNeg
= (cache
& (1 << (lshift
- 1))) != 0;
359 if (signed
&& isNeg
) {
362 if (startByte
== (endByte
- 1)) {
363 cmask
= cache
>>> (index
% BIT_CHAR
);
364 if (((length
) % BIT_CHAR
) > 0) {
365 mask
= ~
((~
0) << length
);
372 cshift
= (int) (end
% BIT_CHAR
);
374 mask
= ~
((~
0) << cshift
);
375 cmask
= cache
& mask
;
380 for (; currByte
>= (startByte
+ 1); currByte
--) {
382 value
|= fBuffer
.get(currByte
) & 0xFF;
384 lshift
= (int) (index
% BIT_CHAR
);
386 mask
= ~
((~
0) << (BIT_CHAR
- lshift
));
387 cmask
= fBuffer
.get(currByte
) & 0xFF;
390 value
<<= (BIT_CHAR
- lshift
);
394 value
|= fBuffer
.get(currByte
) & 0xFF;
399 // ------------------------------------------------------------------------
400 // 'Put' operations on buffer
401 // ------------------------------------------------------------------------
404 * Relative <i>put</i> method to write signed 32-bit integer.
406 * Write four bytes starting from current bit position in the buffer
407 * according to the current byte order. The current position is increased of
408 * <i>length</i> bits.
411 * The int value to write
412 * @throws CTFReaderException
413 * An error occurred writing the data. If the buffer is written
414 * beyond its end, this exception will be raised.
416 public void putInt(int value
) throws CTFReaderException
{
417 putInt(BIT_INT
, value
);
421 * Relative <i>put</i> method to write <i>length</i> bits integer.
423 * Writes <i>length</i> lower-order bits from the provided <i>value</i>,
424 * starting from current bit position in the buffer. Sequential bytes are
425 * written according to the current byte order. The sign bit is carried to
426 * the MSB if signed is true. The sign bit is included in <i>length</i>. The
427 * current position is increased of <i>length</i>.
430 * The number of bits to write
433 * @throws CTFReaderException
434 * An error occurred writing the data. If the buffer is written
435 * beyond its end, this exception will be raised.
437 public void putInt(int length
, int value
) throws CTFReaderException
{
438 final long curPos
= fPosition
;
440 if (!canRead(length
)) {
441 throw new CTFReaderException("Cannot write to bitbuffer, " //$NON-NLS-1$
442 + "insufficient space. Requested: " + length
); //$NON-NLS-1$
447 if (fByteOrder
== ByteOrder
.LITTLE_ENDIAN
) {
448 putIntLE(curPos
, length
, value
);
450 putIntBE(curPos
, length
, value
);
455 private void putIntBE(long index
, int length
, int value
) {
456 if ((length
<= 0) || (length
> BIT_INT
)) {
457 throw new IllegalArgumentException("Length must be between 1-32 bits"); //$NON-NLS-1$
459 long end
= index
+ length
;
460 int startByte
= (int) (index
/ BIT_CHAR
);
461 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
462 int currByte
, lshift
, cshift
, mask
, cmask
;
463 int correctedValue
= value
;
466 * mask v high bits. Works for unsigned and two complement signed
467 * numbers which value do not overflow on length bits.
470 if (length
< BIT_INT
) {
471 correctedValue
&= ~
(~
0 << length
);
475 if (startByte
== (endByte
- 1)) {
476 lshift
= (int) ((BIT_CHAR
- (end
% BIT_CHAR
)) % BIT_CHAR
);
477 mask
= ~
((~
0) << lshift
);
478 if ((index
% BIT_CHAR
) > 0) {
479 mask
|= (~
(0)) << (BIT_CHAR
- (index
% BIT_CHAR
));
481 cmask
= correctedValue
<< lshift
;
483 * low bits are cleared because of left-shift and high bits are
487 int b
= fBuffer
.get(startByte
) & 0xFF;
488 fBuffer
.put(startByte
, (byte) ((b
& mask
) | cmask
));
492 /* head byte contains MSB */
493 currByte
= endByte
- 1;
494 cshift
= (int) (end
% BIT_CHAR
);
496 lshift
= BIT_CHAR
- cshift
;
497 mask
= ~
((~
0) << lshift
);
498 cmask
= correctedValue
<< lshift
;
500 int b
= fBuffer
.get(currByte
) & 0xFF;
501 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
502 correctedValue
>>>= cshift
;
507 for (; currByte
>= (startByte
+ 1); currByte
--) {
508 fBuffer
.put(currByte
, (byte) correctedValue
);
509 correctedValue
>>>= BIT_CHAR
;
511 /* end byte contains LSB */
512 if ((index
% BIT_CHAR
) > 0) {
513 mask
= (~
0) << (BIT_CHAR
- (index
% BIT_CHAR
));
514 cmask
= correctedValue
& ~mask
;
515 int b
= fBuffer
.get(currByte
) & 0xFF;
516 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
518 fBuffer
.put(currByte
, (byte) correctedValue
);
522 private void putIntLE(long index
, int length
, int value
) {
523 if ((length
<= 0) || (length
> BIT_INT
)) {
524 throw new IllegalArgumentException("Length must be between 1-32 bits"); //$NON-NLS-1$
526 long end
= index
+ length
;
527 int startByte
= (int) (index
/ BIT_CHAR
);
528 int endByte
= (int) ((end
+ (BIT_CHAR
- 1)) / BIT_CHAR
);
529 int currByte
, lshift
, cshift
, mask
, cmask
;
530 int correctedValue
= value
;
533 * mask v high bits. Works for unsigned and two complement signed
534 * numbers which value do not overflow on length bits.
537 if (length
< BIT_INT
) {
538 correctedValue
&= ~
(~
0 << length
);
542 if (startByte
== (endByte
- 1)) {
543 lshift
= (int) (index
% BIT_CHAR
);
544 mask
= ~
((~
0) << lshift
);
545 if ((end
% BIT_CHAR
) > 0) {
546 mask
|= (~
(0)) << (end
% BIT_CHAR
);
548 cmask
= correctedValue
<< lshift
;
550 * low bits are cleared because of left-shift and high bits are
554 int b
= fBuffer
.get(startByte
) & 0xFF;
555 fBuffer
.put(startByte
, (byte) ((b
& mask
) | cmask
));
560 currByte
= startByte
;
561 cshift
= (int) (index
% BIT_CHAR
);
563 mask
= ~
((~
0) << cshift
);
564 cmask
= correctedValue
<< cshift
;
566 int b
= fBuffer
.get(currByte
) & 0xFF;
567 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
568 correctedValue
>>>= BIT_CHAR
- cshift
;
573 for (; currByte
< (endByte
- 1); currByte
++) {
574 fBuffer
.put(currByte
, (byte) correctedValue
);
575 correctedValue
>>>= BIT_CHAR
;
578 if ((end
% BIT_CHAR
) > 0) {
579 mask
= (~
0) << (end
% BIT_CHAR
);
580 cmask
= correctedValue
& ~mask
;
581 int b
= fBuffer
.get(currByte
) & 0xFF;
582 fBuffer
.put(currByte
, (byte) ((b
& mask
) | cmask
));
584 fBuffer
.put(currByte
, (byte) correctedValue
);
588 // ------------------------------------------------------------------------
589 // Buffer attributes handling
590 // ------------------------------------------------------------------------
593 * Can this buffer be read for thus amount of bits?
596 * the length in bits to read
597 * @return does the buffer have enough room to read the next "length"
599 public boolean canRead(int length
) {
600 return ((fPosition
+ length
) <= fBitCapacity
);
604 * Sets the order of the buffer.
607 * The order of the buffer.
609 public void setByteOrder(ByteOrder order
) {
611 fBuffer
.order(order
);
615 * Sets the order of the buffer.
617 * @return The order of the buffer.
619 public ByteOrder
getByteOrder() {
624 * Sets the position in the buffer.
627 * The new position of the buffer.
628 * @throws CTFReaderException
629 * Thrown on out of bounds exceptions
632 public void position(long newPosition
) throws CTFReaderException
{
635 if (newPosition
> fBitCapacity
) {
636 throw new CTFReaderException("Out of bounds exception on a position move, attempting to access position: " + newPosition
); //$NON-NLS-1$
638 fPosition
= newPosition
;
643 * Sets the position in the buffer.
645 * @return order The position of the buffer.
648 public long position() {
653 * Sets the byte buffer
659 public void setByteBuffer(ByteBuffer buf
) {
661 * to avoid "The method setByteBuffer(ByteBuffer) from the type
662 * BitBuffer can be declared as static"
664 long data
= fPosition
;
666 throw new UnsupportedOperationException("Bytebuffers are now final"); //$NON-NLS-1$
671 * Gets the byte buffer
673 * @return The byte buffer
675 public ByteBuffer
getByteBuffer() {
680 * Resets the bitbuffer.
682 public void clear() {
This page took 0.045968 seconds and 5 git commands to generate.