View Javadoc
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 }