1 package nl.tno.imb;
2
3 // TODO: add Google protocol buffers implementation
4 // TODO: starting Java 1.7 the DirectByteBuffer seems quick enough, for now implement own buffer (backwards compatible <= 1.6)
5
6 import java.nio.charset.Charset;
7 import java.util.Arrays;
8
9 /**General buffer for use within the IMB framework to standardize byte order and data exchange.<br>
10 * IMB is always little-endian within the framework (and over the network).
11 * IMB defines the following types: byte, boolean, int32, int64, single, double, string.
12 * string is defined as a byte array with UTF-8 characters prefixed with length as int32.<br>
13 * Class is to be extended with Google Protocol Buffers to store data compressed and compatible with Protocol Buffers.<br>
14 * Standard Java ByteBuffers are not used because of performance issues.<br>
15 * Java 1.7 defines DirectByteBuffer which looks promising but for now is not widely used.<br>
16 * All reads advance the read cursor. All qreads advance the read cursor and read without any checking.
17 * All writes advance the write cursor. All qwrites advance the write cursor and write without any checking.
18 * All prepares advance the prepare cursor.<br>
19 * Prepares are to be used to optimize the buffer memory allocations.
20 * prepareApply closes the prepares and allocates the newly needed buffer size.
21 * @author hans.cornelissen@tno.nl
22 */
23 public class TByteBuffer {
24
25 // constructors
26
27 /**Constructor: create byte buffer of the specified length
28 * @param aLength length in bytes of the buffer to create
29 */
30 public TByteBuffer(int aLength) {
31 this.fBuffer = new byte[aLength];
32 }
33
34 /**Constructor: create empty byte buffer
35 */
36 public TByteBuffer() {
37 this.fBuffer = new byte[0];
38 }
39
40 /**Constructor: create byte buffer as copy of the specified byte array
41 * @param aBuffer
42 */
43 public TByteBuffer(byte[] aBuffer) {
44 this.fBuffer = aBuffer;
45 }
46
47 private byte[] fBuffer = null;
48 private int fReadCursor = 0;
49 private int fWriteCursor = 0;
50 private int fPrepareCursor = 0;
51
52 /**length of the byte buffer in bytes
53 * @return length of the allocated buffer in bytes
54 */
55 public int getLength() {
56 return this.fBuffer.length;
57 }
58
59 /**adjust the length of the buffer retaining buffer contents (less when new size is less)
60 * @param aLength new size of buffer in bytes
61 */
62 private void setLength(int aLength) {
63 if (aLength != this.fBuffer.length) {
64 // create new buffer
65 byte[] NewBuffer = new byte[aLength];
66 // check how much data to copy from old buffer
67 int len = this.fBuffer.length;
68 if (len > aLength)
69 len = aLength;
70 // copy old data to new buffer
71 for (int i = 0; i < len; i++)
72 NewBuffer[i] = this.fBuffer[i];
73 this.fBuffer = NewBuffer;
74 }
75 }
76
77 // uncompressed size of variables within the framework
78 /**uncompressed size of boolean within IMB framework */
79 public static final int SIZE_OF_BOOLEAN = Byte.SIZE/8;
80 /**uncompressed size of byte within IMB framework */
81 public static final int SIZE_OF_BYTE = Byte.SIZE/8;
82 /**uncompressed size of 32 bit integer within IMB framework */
83 public static final int SIZE_OF_INT32 = Integer.SIZE/8;
84 /**uncompressed size of 64 bit integer within IMB framework */
85 public static final int SIZE_OF_INT64 = Long.SIZE/8;
86 /**uncompressed size of single within IMB framework */
87 public static final int SIZE_OF_SINGLE = Float.SIZE/8;
88 /**uncompressed size of double within IMB framework */
89 public static final int SIZE_OF_DOUBLE = Double.SIZE/8;
90
91 /**Retrieve reference to internal byte buffer
92 * @return reference to internal byte buffer
93 */
94 public byte[] getBuffer() {
95 return this.fBuffer;
96 }
97
98 /**Clear the byte buffer to zero length and reset all cursors*/
99 public void clear() {
100 setLength(0);
101 this.fReadCursor = 0;
102 this.fPrepareCursor = 0;
103 this.fWriteCursor = 0;
104 }
105
106 /**Clear the byte buffer to the specified length and reset all cursors.*/
107 public void clear(int aLength) {
108 setLength(aLength);
109 this.fReadCursor = 0;
110 this.fWriteCursor = 0;
111 this.fPrepareCursor = 0;
112 }
113
114 /**Check if the byte buffer is empty
115 * @return true if the byte buffer is empty
116 */
117 public boolean isEmpty() {
118 return this.fBuffer.length == 0;
119 }
120
121 /**Retrieve the current reading (cursor) position
122 * @return cursor position for reading: index into byte buffer in bytes starting at 0
123 */
124 public int getReadCursor() {
125 return this.fReadCursor;
126 }
127
128 /**Retrieve the current writing (cursor) position
129 * @return cursor position for writing: index into byte buffer in bytes starting at 0
130 */
131 public int getWriteCursor() {
132 return this.fWriteCursor;
133 }
134
135 /**Reset the reading cursor*/
136 public void ReadStart() {
137 this.fReadCursor = 0;
138 }
139
140 /**Retrieve the bytes that still can be read from the byte buffer
141 * @return bytes available for reading
142 */
143 public int getReadAvailable() {
144 return this.fBuffer.length - this.fReadCursor;
145 }
146
147 /**Read a boolean from the byte buffer
148 * @return boolean read from byte buffer (default is false)
149 */
150 public boolean readBoolean() {
151 return readBoolean(false);
152 }
153
154 /**Read a boolean from the byte buffer
155 * @param aDefaultValue in case of a read error this value is returned
156 * @return boolean read from byte buffer
157 */
158 public boolean readBoolean(boolean aDefaultValue) {
159 if (SIZE_OF_BOOLEAN <= getReadAvailable())
160 return this.fBuffer[this.fReadCursor++] != 0;
161 else
162 return aDefaultValue;
163 }
164
165 /**Read a byte from the byte buffer
166 * @return byte read from the byte buffer
167 */
168 public byte readByte() {
169 return readByte((byte) 0);
170 }
171
172 /**Read a byte from the byte buffer
173 * @param aDefaultValue in case of a read error this value is returned
174 * @return byte read from the byte buffer
175 */
176 public byte readByte(byte aDefaultValue) {
177 if (SIZE_OF_BYTE <= getReadAvailable())
178 return this.fBuffer[this.fReadCursor++];
179 else
180 return aDefaultValue;
181 }
182
183 /**Read an integer (32 bit) from the byte buffer
184 * @return integer (32 bit) read from the byte buffer
185 */
186 public int readInt32() {
187 return readInt32(0);
188 }
189
190 /**Read an integer (32 bit) from the byte buffer
191 * @param aDefaultValue in case of a read error this value is returned
192 * @return integer (32 bit) read from the byte buffer
193 */
194 public int readInt32(int aDefaultValue) {
195 if (SIZE_OF_INT32 <= getReadAvailable()) {
196 this.fReadCursor += SIZE_OF_INT32;
197 return (int)(this.fBuffer[this.fReadCursor - 4] & 0xFF)
198 + ((int)(this.fBuffer[this.fReadCursor - 3] & 0xFF) << 8)
199 + ((int)(this.fBuffer[this.fReadCursor - 2] & 0xFF) << 16)
200 + ((int)(this.fBuffer[this.fReadCursor - 1] & 0xFF) << 24);
201 } else
202 return aDefaultValue;
203 }
204
205 /**Read an integer (64 bit) from the byte buffer
206 * @return integer (64 bit) read from the byte buffer
207 */
208 public long readInt64() {
209 return readInt64(0);
210 }
211
212 /**Read an integer (64 bit) from the byte buffer
213 * @param aDefaultValue in case of a read error this value is returned
214 * @return integer (64 bit) read from the byte buffer
215 */
216 public long readInt64(long aDefaultValue) {
217 if (SIZE_OF_INT64 <= getReadAvailable()) {
218 this.fReadCursor += SIZE_OF_INT64;
219 return (long)(this.fBuffer[this.fReadCursor - 8] & 0xFF)
220 + ((long)(this.fBuffer[this.fReadCursor - 7] & 0xFF) << 8)
221 + ((long)(this.fBuffer[this.fReadCursor - 6] & 0xFF) << 16)
222 + ((long)(this.fBuffer[this.fReadCursor - 5] & 0xFF) << 24)
223 + ((long)(this.fBuffer[this.fReadCursor - 4] & 0xFF) << 32)
224 + ((long)(this.fBuffer[this.fReadCursor - 3] & 0xFF) << 40)
225 + ((long)(this.fBuffer[this.fReadCursor - 2] & 0xFF) << 48)
226 + ((long)(this.fBuffer[this.fReadCursor - 1] & 0xFF) << 56);
227 } else
228 return aDefaultValue;
229 }
230
231 /**Read a single float from the byte buffer
232 * @return single float read from the byte buffer
233 */
234 public float readSingle() {
235 return readSingle(Float.NaN);
236 }
237
238 /**Read a single float from the byte buffer
239 * @param aDefaultValue in case of a read error this value is returned
240 * @return single float read from the byte buffer
241 */
242 public float readSingle(float aDefaultValue) {
243 if (SIZE_OF_SINGLE <= getReadAvailable()) {
244 return Float.intBitsToFloat(readInt32(0));
245 } else
246 return aDefaultValue;
247 }
248
249 /**Read a double float from the byte buffer
250 * @return double float read from the byte buffer
251 */
252 public double readDouble() {
253 return readDouble(Double.NaN);
254 }
255
256 /**Read a double float from the byte buffer
257 * @param aDefaultValue in case of a read error this value is returned
258 * @return double float read from the byte buffer
259 */
260 public double readDouble(double aDefaultValue) {
261 if (SIZE_OF_DOUBLE <= getReadAvailable()) {
262 long res = readInt64(0);
263 return Double.longBitsToDouble(res);
264 } else
265 return aDefaultValue;
266 }
267
268 /**Read a string from the byte buffer.
269 * The string is converted from UTF-8 to a standard string.
270 * @return the string read from the byte buffer
271 */
272 public String readString() {
273 return readString("");
274 }
275
276 /**Read a string from the byte buffer.
277 * The string is converted from UTF-8 to a standard string.
278 * @param aDefaultValue in case of a read error this value is returned
279 * @return the string read from the byte buffer
280 */
281 public String readString(String aDefaultValue) {
282 int len = readInt32(-1);
283 if ((len != -1) && (len <= getReadAvailable())) {
284 if (len > 0) {
285 this.fReadCursor += len;
286 return new String(this.fBuffer, this.fReadCursor - len, len, Charset.forName("UTF-8"));
287 } else
288 return "";
289 } else
290 return aDefaultValue;
291 }
292
293 // read size and data and store as a whole WITHOUT size (size=length buffer)
294
295 /**Read new byte buffer contents from this byte buffer.
296 * Decode a size prefixed number of bytes from the byte buffer into a newly created byte buffer.
297 * The size part is not transfered to the new byte buffer but used as the length.
298 * @return a new byte buffer containing the data read from this byte buffer
299 */
300 public TByteBuffer readByteBuffer() {
301 int len = readInt32(-1);
302 if ((len != -1) && (len <= getReadAvailable())) {
303 this.fReadCursor += len;
304 return new TByteBuffer(Arrays.copyOfRange(this.fBuffer, this.fReadCursor - len, this.fReadCursor));
305 } else
306 return null;
307 }
308
309 // class version of simple read functions (auto type detect by overloading)
310
311 /**Read a Boolean object from the this byte buffer.
312 * @param aValue the Boolean to be read from this byte buffer
313 * @throws IndexOutOfBoundsException when the value could not be read from this byte buffer
314 */
315 // public void read(Boolean aValue) throws IndexOutOfBoundsException {
316 // if (getReadAvailable() < SIZE_OF_BOOLEAN)
317 // throw new IndexOutOfBoundsException();
318 // aValue = fBuffer[fReadCursor++] != 0;
319 // }
320
321 /**Read a Byte object from the this byte buffer.
322 * @param aValue the Byte to be read from this byte buffer
323 * @throws IndexOutOfBoundsException when the value could not be read from this byte buffer
324 */
325 // public void read(Byte aValue) throws IndexOutOfBoundsException {
326 // if (getReadAvailable() < SIZE_OF_BYTE)
327 // throw new IndexOutOfBoundsException();
328 // aValue = fBuffer[fReadCursor++];
329 // }
330
331 /**Read an Integer object from the this byte buffer.
332 * @param aValue the Integer to be read from this byte buffer
333 * @throws IndexOutOfBoundsException when the value could not be read from this byte buffer
334 */
335 // public void read(Integer aValue) throws IndexOutOfBoundsException {
336 // if (getReadAvailable() < SIZE_OF_INT32)
337 // throw new IndexOutOfBoundsException();
338 // fReadCursor += SIZE_OF_INT32;
339 // aValue = (fBuffer[fReadCursor - 4] & 0xFF) + ((fBuffer[fReadCursor - 3] & 0xFF) << 8)
340 // + ((fBuffer[fReadCursor - 2] & 0xFF) << 16) + ((fBuffer[fReadCursor - 1] & 0xFF) << 24);
341 // }
342
343 /**Read a Long object from the this byte buffer.
344 * @param aValue the Long to be read from this byte buffer
345 * @throws IndexOutOfBoundsException when the value could not be read from this byte buffer
346 */
347 // public void read(Long aValue) throws IndexOutOfBoundsException {
348 // if (getReadAvailable() < SIZE_OF_INT64)
349 // throw new IndexOutOfBoundsException();
350 // fReadCursor += SIZE_OF_INT64;
351 // aValue = (long)(fBuffer[fReadCursor - 8] & 0xFF) + ((fBuffer[fReadCursor - 7] & 0xFF) << 8)
352 // + ((fBuffer[fReadCursor - 6] & 0xFF) << 16) + ((fBuffer[fReadCursor - 5] & 0xFF) << 24)
353 // + ((fBuffer[fReadCursor - 4] & 0xFF) << 32) + ((fBuffer[fReadCursor - 3] & 0xFF) << 40)
354 // + ((fBuffer[fReadCursor - 2] & 0xFF) << 48) + ((fBuffer[fReadCursor - 1] & 0xFF) << 56);
355 // }
356
357 /**Read a Float object from the this byte buffer.
358 * @param aValue the Float to be read from this byte buffer
359 * @throws IndexOutOfBoundsException when the value could not be read from this byte buffer
360 */
361 // public void read(Float aValue) throws IndexOutOfBoundsException {
362 // if (getReadAvailable() < SIZE_OF_SINGLE)
363 // throw new IndexOutOfBoundsException();
364 // aValue = Float.intBitsToFloat(readInt32(0));
365 // }
366
367 /**Read a Double object from the this byte buffer.
368 * @param aValue the Double to be read from this byte buffer
369 * @throws IndexOutOfBoundsException when the value could not be read from this byte buffer
370 */
371 // public void read(Double aValue) throws IndexOutOfBoundsException {
372 // if (getReadAvailable() < SIZE_OF_DOUBLE)
373 // throw new IndexOutOfBoundsException();
374 // aValue = Double.longBitsToDouble(readInt64(0));
375 // }
376
377 /**Read a String object from the this byte buffer.
378 * @param aValue the String to be read from this byte buffer
379 * @throws IndexOutOfBoundsException when the value could not be read from this byte buffer
380 */
381 // public void read(String aValue) throws IndexOutOfBoundsException {
382 // Integer len = new Integer(0);
383 // read(len);
384 // if (len > 0)
385 // {
386 // if (getReadAvailable() < len)
387 // throw new IndexOutOfBoundsException();
388 // fReadCursor += len;
389 // aValue = new String(fBuffer, fReadCursor - len, len, Charset.forName("UTF-8"));
390 // }
391 // else
392 // aValue = "";
393 // }
394
395 /**Read size and data and store as a whole WITHOUT size (size=length buffer)
396 * @param aValue byte buffer to store the read data in
397 */
398 public void readByteBuffer(TByteBuffer aValue) {
399 Integer len = new Integer(0);
400 len = readInt32();
401 if (len > 0)
402 {
403 aValue.setLength(len);
404 this.fReadCursor += len;
405 for (int i=0; i<len; i++)
406 aValue.fBuffer[i] = this.fBuffer[this.fReadCursor+i];
407 }
408 else
409 aValue.clear();
410 }
411
412 // QRead (no checking)
413 // Read a boolean from the byte buffer aDefaultValue in case of a read error this value is returned return boolean read from byte buffer
414
415 /**Read a boolean from the byte buffer without any checks
416 * @return the boolean read from the byte buffer
417 */
418 public boolean qReadBoolean() {
419 return this.fBuffer[this.fReadCursor++] != 0;
420 }
421
422 /**Read a byte from the byte buffer without any checks
423 * @return the byte read from the byte buffer
424 */
425 public byte qReadByte() {
426 return this.fBuffer[this.fReadCursor++];
427 }
428
429 /**Read an 32 bit integer from the byte buffer without any checks
430 * @return the 32 bit integer read from the byte buffer
431 */
432 public int qReadInt32() {
433 this.fReadCursor += SIZE_OF_INT32;
434 return (int)(this.fBuffer[this.fReadCursor - 4] & 0xFF)
435 + ((int)(this.fBuffer[this.fReadCursor - 3] & 0xFF) << 8)
436 + ((int)(this.fBuffer[this.fReadCursor - 1] & 0xFF) << 16)
437 + ((int)(this.fBuffer[this.fReadCursor - 1] & 0xFF) << 24);
438 }
439
440 /**Read an 64 bit integer from the byte buffer without any checks
441 * @return the 64 bit integer read from the byte buffer
442 */
443 public long qReadInt64() {
444 this.fReadCursor += SIZE_OF_INT64;
445 return (long)(this.fBuffer[this.fReadCursor - 8] & 0xFF)
446 + ((long)(this.fBuffer[this.fReadCursor - 7] & 0xFF) << 8)
447 + ((long)(this.fBuffer[this.fReadCursor - 6] & 0xFF) << 16)
448 + ((long)(this.fBuffer[this.fReadCursor - 5] & 0xFF) << 24)
449 + ((long)(this.fBuffer[this.fReadCursor - 4] & 0xFF) << 32)
450 + ((long)(this.fBuffer[this.fReadCursor - 3] & 0xFF) << 40)
451 + ((long)(this.fBuffer[this.fReadCursor - 2] & 0xFF) << 48)
452 + ((long)(this.fBuffer[this.fReadCursor - 1] & 0xFF) << 56);
453 }
454
455 /**Read a single (32 bit float) from the byte buffer without any checks
456 * @return the single (32 bit float) read from the byte buffer
457 */
458 public float qReadSingle() {
459 // size of float = size of int (int32)
460 return Float.intBitsToFloat(readInt32(0));
461 }
462
463 /**Read a double from the byte buffer without any checks
464 * @return the double read from the byte buffer
465 */
466 public double qReadDouble(double aDefaultValue) {
467 // size of double = size of long (int64)
468 return Double.longBitsToDouble(readInt64(0));
469 }
470
471 /**Read a string from the byte buffer without any checks
472 * @return the string read from the byte buffer
473 */
474 public String qReadString(String aDefaultValue) {
475 int len = qReadInt32();
476 if (len > 0) {
477 this.fReadCursor += len;
478 return new String(this.fBuffer, this.fReadCursor - len, len, Charset.forName("UTF-8"));
479 } else
480 return "";
481 }
482
483 /**Read a byte buffer this byte buffer without any checks
484 * Read size and data and store as a whole WITHOUT size (size=length buffer)
485 * @return the new byte buffer read from the byte buffer
486 */
487 public TByteBuffer qReadByteBuffer() {
488 int len = qReadInt32();
489 this.fReadCursor += len;
490 return new TByteBuffer(Arrays.copyOfRange(this.fBuffer, this.fReadCursor - len, this.fReadCursor));
491 }
492
493 /**Read all data available from the read cursor in this byte buffer to a newly created byte buffer
494 * @return a newly created byte buffer that contains all data read
495 */
496 public TByteBuffer readRestToByteBuffer() {
497 return new TByteBuffer(readRest());
498 }
499
500 /**Read all data available from the read cursor
501 * @return a byte array containing all data read
502 */
503 public byte[] readRest() {
504 return Arrays.copyOfRange(this.fBuffer, this.fReadCursor, this.fReadCursor + getReadAvailable());
505 }
506
507 /**Skip the specified amount of bytes for reading
508 * Advances the read cursor the specified amount of bytes
509 * @param aValueSize number of bytes to skip for reading
510 */
511 public void skipReading(int aValueSize) {
512 this.fReadCursor += aValueSize;
513 }
514
515 // peek type result
516 /**Read a boolean from the byte buffer at an offset to the read cursor without advancing the read cursor.
517 * If the value could not be read the default 'false' is returned.
518 * @param aOffset 0-based offset to the read cursor to peek at for the boolean
519 * @return the value read from the byte buffer at the specified offset
520 */
521 public boolean peekBoolean(int aOffset) {
522 return peekBoolean(aOffset, false);
523 }
524
525 /**Read a boolean from the byte buffer at an offset to the read cursor without advancing the read cursor.
526 * @param aOffset 0-based offset to the read cursor to peek at for the boolean
527 * @param aDefaultValue if the value could not be read this default is returned
528 * @return the value read from the byte buffer at the specified offset
529 */
530 public boolean peekBoolean(int aOffset, boolean aDefaultValue) {
531 if (SIZE_OF_BOOLEAN + aOffset <= getReadAvailable())
532 return this.fBuffer[this.fReadCursor + aOffset] != 0;
533 else
534 return aDefaultValue;
535 }
536
537 /**Read a byte from the byte buffer at an offset to the read cursor without advancing the read cursor.
538 * If the value could not be read the default '0' is returned.
539 * @param aOffset 0-based offset to the read cursor to peek at for the byte
540 * @return the value read from the byte buffer at the specified offset
541 */
542 public byte peekByte(int aOffset) {
543 return peekByte(aOffset, (byte) 0);
544 }
545
546 /**Read a byte from the byte buffer at an offset to the read cursor without advancing the read cursor.
547 * @param aOffset 0-based offset to the read cursor to peek at for the byte
548 * @param aDefaultValue if the value could not be read this default is returned
549 * @return the value read from the byte buffer at the specified offset
550 */
551 public byte peekByte(int aOffset, byte aDefaultValue) {
552 if (SIZE_OF_BYTE + aOffset <= getReadAvailable())
553 return this.fBuffer[this.fReadCursor + aOffset];
554 else
555 return aDefaultValue;
556 }
557
558 /**Read an 32 bit integer from the byte buffer at an offset to the read cursor without advancing the read cursor.
559 * If the value could not be read the default '0' is returned.
560 * @param aOffset 0-based offset to the read cursor to peek at for the integer
561 * @return the value read from the byte buffer at the specified offset
562 */
563 public int peekInt32(int aOffset) {
564 return peekInt32(aOffset, 0);
565 }
566
567 /**Read an 32 bit integer from the byte buffer at an offset to the read cursor without advancing the read cursor.
568 * @param aOffset 0-based offset to the read cursor to peek at for the integer
569 * @param aDefaultValue if the value could not be read this default is returned
570 * @return the value read from the byte buffer at the specified offset
571 */
572 public int peekInt32(int aOffset, int aDefaultValue) {
573 if (SIZE_OF_INT32 + aOffset <= getReadAvailable()) {
574 return (int)(this.fBuffer[this.fReadCursor + aOffset] & 0xFF)
575 + ((int)(this.fBuffer[this.fReadCursor + aOffset + 1] & 0xFF) << 8)
576 + ((int)(this.fBuffer[this.fReadCursor + aOffset + 2] & 0xFF) << 16)
577 + ((int)(this.fBuffer[this.fReadCursor + aOffset + 3] & 0xFF) << 24);
578 } else
579 return aDefaultValue;
580 }
581
582 /**Read an 64 bit integer (long) from the byte buffer at an offset to the read cursor without advancing the read cursor.
583 * If the value could not be read the default '0' is returned.
584 * @param aOffset 0-based offset to the read cursor to peek at for the long
585 * @return the value read from the byte buffer at the specified offset
586 */
587 public long peekInt64(int aOffset) {
588 return peekInt64(aOffset, 0);
589 }
590
591 /**Read an 64 bit integer (long) from the byte buffer at an offset to the read cursor without advancing the read cursor.
592 * @param aOffset 0-based offset to the read cursor to peek at for the long
593 * @param aDefaultValue if the value could not be read this default is returned
594 * @return the value read from the byte buffer at the specified offset
595 */
596 public long peekInt64(int aOffset, long aDefaultValue) {
597 if (SIZE_OF_INT64 + aOffset <= getReadAvailable())
598 return (long)(this.fBuffer[this.fReadCursor + aOffset] & 0xFF)
599 + ((long)(this.fBuffer[this.fReadCursor + aOffset + 1] & 0xFF) << 8)
600 + ((long)(this.fBuffer[this.fReadCursor + aOffset + 2] & 0xFF) << 16)
601 + ((long)(this.fBuffer[this.fReadCursor + aOffset + 3] & 0xFF) << 24)
602 + ((long)(this.fBuffer[this.fReadCursor + aOffset + 4] & 0xFF) << 32)
603 + ((long)(this.fBuffer[this.fReadCursor + aOffset + 5] & 0xFF) << 40)
604 + ((long)(this.fBuffer[this.fReadCursor + aOffset + 6] & 0xFF) << 48)
605 + ((long)(this.fBuffer[this.fReadCursor + aOffset + 7] & 0xFF) << 56);
606 else
607 return aDefaultValue;
608 }
609
610 /**Read a single (32 bit float) from the byte buffer at an offset to the read cursor without advancing the read cursor.
611 * If the value could not be read the default 'NaN' is returned.
612 * @param aOffset 0-based offset to the read cursor to peek at for the float
613 * @return the value read from the byte buffer at the specified offset
614 */
615 public float peekSingle(int aOffset) {
616 return peekSingle(aOffset, Float.NaN);
617 }
618
619 /**Read a single (32 bit float) from the byte buffer at an offset to the read cursor without advancing the read cursor.
620 * @param aOffset 0-based offset to the read cursor to peek at for the float
621 * @param aDefaultValue if the value could not be read this default is returned
622 * @return the value read from the byte buffer at the specified offset
623 */
624 public float peekSingle(int aOffset, float aDefaultValue) {
625 if (SIZE_OF_SINGLE + aOffset <= getReadAvailable())
626 return Float.intBitsToFloat(peekInt32(aOffset, 0));
627 else
628 return aDefaultValue;
629 }
630
631 /**Read a double from the byte buffer at an offset to the read cursor without advancing the read cursor.
632 * If the value could not be read the default 'NaN' is returned.
633 * @param aOffset 0-based offset to the read cursor to peek at for the double
634 * @return the value read from the byte buffer at the specified offset
635 */
636 public double peekDouble(int aOffset) {
637 return peekDouble(aOffset, Double.NaN);
638 }
639
640 /**Read a double from the byte buffer at an offset to the read cursor without advancing the read cursor.
641 * @param aOffset 0-based offset to the read cursor to peek at for the double
642 * @param aDefaultValue if the value could not be read this default is returned
643 * @return the value read from the byte buffer at the specified offset
644 */
645 public double peekDouble(int aOffset, double aDefaultValue) {
646 if (SIZE_OF_DOUBLE + aOffset <= getReadAvailable())
647 return Double.longBitsToDouble(peekInt64(aOffset, 0));
648 else
649 return aDefaultValue;
650 }
651
652 /**Read a string from the byte buffer at an offset to the read cursor without advancing the read cursor.
653 * If the value could not be read the default "" is returned.
654 * @param aOffset 0-based offset to the read cursor to peek at for the string
655 * @return the value read from the byte buffer at the specified offset
656 */
657 public String peekString(int aOffset) {
658 return peekString(aOffset, "");
659 }
660
661 /**Read a string from the byte buffer at an offset to the read cursor without advancing the read cursor.
662 * @param aOffset 0-based offset to the read cursor to peek at for the string
663 * @param aDefaultValue if the value could not be read this default is returned
664 * @return the value read from the byte buffer at the specified offset
665 */
666 public String peekString(int aOffset, String aDefaultValue) {
667 int len = peekInt32(aOffset, -1);
668 if (len >= 0) {
669 if (len + aOffset <= getReadAvailable()) {
670 return new String(this.fBuffer, this.fReadCursor + aOffset, len, Charset.forName("UTF-8"));
671 } else
672 return aDefaultValue;
673 } else
674 return aDefaultValue;
675 }
676
677 /**Compare the contents of this byte buffer at the read cursor to a given byte array
678 * @param aValue byte array to compare with this byte buffer
679 * @param aOffset offset to the read cursor to start comparing
680 * @return if the byte buffer data equals the byte array contents true is returned
681 */
682 public boolean compare(byte[] aValue, int aOffset) {
683 if (aOffset + aValue.length <= getReadAvailable()) {
684 for (int i = 0; i < aValue.length; i++) {
685 if (this.fBuffer[aOffset + this.fReadCursor + i] != aValue[i])
686 return false;
687 }
688 return true;
689 } else
690 return false;
691 }
692
693 /**Shift all bytes in the byte buffer to the left and insert a new byte to the right (end of byte buffer)
694 * @param aRightByte the byte to insert at the right side of the byte buffer after the shift
695 */
696 public void shiftLeftOneByte(byte aRightByte) {
697 for (int i = 0; i < this.fBuffer.length - 1; i++)
698 this.fBuffer[i] = this.fBuffer[i + 1];
699 this.fBuffer[this.fBuffer.length - 1] = aRightByte;
700 }
701
702 /**Start prepare sequence. This should be called before prepare calls.
703 * Resets the prepare cursor to the current writing cursor position.
704 * @return the new prepare cursor position. This can be used to calls of writeStart to reuse a byte buffer with partial deviating data.
705 */
706 public int prepareStart() {
707 this.fPrepareCursor = this.fWriteCursor;
708 return this.fPrepareCursor;
709 }
710
711 /**Prepares the byte buffer for later writing of a boolean.
712 * Advances the prepare cursor for the correct amount of bytes to write a boolean.
713 * @param aValue the boolean to be written later in a call to qWrite
714 */
715 public void prepare(boolean aValue) {
716 this.fPrepareCursor += SIZE_OF_BOOLEAN;
717 }
718
719 /**Prepares the byte buffer for later writing of a byte.
720 * Advances the prepare cursor for the correct amount of bytes to write a byte.
721 * @param aValue the byte to be written later in a call to qWrite
722 */
723 public void prepare(byte aValue) {
724 this.fPrepareCursor += SIZE_OF_BYTE;
725 }
726
727 /**Prepares the byte buffer for later writing of an 32 bit integer.
728 * Advances the prepare cursor for the correct amount of bytes to write an 32 bit integer.
729 * @param aValue the 32 bit integer to be written later in a call to qWrite
730 */
731 public void prepare(int aValue) {
732 this.fPrepareCursor += SIZE_OF_INT32;
733 }
734
735 /**Prepares the byte buffer for later writing of an 64 bit integer (long).
736 * Advances the prepare cursor for the correct amount of bytes to write an 64 bit integer (long).
737 * @param aValue the 64 bit integer (long) to be written later in a call to qWrite
738 */
739 public void prepare(long aValue) {
740 this.fPrepareCursor += SIZE_OF_INT64;
741 }
742
743 /**Prepares the byte buffer for later writing of a 32 bit single (float).
744 * Advances the prepare cursor for the correct amount of bytes to write a 32 bit single (float).
745 * @param aValue the 32 bit single (float) to be written later in a call to qWrite
746 */
747 public void prepare(float aValue) {
748 this.fPrepareCursor += SIZE_OF_SINGLE;
749 }
750
751 /**Prepares the byte buffer for later writing of a double.
752 * Advances the prepare cursor for the correct amount of bytes to write a double.
753 * @param aValue the double to be written later in a call to qWrite
754 */
755 public void prepare(double aValue) {
756 this.fPrepareCursor += SIZE_OF_DOUBLE;
757 }
758
759 /**Prepares the byte buffer for later writing of a string.
760 * Advances the prepare cursor for the correct amount of bytes to write a string (including its size).
761 * @param aValue the string to be written later in a call to qWrite
762 */
763 public void prepare(String aValue) {
764 this.fPrepareCursor += SIZE_OF_INT32 + aValue.getBytes(Charset.forName("UTF-8")).length;
765 }
766
767 /**Prepares the byte buffer for later writing of a byte array (without size).
768 * Advances the prepare cursor for the correct amount of bytes to write a byte array (without size).
769 * @param aValue the byte array to be written later in a call to qWrite
770 */
771 public void prepare(byte[] aValue) {
772 this.fPrepareCursor += aValue.length;
773 }
774
775 /**Prepares the byte buffer for later writing of an other byte buffers readable data.
776 * Advances the prepare cursor for the correct amount of bytes to write a byte buffers readable data.
777 * @param aValue the byte buffers readable data to be written later in a call to qWrite
778 */
779 public void prepare(TByteBuffer aValue) {
780 this.fPrepareCursor += SIZE_OF_INT32 + aValue.getReadAvailable();
781 }
782
783 /**Prepares the byte buffer for later writing of the specified number of bytes.
784 * Advances the prepare cursor for the correct amount of bytes to write the specified number of bytes.
785 * @param aValueSize the number of bytes to be written later in a call to qWrite
786 */
787 public int prepareSize(int aValueSize) {
788 int res = this.fPrepareCursor;
789 this.fPrepareCursor += aValueSize;
790 return res;
791 }
792
793 /**Adjusts the length of the byte buffer to accommodate at a minimum all prepared data
794 */
795 public void prepareApply() {
796 if (this.fBuffer.length < this.fPrepareCursor)
797 setLength(this.fPrepareCursor);
798 }
799
800 /**Adjusts the length of the byte buffer to accommodate exactly all prepared data
801 */
802 public void prepareApplyAndTrim() {
803 if (this.fBuffer.length != this.fPrepareCursor)
804 setLength(this.fPrepareCursor);
805 }
806
807 /**Start writing at the specified 0-based index.
808 * Resets the write cursor to the specified 0-based index
809 * @param aIndex the new value for the write cursor
810 */
811 public void writeStart(int aIndex) {
812 this.fWriteCursor = aIndex;
813 }
814
815 /**Returns the room still available in the byte buffer to write data to without reallocating memory.
816 * @return the room still left in the byte buffer to write
817 */
818 public int getwriteAvailable() {
819 return this.fBuffer.length - this.fWriteCursor;
820 }
821
822 /**Write the specified boolean to the byte buffer.
823 * Buffer space is allocated if needed.
824 * @param aValue the boolean to be written to the byte buffer
825 */
826 public void write(boolean aValue) {
827 if (SIZE_OF_BOOLEAN > getwriteAvailable())
828 setLength(this.fWriteCursor + SIZE_OF_BOOLEAN);
829 this.fBuffer[this.fWriteCursor] = (aValue) ? (byte) -1 : (byte) 0;
830 this.fWriteCursor += SIZE_OF_BOOLEAN;
831 }
832
833 /**Write the specified byte to the byte buffer.
834 * Buffer space is allocated if needed.
835 * @param aValue the byte to be written to the byte buffer
836 */
837 public void write(byte aValue) {
838 if (SIZE_OF_BYTE > getwriteAvailable())
839 setLength(this.fWriteCursor + SIZE_OF_BYTE);
840 this.fBuffer[this.fWriteCursor] = aValue;
841 this.fWriteCursor += SIZE_OF_BYTE;
842 }
843
844 /**Write the specified 32 bit integer to the byte buffer.
845 * Buffer space is allocated if needed.
846 * @param aValue the 32 bit integer to be written to the byte buffer
847 */
848 public void write(int aValue) {
849 if (SIZE_OF_INT32 > getwriteAvailable())
850 setLength(this.fWriteCursor + SIZE_OF_INT32);
851 this.fBuffer[this.fWriteCursor] = (byte) (aValue & 0xFF);
852 this.fBuffer[this.fWriteCursor + 1] = (byte) ((aValue >> 8) & 0xFF);
853 this.fBuffer[this.fWriteCursor + 2] = (byte) ((aValue >> 16) & 0xFF);
854 this.fBuffer[this.fWriteCursor + 3] = (byte) ((aValue >> 24) & 0xFF);
855 this.fWriteCursor += SIZE_OF_INT32;
856 }
857
858 /**Write the specified 64 bit integer (long) to the byte buffer.
859 * Buffer space is allocated if needed.
860 * @param aValue the 64 bit integer (long) to be written to the byte buffer
861 */
862 public void write(long aValue) {
863 if (SIZE_OF_INT64 > getwriteAvailable())
864 setLength(this.fWriteCursor + SIZE_OF_INT64);
865 this.fBuffer[this.fWriteCursor] = (byte) (aValue & 0xFF);
866 this.fBuffer[this.fWriteCursor + 1] = (byte) ((aValue >> 8) & 0xFF);
867 this.fBuffer[this.fWriteCursor + 2] = (byte) ((aValue >> 16) & 0xFF);
868 this.fBuffer[this.fWriteCursor + 3] = (byte) ((aValue >> 24) & 0xFF);
869 this.fBuffer[this.fWriteCursor + 4] = (byte) ((aValue >> 32) & 0xFF);
870 this.fBuffer[this.fWriteCursor + 5] = (byte) ((aValue >> 40) & 0xFF);
871 this.fBuffer[this.fWriteCursor + 6] = (byte) ((aValue >> 48) & 0xFF);
872 this.fBuffer[this.fWriteCursor + 7] = (byte) ((aValue >> 56) & 0xFF);
873 this.fWriteCursor += SIZE_OF_INT64;
874 }
875
876 /**Write the specified single (float) to the byte buffer.
877 * Buffer space is allocated if needed.
878 * @param aValue the single (float) to be written to the byte buffer
879 */
880 public void write(float aValue) {
881 write(Float.floatToIntBits(aValue));
882 }
883
884 /**Write the specified double to the byte buffer.
885 * Buffer space is allocated if needed.
886 * @param aValue the double to be written to the byte buffer
887 */
888 public void write(double aValue) {
889 write(Double.doubleToLongBits(aValue));
890 }
891
892 /**Write the specified string to the byte buffer in UTF-8 format.
893 * Buffer space is allocated if needed.
894 * @param aValue the string to be written to the byte buffer
895 */
896 public void write(String aValue) {
897 byte[] s = aValue.getBytes(Charset.forName("UTF-8"));
898 int len = s.length;
899 if (SIZE_OF_INT32 + len > getwriteAvailable())
900 setLength(this.fWriteCursor + SIZE_OF_INT32 + len);
901 // first write size
902 write(len);
903 // write content
904 for (int i = 0; i < len; i++)
905 this.fBuffer[this.fWriteCursor + i] = s[i];
906 this.fWriteCursor += len;
907 }
908
909 /**Write the specified byte array WITHOUT the size to the byte buffer.
910 * Buffer space is allocated if needed.
911 * @param aValue the byte buffer to be written to the byte buffer
912 */
913 public void write(byte[] aValue) {
914 if (aValue.length > getwriteAvailable())
915 setLength(this.fWriteCursor + aValue.length);
916 for (int i = 0; i < aValue.length; i++)
917 this.fBuffer[this.fWriteCursor + i] = aValue[i];
918 this.fWriteCursor += aValue.length;
919 }
920
921 // write all readable data WITH size
922 /**Write the readable data in the specified byte buffer to this byte buffer.
923 * Buffer space is allocated if needed.
924 * @param aValue the byte buffer who's readable data is to be written to this byte buffer
925 */
926 public void write(TByteBuffer aValue) {
927 write(aValue.fBuffer.length);
928 write(aValue.fBuffer);
929 }
930
931 // QWrite (no room checking)
932
933 /**write a boolean to the buffer; the QWrite methods do not check for room in the buffer
934 * @param aValue the boolean value to be written to the buffer
935 */
936 public void qWrite(boolean aValue) {
937
938 this.fBuffer[this.fWriteCursor] = (aValue) ? (byte) -1 : (byte) 0;
939 this.fWriteCursor += SIZE_OF_BOOLEAN;
940 }
941
942 /**write a single byte to the buffer; the QWrite methods do not check for room in the buffer
943 * @param aValue the byte value to be written to the buffer
944 */
945 public void qWrite(byte aValue) {
946 this.fBuffer[this.fWriteCursor] = aValue;
947 this.fWriteCursor += SIZE_OF_BYTE;
948 }
949
950 /**write a single integer (32 bit) to the buffer; the QWrite methods do not check for room in the buffer
951 * @param aValue the integer (32 bit) value to be written to the buffer
952 */
953 public void qWrite(int aValue) {
954 this.fBuffer[this.fWriteCursor] = (byte) (aValue & 0xFF);
955 this.fBuffer[this.fWriteCursor + 1] = (byte) ((aValue >> 8) & 0xFF);
956 this.fBuffer[this.fWriteCursor + 2] = (byte) ((aValue >> 16) & 0xFF);
957 this.fBuffer[this.fWriteCursor + 3] = (byte) ((aValue >> 24) & 0xFF);
958 this.fWriteCursor += SIZE_OF_INT32;
959 }
960
961 /**write a single integer (64 bit) to the buffer; the QWrite methods do not check for room in the buffer
962 * @param aValue the integer (64 bit) value to be written to the buffer
963 */
964 public void qWrite(long aValue) {
965 this.fBuffer[this.fWriteCursor] = (byte) (aValue & 0xFF);
966 this.fBuffer[this.fWriteCursor + 1] = (byte) ((aValue >> 8) & 0xFF);
967 this.fBuffer[this.fWriteCursor + 2] = (byte) ((aValue >> 16) & 0xFF);
968 this.fBuffer[this.fWriteCursor + 3] = (byte) ((aValue >> 24) & 0xFF);
969 this.fBuffer[this.fWriteCursor + 4] = (byte) ((aValue >> 32) & 0xFF);
970 this.fBuffer[this.fWriteCursor + 5] = (byte) ((aValue >> 40) & 0xFF);
971 this.fBuffer[this.fWriteCursor + 6] = (byte) ((aValue >> 48) & 0xFF);
972 this.fBuffer[this.fWriteCursor + 7] = (byte) ((aValue >> 56) & 0xFF);
973 this.fWriteCursor += SIZE_OF_INT64;
974 }
975
976 /**write a single float (32 bit) to the buffer; the QWrite methods do not check for room in the buffer
977 * @param aValue the float (32 bit) value to be written to the buffer
978 */
979 public void qWrite(float aValue) {
980 qWrite(Float.floatToIntBits(aValue));
981 }
982
983 /**write a single double (64 bit) to the buffer; the QWrite methods do not check for room in the buffer
984 * @param aValue the float (64 bit) value to be written to the buffer
985 */
986 public void qWrite(double aValue) {
987 qWrite(Double.doubleToLongBits(aValue));
988 }
989
990 /**Write a string to the buffer, prefixed with the size as a 32 bit integer.
991 * The characters are UTF-8 encoded, every char is 1 byte in size
992 * The QWrite methods do not check for room in the buffer
993 * @param aValue the float (32 bit) value to be written to the buffer
994 */
995 public void qWrite(String aValue) {
996 byte[] s = aValue.getBytes(Charset.forName("UTF-8"));
997 int len = s.length;
998 // first write size
999 qWrite(len);
1000 // write content
1001 for (int i = 0; i < len; i++)
1002 this.fBuffer[this.fWriteCursor + i] = s[i];
1003 this.fWriteCursor += len;
1004 }
1005
1006 /**write array of byte WITHOUT size; the QWrite methods do not check for room in the buffer
1007 * @param aValue the byte array written to the buffer (without prefixed size)
1008 */
1009 public void qWrite(byte[] aValue) {
1010 for (int i = 0; i < aValue.length; i++)
1011 this.fBuffer[this.fWriteCursor + i] = aValue[i];
1012 this.fWriteCursor += aValue.length;
1013 }
1014
1015 /**write, with no checking, all readable data from the given byte buffer to this prefixed WITH size
1016 * @param aValue readable data in byte buffer to be written to the buffer
1017 */
1018 public void qWrite(TByteBuffer aValue) {
1019 qWrite(aValue.fBuffer.length);
1020 qWrite(aValue.fBuffer);
1021 }
1022
1023 /**signal number of bytes directly written to buffer without using class methods
1024 * update write cursor and return if it fitted into buffer (should trigger exception ?)
1025 * @param aValueSize number of bytes directly written into buffer
1026 * @return true if all written data fitted into buffer
1027 */
1028 public boolean written(int aValueSize) {
1029 this.fWriteCursor += aValueSize;
1030 return getwriteAvailable() >= 0;
1031 }
1032
1033 /**apply written data (trim extra buffer space)
1034 */
1035 public void writeApply() {
1036 if (this.fWriteCursor != this.fBuffer.length)
1037 setLength(this.fWriteCursor);
1038 }
1039 }