btf: Initial Best Trace Format commit
[deliverable/tracecompass.git] / org.eclipse.linuxtools.ctf.core / src / org / eclipse / linuxtools / ctf / core / event / io / BitBuffer.java
CommitLineData
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
16package org.eclipse.linuxtools.ctf.core.event.io;
17
486efb2e
AM
18import java.nio.ByteBuffer;
19import java.nio.ByteOrder;
20
db8e8f7d
AM
21import 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 30public 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}
This page took 0.064352 seconds and 5 git commands to generate.