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