ctf: Fix some Sonar warnings
[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 */
0594c61c 26public final class BitBuffer {
486efb2e
AM
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() {
0594c61c 99 return getInt(BIT_INT, true);
486efb2e
AM
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;
486efb2e
AM
203 currByte++;
204 }
205 for (; currByte < (endByte - 1); currByte++) {
206 value <<= BIT_CHAR;
207 value |= this.buf.get(currByte) & 0xFF;
208 }
209 lshift = end % BIT_CHAR;
210 if (lshift > 0) {
211 mask = ~((~0) << lshift);
212 cmask = this.buf.get(currByte) & 0xFF;
213 cmask >>>= BIT_CHAR - lshift;
214 cmask &= mask;
215 value <<= lshift;
216 value |= cmask;
217 } else {
218 value <<= BIT_CHAR;
219 value |= this.buf.get(currByte) & 0xFF;
220 }
221 return value;
222 }
223
224 private int getIntLE(int index, int length, boolean signed) {
225 assert ((length > 0) && (length <= BIT_INT));
226 int end = index + length;
227 int startByte = index / BIT_CHAR;
228 int endByte = (end + (BIT_CHAR - 1)) / BIT_CHAR;
229 int currByte, lshift, cshift, mask, cmask, cache, mod;
230 int value = 0;
231
232 currByte = endByte - 1;
233 cache = buf.get(currByte) & 0xFF;
234 mod = end % BIT_CHAR;
235 lshift = (mod > 0) ? mod : BIT_CHAR;
236 boolean isNeg = (cache & (1 << (lshift - 1))) != 0;
237 if (signed && isNeg) {
238 value = ~0;
239 }
240 if (startByte == (endByte - 1)) {
241 cmask = cache >>> (index % BIT_CHAR);
242 if (((length) % BIT_CHAR) > 0) {
243 mask = ~((~0) << length);
244 cmask &= mask;
245 }
246 value <<= length;
247 value |= cmask;
248 return value;
249 }
250 cshift = end % BIT_CHAR;
251 if (cshift > 0) {
252 mask = ~((~0) << cshift);
253 cmask = cache & mask;
254 value <<= cshift;
255 value |= cmask;
486efb2e
AM
256 currByte--;
257 }
258 for (; currByte >= (startByte + 1); currByte--) {
259 value <<= BIT_CHAR;
260 value |= buf.get(currByte) & 0xFF;
261 }
262 lshift = index % BIT_CHAR;
263 if (lshift > 0) {
264 mask = ~((~0) << (BIT_CHAR - lshift));
265 cmask = buf.get(currByte) & 0xFF;
266 cmask >>>= lshift;
267 cmask &= mask;
268 value <<= (BIT_CHAR - lshift);
269 value |= cmask;
270 } else {
271 value <<= BIT_CHAR;
272 value |= buf.get(currByte) & 0xFF;
273 }
274 return value;
275 }
276
277 // ------------------------------------------------------------------------
278 // 'Put' operations on buffer
279 // ------------------------------------------------------------------------
280
281 /**
282 * Relative <i>put</i> method to write signed 32-bit integer.
283 *
284 * Write four bytes starting from current bit position in the buffer
285 * according to the current byte order. The current position is increased of
286 * <i>length</i> bits.
287 *
288 * @param value
289 * The int value to write
290 */
291 public void putInt(int value) {
292 putInt(BIT_INT, value);
293 }
294
295 /**
296 * Relative <i>put</i> method to write <i>length</i> bits integer.
297 *
298 * Writes <i>length</i> lower-order bits from the provided <i>value</i>,
299 * starting from current bit position in the buffer. Sequential bytes are
300 * written according to the current byte order. The sign bit is carried to
301 * the MSB if signed is true. The sign bit is included in <i>length</i>. The
302 * current position is increased of <i>length</i>.
303 *
304 * @param length
305 * The number of bits to write
306 * @param value
307 * The value to write
308 */
309 public void putInt(int length, int value) {
310 final int curPos = this.pos;
311
312 if (!canRead(length)) {
313 throw new BufferOverflowException();
314 }
315 if (length == 0) {
316 return;
317 }
318 if (this.byteOrder == ByteOrder.LITTLE_ENDIAN) {
319 putIntLE(curPos, length, value);
320 } else {
321 putIntBE(curPos, length, value);
322 }
323 this.pos += length;
324 }
325
326 private void putIntBE(int index, int length, int value) {
327 assert ((length > 0) && (length <= BIT_INT));
328 int end = index + length;
329 int startByte = index / BIT_CHAR;
330 int endByte = (end + (BIT_CHAR - 1)) / BIT_CHAR;
331 int currByte, lshift, cshift, mask, cmask;
332 int correctedValue = value;
333
334 /*
335 * mask v high bits. Works for unsigned and two complement signed
336 * numbers which value do not overflow on length bits.
337 */
338
339 if (length < BIT_INT) {
340 correctedValue &= ~(~0 << length);
341 }
342
343 /* sub byte */
344 if (startByte == (endByte - 1)) {
345 lshift = (BIT_CHAR - (end % BIT_CHAR)) % BIT_CHAR;
346 mask = ~((~0) << lshift);
347 if ((index % BIT_CHAR) > 0) {
348 mask |= (~(0)) << (BIT_CHAR - (index % BIT_CHAR));
349 }
350 cmask = correctedValue << lshift;
351 /*
352 * low bits are cleared because of lshift and high bits are already
353 * cleared
354 */
355 cmask &= ~mask;
356 int b = this.buf.get(startByte) & 0xFF;
357 this.buf.put(startByte, (byte) ((b & mask) | cmask));
358 return;
359 }
360
361 /* head byte contains MSB */
362 currByte = endByte - 1;
363 cshift = end % BIT_CHAR;
364 if (cshift > 0) {
365 lshift = BIT_CHAR - cshift;
366 mask = ~((~0) << lshift);
367 cmask = correctedValue << lshift;
368 cmask &= ~mask;
369 int b = this.buf.get(currByte) & 0xFF;
370 this.buf.put(currByte, (byte) ((b & mask) | cmask));
371 correctedValue >>>= cshift;
486efb2e
AM
372 currByte--;
373 }
374
375 /* middle byte(s) */
376 for (; currByte >= (startByte + 1); currByte--) {
377 this.buf.put(currByte, (byte) correctedValue);
378 correctedValue >>>= BIT_CHAR;
379 }
380 /* end byte contains LSB */
381 if ((index % BIT_CHAR) > 0) {
382 mask = (~0) << (BIT_CHAR - (index % BIT_CHAR));
383 cmask = correctedValue & ~mask;
384 int b = this.buf.get(currByte) & 0xFF;
385 this.buf.put(currByte, (byte) ((b & mask) | cmask));
386 } else {
387 this.buf.put(currByte, (byte) correctedValue);
388 }
389 }
390
391 private void putIntLE(int index, int length, int value) {
392 assert ((length > 0) && (length <= BIT_INT));
393 int end = index + length;
394 int startByte = index / BIT_CHAR;
395 int endByte = (end + (BIT_CHAR - 1)) / BIT_CHAR;
396 int currByte, lshift, cshift, mask, cmask;
397 int correctedValue = value;
398
399 /*
400 * mask v high bits. Works for unsigned and two complement signed
401 * numbers which value do not overflow on length bits.
402 */
403
404 if (length < BIT_INT) {
405 correctedValue &= ~(~0 << length);
406 }
407
408 /* sub byte */
409 if (startByte == (endByte - 1)) {
410 lshift = index % BIT_CHAR;
411 mask = ~((~0) << lshift);
412 if ((end % BIT_CHAR) > 0) {
413 mask |= (~(0)) << (end % BIT_CHAR);
414 }
415 cmask = correctedValue << lshift;
416 /*
417 * low bits are cleared because of lshift and high bits are already
418 * cleared
419 */
420 cmask &= ~mask;
421 int b = this.buf.get(startByte) & 0xFF;
422 this.buf.put(startByte, (byte) ((b & mask) | cmask));
423 return;
424 }
425
426 /* head byte */
427 currByte = startByte;
428 cshift = index % BIT_CHAR;
429 if (cshift > 0) {
430 mask = ~((~0) << cshift);
431 cmask = correctedValue << cshift;
432 cmask &= ~mask;
433 int b = this.buf.get(currByte) & 0xFF;
434 this.buf.put(currByte, (byte) ((b & mask) | cmask));
435 correctedValue >>>= BIT_CHAR - cshift;
486efb2e
AM
436 currByte++;
437 }
438
439 /* middle byte(s) */
440 for (; currByte < (endByte - 1); currByte++) {
441 this.buf.put(currByte, (byte) correctedValue);
442 correctedValue >>>= BIT_CHAR;
443 }
444 /* end byte */
445 if ((end % BIT_CHAR) > 0) {
446 mask = (~0) << (end % BIT_CHAR);
447 cmask = correctedValue & ~mask;
448 int b = this.buf.get(currByte) & 0xFF;
449 this.buf.put(currByte, (byte) ((b & mask) | cmask));
450 } else {
451 this.buf.put(currByte, (byte) correctedValue);
452 }
453 }
454
455 // ------------------------------------------------------------------------
456 // Buffer attributes handling
457 // ------------------------------------------------------------------------
458
459 /**
460 * Can this buffer be read for thus amount of bits?
461 *
462 * @param length
463 * the length in bits to read
464 * @return does the buffer have enough room to read the next "length"
465 */
466 public boolean canRead(int length) {
467 if (this.buf == null) {
468 return false;
469 }
470
471 if ((this.pos + length) > (this.buf.capacity() * BIT_CHAR)) {
472 return false;
473 }
474 return true;
475 }
476
477 /**
478 * Sets the order of the buffer.
479 *
480 * @param order
481 * The order of the buffer.
482 */
483 public void setByteOrder(ByteOrder order) {
484 this.byteOrder = order;
485 if (this.buf != null) {
486 this.buf.order(order);
487 }
488 }
489
490 /**
491 * Sets the order of the buffer.
492 *
493 * @return The order of the buffer.
494 */
495 public ByteOrder getByteOrder() {
496 return this.byteOrder;
497 }
498
499 /**
500 * Sets the position in the buffer.
501 *
502 * @param newPosition
503 * The new position of the buffer.
504 */
505 public void position(int newPosition) {
506 this.pos = newPosition;
507 }
508
509 /**
510 *
511 * Sets the position in the buffer.
512 *
513 * @return order The position of the buffer.
514 */
515 public int position() {
516 return this.pos;
517 }
518
519 /**
520 * Sets the byte buffer
521 *
522 * @param buf
523 * the byte buffer
524 */
525 public void setByteBuffer(ByteBuffer buf) {
526 this.buf = buf;
527 if (buf != null) {
528 this.buf.order(this.byteOrder);
529 }
530 clear();
531 }
532
533 /**
534 * Gets the byte buffer
535 *
536 * @return The byte buffer
537 */
538 public ByteBuffer getByteBuffer() {
539 return this.buf;
540 }
541
542 /**
543 * resets the bitbuffer.
544 */
545 public void clear() {
546 position(0);
547
548 if (this.buf == null) {
549 return;
550 }
551 this.buf.clear();
552 }
553
554}
This page took 0.053521 seconds and 5 git commands to generate.