tmf: Correctly export all packages in runtime plugins
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / internal / ctf / core / event / io / BitBuffer.java
1 /*******************************************************************************.
2 * Copyright (c) 2011-2012 Ericsson, Ecole Polytechnique de Montreal and others
3 *
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
8 *
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 *******************************************************************************/
13
14 package org.eclipse.linuxtools.internal.ctf.core.event.io;
15
16 import java.nio.BufferOverflowException;
17 import java.nio.ByteBuffer;
18 import java.nio.ByteOrder;
19
20 /**
21 * <b><u>BitBuffer</u></b>
22 * <p>
23 * A bitwise buffer capable of accessing fields with bit offsets.
24 */
25 public class BitBuffer {
26
27 // ------------------------------------------------------------------------
28 // Constants
29 // ------------------------------------------------------------------------
30
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;
42
43 // ------------------------------------------------------------------------
44 // Attributes
45 // ------------------------------------------------------------------------
46
47 private ByteBuffer buf;
48 private int pos;
49 private ByteOrder byteOrder;
50
51 // ------------------------------------------------------------------------
52 // Constructors
53 // ------------------------------------------------------------------------
54 /**
55 * Default constructor, makes a bigendian buffer
56 */
57 public BitBuffer() {
58 this(null, ByteOrder.BIG_ENDIAN);
59 }
60
61 /**
62 * Constructor, makes a bigendian buffer
63 *
64 * @param buf
65 * the bytebuffer to read
66 */
67 public BitBuffer(ByteBuffer buf) {
68 this(buf, ByteOrder.BIG_ENDIAN);
69 }
70
71 /**
72 * Constructor that is fully parametrisable
73 *
74 * @param buf
75 * the buffer to read
76 * @param order
77 * the byte order (big endian, little endian, network?)
78 */
79 public BitBuffer(ByteBuffer buf, ByteOrder order) {
80 setByteBuffer(buf);
81 setByteOrder(order);
82 position(0);
83 }
84
85 // ------------------------------------------------------------------------
86 // 'Get' operations on buffer
87 // ------------------------------------------------------------------------
88
89 /**
90 * Relative <i>get</i> method for reading 32-bit integer.
91 *
92 * Reads next four bytes from the current bit position according to current
93 * byte order.
94 *
95 * @return The int value read from the buffer
96 */
97 public int getInt() {
98 int val = getInt(BIT_INT, true);
99 return val;
100 }
101
102 /**
103 * Relative <i>get</i> method for reading integer of <i>length</i> bits.
104 *
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.
108 *
109 * @param length
110 * The length in bits of this integer
111 * @param signed
112 * The sign extended flag
113 * @return The int value read from the buffer
114 */
115 public int getInt(int length, boolean signed) {
116 int val = 0;
117 if (!canRead(length)) {
118 throw new BufferOverflowException();
119 }
120 if (length == 0) {
121 return 0;
122 }
123 boolean gotIt = false;
124
125 // Fall back to fast ByteBuffer reader if we want to read byte-aligned bytes
126 if (this.pos % BitBuffer.BIT_CHAR == 0) {
127 switch (length) {
128 case BitBuffer.BIT_CHAR:
129 // Byte
130 if (signed) {
131 val = this.buf.get(this.pos / 8);
132 } else {
133 val = (this.buf.get(this.pos / 8)) & 0xff;
134 }
135 gotIt = true;
136 break;
137
138 case BitBuffer.BIT_SHORT:
139 // Word
140 if (signed) {
141 val = this.buf.getShort(this.pos / 8);
142 } else {
143 short a = this.buf.getShort(this.pos / 8);
144 val = a & 0xffff;
145 }
146 gotIt = true;
147 break;
148
149 case BitBuffer.BIT_INT:
150 // Double word
151 val = this.buf.getInt(this.pos / 8);
152 gotIt = true;
153 break;
154
155 default:
156 break;
157 }
158 }
159 if (!gotIt) {
160 // Nothing read yet: use longer methods
161 if (this.byteOrder == ByteOrder.LITTLE_ENDIAN) {
162 val = getIntLE(this.pos, length, signed);
163 } else {
164 val = getIntBE(this.pos, length, signed);
165 }
166 }
167 this.pos += length;
168
169 return val;
170 }
171
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;
178 int value = 0;
179
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) {
184 value = ~0;
185 }
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);
190 cmask &= mask;
191 }
192 value <<= length;
193 value |= cmask;
194 return value;
195 }
196 cshift = index % BIT_CHAR;
197 if (cshift > 0) {
198 mask = ~((~0) << (BIT_CHAR - cshift));
199 cmask = cache & mask;
200 lshift = BIT_CHAR - cshift;
201 value <<= lshift;
202 value |= cmask;
203 // index += lshift;
204 currByte++;
205 }
206 for (; currByte < (endByte - 1); currByte++) {
207 value <<= BIT_CHAR;
208 value |= this.buf.get(currByte) & 0xFF;
209 }
210 lshift = end % BIT_CHAR;
211 if (lshift > 0) {
212 mask = ~((~0) << lshift);
213 cmask = this.buf.get(currByte) & 0xFF;
214 cmask >>>= BIT_CHAR - lshift;
215 cmask &= mask;
216 value <<= lshift;
217 value |= cmask;
218 } else {
219 value <<= BIT_CHAR;
220 value |= this.buf.get(currByte) & 0xFF;
221 }
222 return value;
223 }
224
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;
231 int value = 0;
232
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) {
239 value = ~0;
240 }
241 if (startByte == (endByte - 1)) {
242 cmask = cache >>> (index % BIT_CHAR);
243 if (((length) % BIT_CHAR) > 0) {
244 mask = ~((~0) << length);
245 cmask &= mask;
246 }
247 value <<= length;
248 value |= cmask;
249 return value;
250 }
251 cshift = end % BIT_CHAR;
252 if (cshift > 0) {
253 mask = ~((~0) << cshift);
254 cmask = cache & mask;
255 value <<= cshift;
256 value |= cmask;
257 // end -= cshift;
258 currByte--;
259 }
260 for (; currByte >= (startByte + 1); currByte--) {
261 value <<= BIT_CHAR;
262 value |= buf.get(currByte) & 0xFF;
263 }
264 lshift = index % BIT_CHAR;
265 if (lshift > 0) {
266 mask = ~((~0) << (BIT_CHAR - lshift));
267 cmask = buf.get(currByte) & 0xFF;
268 cmask >>>= lshift;
269 cmask &= mask;
270 value <<= (BIT_CHAR - lshift);
271 value |= cmask;
272 } else {
273 value <<= BIT_CHAR;
274 value |= buf.get(currByte) & 0xFF;
275 }
276 return value;
277 }
278
279 // ------------------------------------------------------------------------
280 // 'Put' operations on buffer
281 // ------------------------------------------------------------------------
282
283 /**
284 * Relative <i>put</i> method to write signed 32-bit integer.
285 *
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.
289 *
290 * @param value
291 * The int value to write
292 */
293 public void putInt(int value) {
294 putInt(BIT_INT, value);
295 }
296
297 /**
298 * Relative <i>put</i> method to write <i>length</i> bits integer.
299 *
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>.
305 *
306 * @param length
307 * The number of bits to write
308 * @param value
309 * The value to write
310 */
311 public void putInt(int length, int value) {
312 final int curPos = this.pos;
313
314 if (!canRead(length)) {
315 throw new BufferOverflowException();
316 }
317 if (length == 0) {
318 return;
319 }
320 if (this.byteOrder == ByteOrder.LITTLE_ENDIAN) {
321 putIntLE(curPos, length, value);
322 } else {
323 putIntBE(curPos, length, value);
324 }
325 this.pos += length;
326 }
327
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;
335
336 /*
337 * mask v high bits. Works for unsigned and two complement signed
338 * numbers which value do not overflow on length bits.
339 */
340
341 if (length < BIT_INT) {
342 correctedValue &= ~(~0 << length);
343 }
344
345 /* sub byte */
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));
351 }
352 cmask = correctedValue << lshift;
353 /*
354 * low bits are cleared because of lshift and high bits are already
355 * cleared
356 */
357 cmask &= ~mask;
358 int b = this.buf.get(startByte) & 0xFF;
359 this.buf.put(startByte, (byte) ((b & mask) | cmask));
360 return;
361 }
362
363 /* head byte contains MSB */
364 currByte = endByte - 1;
365 cshift = end % BIT_CHAR;
366 if (cshift > 0) {
367 lshift = BIT_CHAR - cshift;
368 mask = ~((~0) << lshift);
369 cmask = correctedValue << lshift;
370 cmask &= ~mask;
371 int b = this.buf.get(currByte) & 0xFF;
372 this.buf.put(currByte, (byte) ((b & mask) | cmask));
373 correctedValue >>>= cshift;
374 // end -= cshift;
375 currByte--;
376 }
377
378 /* middle byte(s) */
379 for (; currByte >= (startByte + 1); currByte--) {
380 this.buf.put(currByte, (byte) correctedValue);
381 correctedValue >>>= BIT_CHAR;
382 }
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));
389 } else {
390 this.buf.put(currByte, (byte) correctedValue);
391 }
392 }
393
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;
401
402 /*
403 * mask v high bits. Works for unsigned and two complement signed
404 * numbers which value do not overflow on length bits.
405 */
406
407 if (length < BIT_INT) {
408 correctedValue &= ~(~0 << length);
409 }
410
411 /* sub byte */
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);
417 }
418 cmask = correctedValue << lshift;
419 /*
420 * low bits are cleared because of lshift and high bits are already
421 * cleared
422 */
423 cmask &= ~mask;
424 int b = this.buf.get(startByte) & 0xFF;
425 this.buf.put(startByte, (byte) ((b & mask) | cmask));
426 return;
427 }
428
429 /* head byte */
430 currByte = startByte;
431 cshift = index % BIT_CHAR;
432 if (cshift > 0) {
433 mask = ~((~0) << cshift);
434 cmask = correctedValue << cshift;
435 cmask &= ~mask;
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;
440 currByte++;
441 }
442
443 /* middle byte(s) */
444 for (; currByte < (endByte - 1); currByte++) {
445 this.buf.put(currByte, (byte) correctedValue);
446 correctedValue >>>= BIT_CHAR;
447 }
448 /* end byte */
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));
454 } else {
455 this.buf.put(currByte, (byte) correctedValue);
456 }
457 }
458
459 // ------------------------------------------------------------------------
460 // Buffer attributes handling
461 // ------------------------------------------------------------------------
462
463 /**
464 * Can this buffer be read for thus amount of bits?
465 *
466 * @param length
467 * the length in bits to read
468 * @return does the buffer have enough room to read the next "length"
469 */
470 public boolean canRead(int length) {
471 if (this.buf == null) {
472 return false;
473 }
474
475 if ((this.pos + length) > (this.buf.capacity() * BIT_CHAR)) {
476 return false;
477 }
478 return true;
479 }
480
481 /**
482 * Sets the order of the buffer.
483 *
484 * @param order
485 * The order of the buffer.
486 */
487 public void setByteOrder(ByteOrder order) {
488 this.byteOrder = order;
489 if (this.buf != null) {
490 this.buf.order(order);
491 }
492 }
493
494 /**
495 * Sets the order of the buffer.
496 *
497 * @return The order of the buffer.
498 */
499 public ByteOrder getByteOrder() {
500 return this.byteOrder;
501 }
502
503 /**
504 * Sets the position in the buffer.
505 *
506 * @param newPosition
507 * The new position of the buffer.
508 */
509 public void position(int newPosition) {
510 this.pos = newPosition;
511 }
512
513 /**
514 *
515 * Sets the position in the buffer.
516 *
517 * @return order The position of the buffer.
518 */
519 public int position() {
520 return this.pos;
521 }
522
523 /**
524 * Sets the byte buffer
525 *
526 * @param buf
527 * the byte buffer
528 */
529 public void setByteBuffer(ByteBuffer buf) {
530 this.buf = buf;
531 if (buf != null) {
532 this.buf.order(this.byteOrder);
533 }
534 clear();
535 }
536
537 /**
538 * Gets the byte buffer
539 *
540 * @return The byte buffer
541 */
542 public ByteBuffer getByteBuffer() {
543 return this.buf;
544 }
545
546 /**
547 * resets the bitbuffer.
548 */
549 public void clear() {
550 position(0);
551
552 if (this.buf == null) {
553 return;
554 }
555 this.buf.clear();
556 }
557
558 }
This page took 0.043495 seconds and 5 git commands to generate.