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 }