Commit | Line | Data |
---|---|---|
486efb2e | 1 | /*******************************************************************************. |
60ae41e1 | 2 | * Copyright (c) 2011, 2013 Ericsson, Ecole Polytechnique de Montreal and others |
486efb2e AM |
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 | * | |
2b50c5ac MK |
9 | * Contributors: |
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 | |
486efb2e AM |
14 | *******************************************************************************/ |
15 | ||
16 | package org.eclipse.linuxtools.ctf.core.event.io; | |
17 | ||
486efb2e AM |
18 | import java.nio.ByteBuffer; |
19 | import java.nio.ByteOrder; | |
20 | ||
db8e8f7d AM |
21 | import org.eclipse.linuxtools.ctf.core.trace.CTFReaderException; |
22 | ||
486efb2e AM |
23 | /** |
24 | * <b><u>BitBuffer</u></b> | |
25 | * <p> | |
26 | * A bitwise buffer capable of accessing fields with bit offsets. | |
2b50c5ac | 27 | * |
486efb2e AM |
28 | * @since 2.0 |
29 | */ | |
0594c61c | 30 | public final class BitBuffer { |
486efb2e AM |
31 | |
32 | // ------------------------------------------------------------------------ | |
33 | // Constants | |
34 | // ------------------------------------------------------------------------ | |
35 | ||
36 | /* default bit width */ | |
37 | /** 8 bits to a char */ | |
38 | public static final int BIT_CHAR = 8; | |
39 | /** 16 bits to a short */ | |
40 | public static final int BIT_SHORT = 16; | |
41 | /** 32 bits to an int */ | |
42 | public static final int BIT_INT = 32; | |
43 | /** 32 bits to a float */ | |
44 | public static final int BIT_FLOAT = 32; | |
45 | /** 64 bits to a long */ | |
46 | public static final int BIT_LONG = 64; | |
47 | ||
48 | // ------------------------------------------------------------------------ | |
49 | // Attributes | |
50 | // ------------------------------------------------------------------------ | |
51 | ||
4c67e724 MK |
52 | private ByteBuffer fBuffer; |
53 | private long fPosition; | |
54 | private ByteOrder fByteOrder; | |
486efb2e AM |
55 | |
56 | // ------------------------------------------------------------------------ | |
57 | // Constructors | |
58 | // ------------------------------------------------------------------------ | |
59 | /** | |
74e4b6b9 | 60 | * Default constructor, makes a big-endian buffer |
486efb2e AM |
61 | */ |
62 | public BitBuffer() { | |
63 | this(null, ByteOrder.BIG_ENDIAN); | |
64 | } | |
65 | ||
66 | /** | |
74e4b6b9 | 67 | * Constructor, makes a big-endian buffer |
486efb2e AM |
68 | * |
69 | * @param buf | |
70 | * the bytebuffer to read | |
71 | */ | |
72 | public BitBuffer(ByteBuffer buf) { | |
73 | this(buf, ByteOrder.BIG_ENDIAN); | |
74 | } | |
75 | ||
76 | /** | |
74e4b6b9 | 77 | * Constructor that is fully parameterizable |
486efb2e AM |
78 | * |
79 | * @param buf | |
80 | * the buffer to read | |
81 | * @param order | |
74e4b6b9 | 82 | * the byte order (big-endian, little-endian, network?) |
486efb2e AM |
83 | */ |
84 | public BitBuffer(ByteBuffer buf, ByteOrder order) { | |
85 | setByteBuffer(buf); | |
86 | setByteOrder(order); | |
4c67e724 MK |
87 | resetPosition(); |
88 | } | |
89 | ||
90 | private void resetPosition() { | |
91 | fPosition = 0; | |
486efb2e AM |
92 | } |
93 | ||
94 | // ------------------------------------------------------------------------ | |
95 | // 'Get' operations on buffer | |
96 | // ------------------------------------------------------------------------ | |
97 | ||
98 | /** | |
99 | * Relative <i>get</i> method for reading 32-bit integer. | |
100 | * | |
101 | * Reads next four bytes from the current bit position according to current | |
102 | * byte order. | |
103 | * | |
2b50c5ac | 104 | * @return The int value (signed) read from the buffer |
db8e8f7d | 105 | * @throws CTFReaderException |
2b50c5ac MK |
106 | * An error occurred reading the long. This exception can be |
107 | * raised if the buffer tries to read out of bounds | |
486efb2e | 108 | */ |
db8e8f7d | 109 | public int getInt() throws CTFReaderException { |
0594c61c | 110 | return getInt(BIT_INT, true); |
486efb2e AM |
111 | } |
112 | ||
2b50c5ac MK |
113 | /** |
114 | * Relative <i>get</i> method for reading 64-bit integer. | |
115 | * | |
116 | * Reads next eight bytes from the current bit position according to current | |
117 | * byte order. | |
118 | * | |
119 | * @return The long value (signed) read from the buffer | |
120 | * @throws CTFReaderException | |
121 | * An error occurred reading the long. This exception can be | |
122 | * raised if the buffer tries to read out of bounds | |
c4767854 | 123 | * @since 3.0 |
2b50c5ac MK |
124 | */ |
125 | public long getLong() throws CTFReaderException { | |
126 | return get(BIT_LONG, true); | |
127 | } | |
128 | ||
129 | /** | |
130 | * Relative <i>get</i> method for reading long of <i>length</i> bits. | |
131 | * | |
132 | * Reads <i>length</i> bits starting at the current position. The result is | |
133 | * signed extended if <i>signed</i> is true. The current position is | |
134 | * increased of <i>length</i> bits. | |
135 | * | |
136 | * @param length | |
137 | * The length in bits of this integer | |
138 | * @param signed | |
139 | * The sign extended flag | |
140 | * @return The long value read from the buffer | |
141 | * @throws CTFReaderException | |
142 | * An error occurred reading the data. If more than 64 bits at a | |
143 | * time are read, or the buffer is read beyond its end, this | |
144 | * exception will be raised. | |
c4767854 | 145 | * @since 3.0 |
2b50c5ac MK |
146 | */ |
147 | public long get(int length, boolean signed) throws CTFReaderException { | |
148 | if (length > BIT_LONG) { | |
149 | throw new CTFReaderException("Cannot read a long longer than 64 bits. Rquested: " + length); //$NON-NLS-1$ | |
150 | } | |
151 | if (length > BIT_INT) { | |
152 | final int highShift = length - BIT_INT; | |
153 | long a = getInt(); | |
154 | long b = getInt(highShift, false); | |
155 | long retVal; | |
156 | /* Cast the signed-extended int into a unsigned int. */ | |
157 | a &= 0xFFFFFFFFL; | |
158 | b &= (1L << highShift) - 1L; | |
159 | ||
4c67e724 | 160 | retVal = (fByteOrder == ByteOrder.BIG_ENDIAN) ? ((a << highShift) | b) : ((b << BIT_INT) | a); |
2b50c5ac MK |
161 | /* sign extend */ |
162 | if (signed) { | |
163 | int signExtendBits = BIT_LONG - length; | |
164 | retVal = (retVal << signExtendBits) >> signExtendBits; | |
165 | } | |
166 | return retVal; | |
167 | } | |
168 | long retVal = getInt(length, signed); | |
169 | return (signed ? retVal : (retVal & 0xFFFFFFFFL)); | |
170 | } | |
171 | ||
486efb2e AM |
172 | /** |
173 | * Relative <i>get</i> method for reading integer of <i>length</i> bits. | |
174 | * | |
175 | * Reads <i>length</i> bits starting at the current position. The result is | |
176 | * signed extended if <i>signed</i> is true. The current position is | |
177 | * increased of <i>length</i> bits. | |
178 | * | |
179 | * @param length | |
180 | * The length in bits of this integer | |
181 | * @param signed | |
182 | * The sign extended flag | |
183 | * @return The int value read from the buffer | |
db8e8f7d AM |
184 | * @throws CTFReaderException |
185 | * An error occurred reading the data. When the buffer is read | |
186 | * beyond its end, this exception will be raised. | |
486efb2e | 187 | */ |
2b50c5ac | 188 | private int getInt(int length, boolean signed) throws CTFReaderException { |
74e4b6b9 EB |
189 | |
190 | /* Nothing to read. */ | |
486efb2e AM |
191 | if (length == 0) { |
192 | return 0; | |
193 | } | |
74e4b6b9 EB |
194 | |
195 | /* Validate that the buffer has enough bits. */ | |
196 | if (!canRead(length)) { | |
db8e8f7d AM |
197 | throw new CTFReaderException("Cannot read the integer, " + //$NON-NLS-1$ |
198 | "the buffer does not have enough remaining space. " + //$NON-NLS-1$ | |
199 | "Requested:" + length); //$NON-NLS-1$ | |
74e4b6b9 EB |
200 | } |
201 | ||
202 | /* Get the value from the byte buffer. */ | |
203 | int val = 0; | |
486efb2e AM |
204 | boolean gotIt = false; |
205 | ||
2b50c5ac MK |
206 | /* |
207 | * Try a fast read when the position is byte-aligned by using | |
208 | * java.nio.ByteBuffer's native methods | |
209 | */ | |
210 | /* | |
211 | * A faster alignment detection as the compiler cannot guaranty that pos | |
212 | * is always positive. | |
213 | */ | |
4c67e724 | 214 | if ((fPosition & (BitBuffer.BIT_CHAR - 1)) == 0) { |
486efb2e AM |
215 | switch (length) { |
216 | case BitBuffer.BIT_CHAR: | |
217 | // Byte | |
4c67e724 | 218 | val = fBuffer.get((int) (fPosition / 8)); |
74e4b6b9 EB |
219 | if (!signed) { |
220 | val = val & 0xff; | |
486efb2e AM |
221 | } |
222 | gotIt = true; | |
223 | break; | |
224 | ||
225 | case BitBuffer.BIT_SHORT: | |
226 | // Word | |
4c67e724 | 227 | val = fBuffer.getShort((int) (fPosition / 8)); |
74e4b6b9 EB |
228 | if (!signed) { |
229 | val = val & 0xffff; | |
486efb2e AM |
230 | } |
231 | gotIt = true; | |
232 | break; | |
233 | ||
234 | case BitBuffer.BIT_INT: | |
235 | // Double word | |
4c67e724 | 236 | val = fBuffer.getInt((int) (fPosition / 8)); |
486efb2e AM |
237 | gotIt = true; |
238 | break; | |
239 | ||
240 | default: | |
241 | break; | |
242 | } | |
243 | } | |
74e4b6b9 EB |
244 | |
245 | /* When not byte-aligned, fall-back to a general decoder. */ | |
486efb2e AM |
246 | if (!gotIt) { |
247 | // Nothing read yet: use longer methods | |
4c67e724 MK |
248 | if (fByteOrder == ByteOrder.LITTLE_ENDIAN) { |
249 | val = getIntLE(fPosition, length, signed); | |
486efb2e | 250 | } else { |
4c67e724 | 251 | val = getIntBE(fPosition, length, signed); |
486efb2e AM |
252 | } |
253 | } | |
4c67e724 | 254 | fPosition += length; |
486efb2e AM |
255 | |
256 | return val; | |
257 | } | |
258 | ||
47ca6c05 | 259 | private int getIntBE(long index, int length, boolean signed) { |
486efb2e | 260 | assert ((length > 0) && (length <= BIT_INT)); |
47ca6c05 SM |
261 | long end = index + length; |
262 | int startByte = (int) (index / BIT_CHAR); | |
263 | int endByte = (int) ((end + (BIT_CHAR - 1)) / BIT_CHAR); | |
486efb2e AM |
264 | int currByte, lshift, cshift, mask, cmask, cache; |
265 | int value = 0; | |
266 | ||
267 | currByte = startByte; | |
4c67e724 | 268 | cache = fBuffer.get(currByte) & 0xFF; |
486efb2e AM |
269 | boolean isNeg = (cache & (1 << (BIT_CHAR - (index % BIT_CHAR) - 1))) != 0; |
270 | if (signed && isNeg) { | |
271 | value = ~0; | |
272 | } | |
273 | if (startByte == (endByte - 1)) { | |
274 | cmask = cache >>> ((BIT_CHAR - (end % BIT_CHAR)) % BIT_CHAR); | |
275 | if (((length) % BIT_CHAR) > 0) { | |
276 | mask = ~((~0) << length); | |
277 | cmask &= mask; | |
278 | } | |
279 | value <<= length; | |
280 | value |= cmask; | |
281 | return value; | |
282 | } | |
47ca6c05 | 283 | cshift = (int) (index % BIT_CHAR); |
486efb2e AM |
284 | if (cshift > 0) { |
285 | mask = ~((~0) << (BIT_CHAR - cshift)); | |
286 | cmask = cache & mask; | |
287 | lshift = BIT_CHAR - cshift; | |
288 | value <<= lshift; | |
289 | value |= cmask; | |
486efb2e AM |
290 | currByte++; |
291 | } | |
292 | for (; currByte < (endByte - 1); currByte++) { | |
293 | value <<= BIT_CHAR; | |
4c67e724 | 294 | value |= fBuffer.get(currByte) & 0xFF; |
486efb2e | 295 | } |
47ca6c05 | 296 | lshift = (int) (end % BIT_CHAR); |
486efb2e AM |
297 | if (lshift > 0) { |
298 | mask = ~((~0) << lshift); | |
4c67e724 | 299 | cmask = fBuffer.get(currByte) & 0xFF; |
486efb2e AM |
300 | cmask >>>= BIT_CHAR - lshift; |
301 | cmask &= mask; | |
302 | value <<= lshift; | |
303 | value |= cmask; | |
304 | } else { | |
305 | value <<= BIT_CHAR; | |
4c67e724 | 306 | value |= fBuffer.get(currByte) & 0xFF; |
486efb2e AM |
307 | } |
308 | return value; | |
309 | } | |
310 | ||
47ca6c05 | 311 | private int getIntLE(long index, int length, boolean signed) { |
486efb2e | 312 | assert ((length > 0) && (length <= BIT_INT)); |
47ca6c05 SM |
313 | long end = index + length; |
314 | int startByte = (int) (index / BIT_CHAR); | |
315 | int endByte = (int) ((end + (BIT_CHAR - 1)) / BIT_CHAR); | |
486efb2e AM |
316 | int currByte, lshift, cshift, mask, cmask, cache, mod; |
317 | int value = 0; | |
318 | ||
319 | currByte = endByte - 1; | |
4c67e724 | 320 | cache = fBuffer.get(currByte) & 0xFF; |
47ca6c05 | 321 | mod = (int) (end % BIT_CHAR); |
486efb2e AM |
322 | lshift = (mod > 0) ? mod : BIT_CHAR; |
323 | boolean isNeg = (cache & (1 << (lshift - 1))) != 0; | |
324 | if (signed && isNeg) { | |
325 | value = ~0; | |
326 | } | |
327 | if (startByte == (endByte - 1)) { | |
328 | cmask = cache >>> (index % BIT_CHAR); | |
329 | if (((length) % BIT_CHAR) > 0) { | |
330 | mask = ~((~0) << length); | |
331 | cmask &= mask; | |
332 | } | |
333 | value <<= length; | |
334 | value |= cmask; | |
335 | return value; | |
336 | } | |
47ca6c05 | 337 | cshift = (int) (end % BIT_CHAR); |
486efb2e AM |
338 | if (cshift > 0) { |
339 | mask = ~((~0) << cshift); | |
340 | cmask = cache & mask; | |
341 | value <<= cshift; | |
342 | value |= cmask; | |
486efb2e AM |
343 | currByte--; |
344 | } | |
345 | for (; currByte >= (startByte + 1); currByte--) { | |
346 | value <<= BIT_CHAR; | |
4c67e724 | 347 | value |= fBuffer.get(currByte) & 0xFF; |
486efb2e | 348 | } |
47ca6c05 | 349 | lshift = (int) (index % BIT_CHAR); |
486efb2e AM |
350 | if (lshift > 0) { |
351 | mask = ~((~0) << (BIT_CHAR - lshift)); | |
4c67e724 | 352 | cmask = fBuffer.get(currByte) & 0xFF; |
486efb2e AM |
353 | cmask >>>= lshift; |
354 | cmask &= mask; | |
355 | value <<= (BIT_CHAR - lshift); | |
356 | value |= cmask; | |
357 | } else { | |
358 | value <<= BIT_CHAR; | |
4c67e724 | 359 | value |= fBuffer.get(currByte) & 0xFF; |
486efb2e AM |
360 | } |
361 | return value; | |
362 | } | |
363 | ||
364 | // ------------------------------------------------------------------------ | |
365 | // 'Put' operations on buffer | |
366 | // ------------------------------------------------------------------------ | |
367 | ||
368 | /** | |
369 | * Relative <i>put</i> method to write signed 32-bit integer. | |
370 | * | |
371 | * Write four bytes starting from current bit position in the buffer | |
372 | * according to the current byte order. The current position is increased of | |
373 | * <i>length</i> bits. | |
374 | * | |
375 | * @param value | |
376 | * The int value to write | |
db8e8f7d AM |
377 | * @throws CTFReaderException |
378 | * An error occurred writing the data. If the buffer is written | |
379 | * beyond its end, this exception will be raised. | |
486efb2e | 380 | */ |
db8e8f7d | 381 | public void putInt(int value) throws CTFReaderException { |
486efb2e AM |
382 | putInt(BIT_INT, value); |
383 | } | |
384 | ||
385 | /** | |
386 | * Relative <i>put</i> method to write <i>length</i> bits integer. | |
387 | * | |
388 | * Writes <i>length</i> lower-order bits from the provided <i>value</i>, | |
389 | * starting from current bit position in the buffer. Sequential bytes are | |
390 | * written according to the current byte order. The sign bit is carried to | |
391 | * the MSB if signed is true. The sign bit is included in <i>length</i>. The | |
392 | * current position is increased of <i>length</i>. | |
393 | * | |
394 | * @param length | |
395 | * The number of bits to write | |
396 | * @param value | |
397 | * The value to write | |
db8e8f7d AM |
398 | * @throws CTFReaderException |
399 | * An error occurred writing the data. If the buffer is written | |
400 | * beyond its end, this exception will be raised. | |
486efb2e | 401 | */ |
db8e8f7d | 402 | public void putInt(int length, int value) throws CTFReaderException { |
4c67e724 | 403 | final long curPos = fPosition; |
486efb2e AM |
404 | |
405 | if (!canRead(length)) { | |
db8e8f7d AM |
406 | throw new CTFReaderException("Cannot write to bitbuffer, " //$NON-NLS-1$ |
407 | + "insufficient space. Requested: " + length); //$NON-NLS-1$ | |
486efb2e AM |
408 | } |
409 | if (length == 0) { | |
410 | return; | |
411 | } | |
4c67e724 | 412 | if (fByteOrder == ByteOrder.LITTLE_ENDIAN) { |
486efb2e AM |
413 | putIntLE(curPos, length, value); |
414 | } else { | |
415 | putIntBE(curPos, length, value); | |
416 | } | |
4c67e724 | 417 | fPosition += length; |
486efb2e AM |
418 | } |
419 | ||
47ca6c05 | 420 | private void putIntBE(long index, int length, int value) { |
486efb2e | 421 | assert ((length > 0) && (length <= BIT_INT)); |
47ca6c05 SM |
422 | long end = index + length; |
423 | int startByte = (int) (index / BIT_CHAR); | |
424 | int endByte = (int) ((end + (BIT_CHAR - 1)) / BIT_CHAR); | |
486efb2e AM |
425 | int currByte, lshift, cshift, mask, cmask; |
426 | int correctedValue = value; | |
427 | ||
428 | /* | |
429 | * mask v high bits. Works for unsigned and two complement signed | |
430 | * numbers which value do not overflow on length bits. | |
431 | */ | |
432 | ||
433 | if (length < BIT_INT) { | |
434 | correctedValue &= ~(~0 << length); | |
435 | } | |
436 | ||
437 | /* sub byte */ | |
438 | if (startByte == (endByte - 1)) { | |
47ca6c05 | 439 | lshift = (int) ((BIT_CHAR - (end % BIT_CHAR)) % BIT_CHAR); |
486efb2e AM |
440 | mask = ~((~0) << lshift); |
441 | if ((index % BIT_CHAR) > 0) { | |
442 | mask |= (~(0)) << (BIT_CHAR - (index % BIT_CHAR)); | |
443 | } | |
444 | cmask = correctedValue << lshift; | |
445 | /* | |
74e4b6b9 EB |
446 | * low bits are cleared because of left-shift and high bits are |
447 | * already cleared | |
486efb2e AM |
448 | */ |
449 | cmask &= ~mask; | |
4c67e724 MK |
450 | int b = fBuffer.get(startByte) & 0xFF; |
451 | fBuffer.put(startByte, (byte) ((b & mask) | cmask)); | |
486efb2e AM |
452 | return; |
453 | } | |
454 | ||
455 | /* head byte contains MSB */ | |
456 | currByte = endByte - 1; | |
47ca6c05 | 457 | cshift = (int) (end % BIT_CHAR); |
486efb2e AM |
458 | if (cshift > 0) { |
459 | lshift = BIT_CHAR - cshift; | |
460 | mask = ~((~0) << lshift); | |
461 | cmask = correctedValue << lshift; | |
462 | cmask &= ~mask; | |
4c67e724 MK |
463 | int b = fBuffer.get(currByte) & 0xFF; |
464 | fBuffer.put(currByte, (byte) ((b & mask) | cmask)); | |
486efb2e | 465 | correctedValue >>>= cshift; |
486efb2e AM |
466 | currByte--; |
467 | } | |
468 | ||
469 | /* middle byte(s) */ | |
470 | for (; currByte >= (startByte + 1); currByte--) { | |
4c67e724 | 471 | fBuffer.put(currByte, (byte) correctedValue); |
486efb2e AM |
472 | correctedValue >>>= BIT_CHAR; |
473 | } | |
474 | /* end byte contains LSB */ | |
475 | if ((index % BIT_CHAR) > 0) { | |
476 | mask = (~0) << (BIT_CHAR - (index % BIT_CHAR)); | |
477 | cmask = correctedValue & ~mask; | |
4c67e724 MK |
478 | int b = fBuffer.get(currByte) & 0xFF; |
479 | fBuffer.put(currByte, (byte) ((b & mask) | cmask)); | |
486efb2e | 480 | } else { |
4c67e724 | 481 | fBuffer.put(currByte, (byte) correctedValue); |
486efb2e AM |
482 | } |
483 | } | |
484 | ||
47ca6c05 | 485 | private void putIntLE(long index, int length, int value) { |
486efb2e | 486 | assert ((length > 0) && (length <= BIT_INT)); |
47ca6c05 SM |
487 | long end = index + length; |
488 | int startByte = (int) (index / BIT_CHAR); | |
489 | int endByte = (int) ((end + (BIT_CHAR - 1)) / BIT_CHAR); | |
486efb2e AM |
490 | int currByte, lshift, cshift, mask, cmask; |
491 | int correctedValue = value; | |
492 | ||
493 | /* | |
494 | * mask v high bits. Works for unsigned and two complement signed | |
495 | * numbers which value do not overflow on length bits. | |
496 | */ | |
497 | ||
498 | if (length < BIT_INT) { | |
499 | correctedValue &= ~(~0 << length); | |
500 | } | |
501 | ||
502 | /* sub byte */ | |
503 | if (startByte == (endByte - 1)) { | |
47ca6c05 | 504 | lshift = (int) (index % BIT_CHAR); |
486efb2e AM |
505 | mask = ~((~0) << lshift); |
506 | if ((end % BIT_CHAR) > 0) { | |
507 | mask |= (~(0)) << (end % BIT_CHAR); | |
508 | } | |
509 | cmask = correctedValue << lshift; | |
510 | /* | |
74e4b6b9 EB |
511 | * low bits are cleared because of left-shift and high bits are |
512 | * already cleared | |
486efb2e AM |
513 | */ |
514 | cmask &= ~mask; | |
4c67e724 MK |
515 | int b = fBuffer.get(startByte) & 0xFF; |
516 | fBuffer.put(startByte, (byte) ((b & mask) | cmask)); | |
486efb2e AM |
517 | return; |
518 | } | |
519 | ||
520 | /* head byte */ | |
521 | currByte = startByte; | |
47ca6c05 | 522 | cshift = (int) (index % BIT_CHAR); |
486efb2e AM |
523 | if (cshift > 0) { |
524 | mask = ~((~0) << cshift); | |
525 | cmask = correctedValue << cshift; | |
526 | cmask &= ~mask; | |
4c67e724 MK |
527 | int b = fBuffer.get(currByte) & 0xFF; |
528 | fBuffer.put(currByte, (byte) ((b & mask) | cmask)); | |
486efb2e | 529 | correctedValue >>>= BIT_CHAR - cshift; |
486efb2e AM |
530 | currByte++; |
531 | } | |
532 | ||
533 | /* middle byte(s) */ | |
534 | for (; currByte < (endByte - 1); currByte++) { | |
4c67e724 | 535 | fBuffer.put(currByte, (byte) correctedValue); |
486efb2e AM |
536 | correctedValue >>>= BIT_CHAR; |
537 | } | |
538 | /* end byte */ | |
539 | if ((end % BIT_CHAR) > 0) { | |
540 | mask = (~0) << (end % BIT_CHAR); | |
541 | cmask = correctedValue & ~mask; | |
4c67e724 MK |
542 | int b = fBuffer.get(currByte) & 0xFF; |
543 | fBuffer.put(currByte, (byte) ((b & mask) | cmask)); | |
486efb2e | 544 | } else { |
4c67e724 | 545 | fBuffer.put(currByte, (byte) correctedValue); |
486efb2e AM |
546 | } |
547 | } | |
548 | ||
549 | // ------------------------------------------------------------------------ | |
550 | // Buffer attributes handling | |
551 | // ------------------------------------------------------------------------ | |
552 | ||
553 | /** | |
554 | * Can this buffer be read for thus amount of bits? | |
555 | * | |
556 | * @param length | |
557 | * the length in bits to read | |
558 | * @return does the buffer have enough room to read the next "length" | |
559 | */ | |
560 | public boolean canRead(int length) { | |
4c67e724 | 561 | if (fBuffer == null) { |
486efb2e AM |
562 | return false; |
563 | } | |
564 | ||
4c67e724 | 565 | if ((fPosition + length) > (((long) fBuffer.capacity()) * BIT_CHAR)) { |
486efb2e AM |
566 | return false; |
567 | } | |
568 | return true; | |
569 | } | |
570 | ||
571 | /** | |
572 | * Sets the order of the buffer. | |
573 | * | |
574 | * @param order | |
575 | * The order of the buffer. | |
576 | */ | |
577 | public void setByteOrder(ByteOrder order) { | |
4c67e724 MK |
578 | fByteOrder = order; |
579 | if (fBuffer != null) { | |
580 | fBuffer.order(order); | |
486efb2e AM |
581 | } |
582 | } | |
583 | ||
584 | /** | |
585 | * Sets the order of the buffer. | |
586 | * | |
587 | * @return The order of the buffer. | |
588 | */ | |
589 | public ByteOrder getByteOrder() { | |
4c67e724 | 590 | return fByteOrder; |
486efb2e AM |
591 | } |
592 | ||
593 | /** | |
594 | * Sets the position in the buffer. | |
595 | * | |
596 | * @param newPosition | |
597 | * The new position of the buffer. | |
4c67e724 MK |
598 | * @throws CTFReaderException |
599 | * Thrown on out of bounds exceptions | |
c4767854 | 600 | * @since 3.0 |
486efb2e | 601 | */ |
4c67e724 MK |
602 | public void position(long newPosition) throws CTFReaderException { |
603 | ||
604 | if ((fBuffer != null) && (newPosition / 8) > fBuffer.capacity()) { | |
605 | throw new CTFReaderException("Out of bounds exception on a position move, attempting to access position: " + newPosition); //$NON-NLS-1$ | |
606 | } | |
607 | fPosition = newPosition; | |
486efb2e AM |
608 | } |
609 | ||
610 | /** | |
611 | * | |
612 | * Sets the position in the buffer. | |
613 | * | |
614 | * @return order The position of the buffer. | |
c4767854 | 615 | * @since 3.0 |
486efb2e | 616 | */ |
47ca6c05 | 617 | public long position() { |
4c67e724 | 618 | return fPosition; |
486efb2e AM |
619 | } |
620 | ||
621 | /** | |
622 | * Sets the byte buffer | |
623 | * | |
624 | * @param buf | |
625 | * the byte buffer | |
626 | */ | |
627 | public void setByteBuffer(ByteBuffer buf) { | |
4c67e724 | 628 | fBuffer = buf; |
486efb2e | 629 | if (buf != null) { |
4c67e724 | 630 | fBuffer.order(fByteOrder); |
486efb2e AM |
631 | } |
632 | clear(); | |
633 | } | |
634 | ||
635 | /** | |
636 | * Gets the byte buffer | |
637 | * | |
638 | * @return The byte buffer | |
639 | */ | |
640 | public ByteBuffer getByteBuffer() { | |
4c67e724 | 641 | return fBuffer; |
486efb2e AM |
642 | } |
643 | ||
644 | /** | |
74e4b6b9 | 645 | * Resets the bitbuffer. |
486efb2e AM |
646 | */ |
647 | public void clear() { | |
4c67e724 MK |
648 | resetPosition(); |
649 | if (fBuffer == null) { | |
486efb2e AM |
650 | return; |
651 | } | |
4c67e724 | 652 | fBuffer.clear(); |
486efb2e AM |
653 | } |
654 | ||
655 | } |