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