1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.wifi.aware; 18 19 import android.annotation.Nullable; 20 21 import java.nio.BufferOverflowException; 22 import java.nio.ByteOrder; 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.NoSuchElementException; 28 29 /** 30 * Utility class to construct and parse byte arrays using the TLV format - 31 * Type/Length/Value format. The utilities accept a configuration of the size of 32 * the Type field and the Length field. A Type field size of 0 is allowed - 33 * allowing usage for LV (no T) array formats. 34 * 35 * @hide 36 */ 37 public class TlvBufferUtils { TlvBufferUtils()38 private TlvBufferUtils() { 39 // no reason to ever create this class 40 } 41 42 /** 43 * Utility class to construct byte arrays using the TLV format - 44 * Type/Length/Value. 45 * <p> 46 * A constructor is created specifying the size of the Type (T) and Length 47 * (L) fields. A specification of zero size T field is allowed - resulting 48 * in LV type format. 49 * <p> 50 * The byte array is either provided (using 51 * {@link TlvConstructor#wrap(byte[])}) or allocated (using 52 * {@link TlvConstructor#allocate(int)}). 53 * <p> 54 * Values are added to the structure using the {@code TlvConstructor.put*()} 55 * methods. 56 * <p> 57 * The final byte array is obtained using {@link TlvConstructor#getArray()}. 58 */ 59 public static class TlvConstructor { 60 private int mTypeSize; 61 private int mLengthSize; 62 private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN; 63 64 private byte[] mArray; 65 private int mArrayLength; 66 private int mPosition; 67 68 /** 69 * Define a TLV constructor with the specified size of the Type (T) and 70 * Length (L) fields. 71 * 72 * @param typeSize Number of bytes used for the Type (T) field. Values 73 * of 0, 1, or 2 bytes are allowed. A specification of 0 74 * bytes implies that the field being constructed has the LV 75 * format rather than the TLV format. 76 * @param lengthSize Number of bytes used for the Length (L) field. 77 * Values of 1 or 2 bytes are allowed. 78 */ TlvConstructor(int typeSize, int lengthSize)79 public TlvConstructor(int typeSize, int lengthSize) { 80 if (typeSize < 0 || typeSize > 2 || lengthSize <= 0 || lengthSize > 2) { 81 throw new IllegalArgumentException( 82 "Invalid sizes - typeSize=" + typeSize + ", lengthSize=" + lengthSize); 83 } 84 mTypeSize = typeSize; 85 mLengthSize = lengthSize; 86 mPosition = 0; 87 } 88 89 /** 90 * Configure the TLV constructor to use a particular byte order. Should be 91 * {@link ByteOrder#BIG_ENDIAN} (the default at construction) or 92 * {@link ByteOrder#LITTLE_ENDIAN}. 93 * 94 * @return The constructor to facilitate chaining 95 * {@code ctr.putXXX(..).putXXX(..)}. 96 */ setByteOrder(ByteOrder byteOrder)97 public TlvConstructor setByteOrder(ByteOrder byteOrder) { 98 mByteOrder = byteOrder; 99 return this; 100 } 101 102 /** 103 * Set the byte array to be used to construct the TLV. 104 * 105 * @param array Byte array to be formatted. 106 * @return The constructor to facilitate chaining 107 * {@code ctr.putXXX(..).putXXX(..)}. 108 */ wrap(@ullable byte[] array)109 public TlvConstructor wrap(@Nullable byte[] array) { 110 mArray = array; 111 mArrayLength = (array == null) ? 0 : array.length; 112 mPosition = 0; 113 return this; 114 } 115 116 /** 117 * Allocates a new byte array to be used to construct a TLV. 118 * 119 * @param capacity The size of the byte array to be allocated. 120 * @return The constructor to facilitate chaining 121 * {@code ctr.putXXX(..).putXXX(..)}. 122 */ allocate(int capacity)123 public TlvConstructor allocate(int capacity) { 124 mArray = new byte[capacity]; 125 mArrayLength = capacity; 126 mPosition = 0; 127 return this; 128 } 129 130 /** 131 * Creates a TLV array (of the previously specified Type and Length sizes) from the input 132 * list. Allocates an array matching the contents (and required Type and Length 133 * fields), copies the contents, and set the Length fields. The Type field is set to 0. 134 * 135 * @param list A list of fields to be added to the TLV buffer. 136 * @return The constructor of the TLV. 137 */ allocateAndPut(@ullable List<byte[]> list)138 public TlvConstructor allocateAndPut(@Nullable List<byte[]> list) { 139 if (list != null) { 140 int size = 0; 141 for (byte[] field : list) { 142 size += mTypeSize + mLengthSize; 143 if (field != null) { 144 size += field.length; 145 } 146 } 147 allocate(size); 148 for (byte[] field : list) { 149 putByteArray(0, field); 150 } 151 } 152 return this; 153 } 154 155 /** 156 * Copies a byte into the TLV with the indicated type. For an LV 157 * formatted structure (i.e. typeLength=0 in {@link TlvConstructor 158 * TlvConstructor(int, int)} ) the type field is ignored. 159 * 160 * @param type The value to be placed into the Type field. 161 * @param b The byte to be inserted into the structure. 162 * @return The constructor to facilitate chaining 163 * {@code ctr.putXXX(..).putXXX(..)}. 164 */ putByte(int type, byte b)165 public TlvConstructor putByte(int type, byte b) { 166 checkLength(1); 167 addHeader(type, 1); 168 mArray[mPosition++] = b; 169 return this; 170 } 171 172 /** 173 * Copies a raw byte into the TLV buffer - without a type or a length. 174 * 175 * @param b The byte to be inserted into the structure. 176 * @return The constructor to facilitate chaining {@code cts.putXXX(..).putXXX(..)}. 177 */ putRawByte(byte b)178 public TlvConstructor putRawByte(byte b) { 179 checkRawLength(1); 180 mArray[mPosition++] = b; 181 return this; 182 } 183 184 /** 185 * Copies a byte array into the TLV with the indicated type. For an LV 186 * formatted structure (i.e. typeLength=0 in {@link TlvConstructor 187 * TlvConstructor(int, int)} ) the type field is ignored. 188 * 189 * @param type The value to be placed into the Type field. 190 * @param array The array to be copied into the TLV structure. 191 * @param offset Start copying from the array at the specified offset. 192 * @param length Copy the specified number (length) of bytes from the 193 * array. 194 * @return The constructor to facilitate chaining 195 * {@code ctr.putXXX(..).putXXX(..)}. 196 */ putByteArray(int type, @Nullable byte[] array, int offset, int length)197 public TlvConstructor putByteArray(int type, @Nullable byte[] array, int offset, 198 int length) { 199 checkLength(length); 200 addHeader(type, length); 201 if (length != 0) { 202 System.arraycopy(array, offset, mArray, mPosition, length); 203 } 204 mPosition += length; 205 return this; 206 } 207 208 /** 209 * Copies a byte array into the TLV with the indicated type. For an LV 210 * formatted structure (i.e. typeLength=0 in {@link TlvConstructor 211 * TlvConstructor(int, int)} ) the type field is ignored. 212 * 213 * @param type The value to be placed into the Type field. 214 * @param array The array to be copied (in full) into the TLV structure. 215 * @return The constructor to facilitate chaining 216 * {@code ctr.putXXX(..).putXXX(..)}. 217 */ putByteArray(int type, @Nullable byte[] array)218 public TlvConstructor putByteArray(int type, @Nullable byte[] array) { 219 return putByteArray(type, array, 0, (array == null) ? 0 : array.length); 220 } 221 222 /** 223 * Copies a byte array into the TLV - without a type or a length. 224 * 225 * @param array The array to be copied (in full) into the TLV structure. 226 * @return The constructor to facilitate chaining 227 * {@code ctr.putXXX(..).putXXX(..)}. 228 */ putRawByteArray(@ullable byte[] array)229 public TlvConstructor putRawByteArray(@Nullable byte[] array) { 230 if (array == null) return this; 231 232 checkRawLength(array.length); 233 System.arraycopy(array, 0, mArray, mPosition, array.length); 234 mPosition += array.length; 235 return this; 236 } 237 238 /** 239 * Places a zero length element (i.e. Length field = 0) into the TLV. 240 * For an LV formatted structure (i.e. typeLength=0 in 241 * {@link TlvConstructor TlvConstructor(int, int)} ) the type field is 242 * ignored. 243 * 244 * @param type The value to be placed into the Type field. 245 * @return The constructor to facilitate chaining 246 * {@code ctr.putXXX(..).putXXX(..)}. 247 */ putZeroLengthElement(int type)248 public TlvConstructor putZeroLengthElement(int type) { 249 checkLength(0); 250 addHeader(type, 0); 251 return this; 252 } 253 254 /** 255 * Copies short into the TLV with the indicated type. For an LV 256 * formatted structure (i.e. typeLength=0 in {@link TlvConstructor 257 * TlvConstructor(int, int)} ) the type field is ignored. 258 * 259 * @param type The value to be placed into the Type field. 260 * @param data The short to be inserted into the structure. 261 * @return The constructor to facilitate chaining 262 * {@code ctr.putXXX(..).putXXX(..)}. 263 */ putShort(int type, short data)264 public TlvConstructor putShort(int type, short data) { 265 checkLength(2); 266 addHeader(type, 2); 267 pokeShort(mArray, mPosition, data, mByteOrder); 268 mPosition += 2; 269 return this; 270 } 271 272 /** 273 * Copies integer into the TLV with the indicated type. For an LV 274 * formatted structure (i.e. typeLength=0 in {@link TlvConstructor 275 * TlvConstructor(int, int)} ) the type field is ignored. 276 * 277 * @param type The value to be placed into the Type field. 278 * @param data The integer to be inserted into the structure. 279 * @return The constructor to facilitate chaining 280 * {@code ctr.putXXX(..).putXXX(..)}. 281 */ putInt(int type, int data)282 public TlvConstructor putInt(int type, int data) { 283 checkLength(4); 284 addHeader(type, 4); 285 pokeInt(mArray, mPosition, data, mByteOrder); 286 mPosition += 4; 287 return this; 288 } 289 290 /** 291 * Copies a String's byte representation into the TLV with the indicated 292 * type. For an LV formatted structure (i.e. typeLength=0 in 293 * {@link TlvConstructor TlvConstructor(int, int)} ) the type field is 294 * ignored. 295 * 296 * @param type The value to be placed into the Type field. 297 * @param data The string whose bytes are to be inserted into the 298 * structure. 299 * @return The constructor to facilitate chaining 300 * {@code ctr.putXXX(..).putXXX(..)}. 301 */ putString(int type, @Nullable String data)302 public TlvConstructor putString(int type, @Nullable String data) { 303 byte[] bytes = null; 304 int length = 0; 305 if (data != null) { 306 bytes = data.getBytes(); 307 length = bytes.length; 308 } 309 return putByteArray(type, bytes, 0, length); 310 } 311 312 /** 313 * Returns the constructed TLV formatted byte-array. This array is a copy of the wrapped 314 * or allocated array - truncated to just the significant bytes - i.e. those written into 315 * the (T)LV. 316 * 317 * @return The byte array containing the TLV formatted structure. 318 */ getArray()319 public byte[] getArray() { 320 return Arrays.copyOf(mArray, getActualLength()); 321 } 322 323 /** 324 * Returns the size of the TLV formatted portion of the wrapped or 325 * allocated byte array. The array itself is returned with 326 * {@link TlvConstructor#getArray()}. 327 * 328 * @return The size of the TLV formatted portion of the byte array. 329 */ getActualLength()330 private int getActualLength() { 331 return mPosition; 332 } 333 checkLength(int dataLength)334 private void checkLength(int dataLength) { 335 if (mPosition + mTypeSize + mLengthSize + dataLength > mArrayLength) { 336 throw new BufferOverflowException(); 337 } 338 } 339 checkRawLength(int dataLength)340 private void checkRawLength(int dataLength) { 341 if (mPosition + dataLength > mArrayLength) { 342 throw new BufferOverflowException(); 343 } 344 } 345 addHeader(int type, int length)346 private void addHeader(int type, int length) { 347 if (mTypeSize == 1) { 348 mArray[mPosition] = (byte) type; 349 } else if (mTypeSize == 2) { 350 pokeShort(mArray, mPosition, (short) type, mByteOrder); 351 } 352 mPosition += mTypeSize; 353 354 if (mLengthSize == 1) { 355 mArray[mPosition] = (byte) length; 356 } else if (mLengthSize == 2) { 357 pokeShort(mArray, mPosition, (short) length, mByteOrder); 358 } 359 mPosition += mLengthSize; 360 } 361 } 362 363 /** 364 * Utility class used when iterating over a TLV formatted byte-array. Use 365 * {@link TlvIterable} to iterate over array. A {@link TlvElement} 366 * represents each entry in a TLV formatted byte-array. 367 */ 368 public static class TlvElement { 369 /** 370 * The Type (T) field of the current TLV element. Note that for LV 371 * formatted byte-arrays (i.e. TLV whose Type/T size is 0) the value of 372 * this field is undefined. 373 */ 374 public int type; 375 376 /** 377 * The Length (L) field of the current TLV element. 378 */ 379 public int length; 380 381 /** 382 * Control of the endianess of the TLV element - true for big-endian, false for little- 383 * endian. 384 */ 385 public ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; 386 387 /** 388 * The Value (V) field - a raw byte array representing the current TLV 389 * element where the entry starts at {@link TlvElement#offset}. 390 */ 391 private byte[] mRefArray; 392 393 /** 394 * The offset to be used into {@link TlvElement#mRefArray} to access the 395 * raw data representing the current TLV element. 396 */ 397 public int offset; 398 TlvElement(int type, int length, @Nullable byte[] refArray, int offset)399 private TlvElement(int type, int length, @Nullable byte[] refArray, int offset) { 400 this.type = type; 401 this.length = length; 402 mRefArray = refArray; 403 this.offset = offset; 404 405 if (offset + length > refArray.length) { 406 throw new BufferOverflowException(); 407 } 408 } 409 410 /** 411 * Return the raw byte array of the Value (V) field. 412 * 413 * @return The Value (V) field as a byte array. 414 */ getRawData()415 public byte[] getRawData() { 416 return Arrays.copyOfRange(mRefArray, offset, offset + length); 417 } 418 419 /** 420 * Utility function to return a byte representation of a TLV element of 421 * length 1. Note: an attempt to call this function on a TLV item whose 422 * {@link TlvElement#length} is != 1 will result in an exception. 423 * 424 * @return byte representation of current TLV element. 425 */ getByte()426 public byte getByte() { 427 if (length != 1) { 428 throw new IllegalArgumentException( 429 "Accesing a byte from a TLV element of length " + length); 430 } 431 return mRefArray[offset]; 432 } 433 434 /** 435 * Utility function to return a short representation of a TLV element of 436 * length 2. Note: an attempt to call this function on a TLV item whose 437 * {@link TlvElement#length} is != 2 will result in an exception. 438 * 439 * @return short representation of current TLV element. 440 */ getShort()441 public short getShort() { 442 if (length != 2) { 443 throw new IllegalArgumentException( 444 "Accesing a short from a TLV element of length " + length); 445 } 446 return peekShort(mRefArray, offset, byteOrder); 447 } 448 449 /** 450 * Utility function to return an integer representation of a TLV element 451 * of length 4. Note: an attempt to call this function on a TLV item 452 * whose {@link TlvElement#length} is != 4 will result in an exception. 453 * 454 * @return integer representation of current TLV element. 455 */ getInt()456 public int getInt() { 457 if (length != 4) { 458 throw new IllegalArgumentException( 459 "Accesing an int from a TLV element of length " + length); 460 } 461 return peekInt(mRefArray, offset, byteOrder); 462 } 463 464 /** 465 * Utility function to return a String representation of a TLV element. 466 * 467 * @return String repersentation of the current TLV element. 468 */ getString()469 public String getString() { 470 return new String(mRefArray, offset, length); 471 } 472 } 473 474 /** 475 * Utility class to iterate over a TLV formatted byte-array. 476 */ 477 public static class TlvIterable implements Iterable<TlvElement> { 478 private int mTypeSize; 479 private int mLengthSize; 480 private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN; 481 private byte[] mArray; 482 private int mArrayLength; 483 484 /** 485 * Constructs a TlvIterable object - specifying the format of the TLV 486 * (the sizes of the Type and Length fields), and the byte array whose 487 * data is to be parsed. 488 * 489 * @param typeSize Number of bytes used for the Type (T) field. Valid 490 * values are 0 (i.e. indicating the format is LV rather than 491 * TLV), 1, and 2 bytes. 492 * @param lengthSize Number of bytes used for the Length (L) field. 493 * Values values are 1 or 2 bytes. 494 * @param array The TLV formatted byte-array to parse. 495 */ TlvIterable(int typeSize, int lengthSize, @Nullable byte[] array)496 public TlvIterable(int typeSize, int lengthSize, @Nullable byte[] array) { 497 if (typeSize < 0 || typeSize > 2 || lengthSize <= 0 || lengthSize > 2) { 498 throw new IllegalArgumentException( 499 "Invalid sizes - typeSize=" + typeSize + ", lengthSize=" + lengthSize); 500 } 501 mTypeSize = typeSize; 502 mLengthSize = lengthSize; 503 mArray = array; 504 mArrayLength = (array == null) ? 0 : array.length; 505 } 506 507 /** 508 * Configure the TLV iterator to use little-endian byte ordering. 509 */ setByteOrder(ByteOrder byteOrder)510 public void setByteOrder(ByteOrder byteOrder) { 511 mByteOrder = byteOrder; 512 } 513 514 /** 515 * Prints out a parsed representation of the TLV-formatted byte array. 516 * Whenever possible bytes, shorts, and integer are printed out (for 517 * fields whose length is 1, 2, or 4 respectively). 518 */ 519 @Override toString()520 public String toString() { 521 StringBuilder builder = new StringBuilder(); 522 523 builder.append("["); 524 boolean first = true; 525 for (TlvElement tlv : this) { 526 if (!first) { 527 builder.append(","); 528 } 529 first = false; 530 builder.append(" ("); 531 if (mTypeSize != 0) { 532 builder.append("T=" + tlv.type + ","); 533 } 534 builder.append("L=" + tlv.length + ") "); 535 if (tlv.length == 0) { 536 builder.append("<null>"); 537 } else if (tlv.length == 1) { 538 builder.append(tlv.getByte()); 539 } else if (tlv.length == 2) { 540 builder.append(tlv.getShort()); 541 } else if (tlv.length == 4) { 542 builder.append(tlv.getInt()); 543 } else { 544 builder.append("<bytes>"); 545 } 546 if (tlv.length != 0) { 547 builder.append(" (S='" + tlv.getString() + "')"); 548 } 549 } 550 builder.append("]"); 551 552 return builder.toString(); 553 } 554 555 /** 556 * Returns a List with the raw contents (no types) of the iterator. 557 */ toList()558 public List<byte[]> toList() { 559 List<byte[]> list = new ArrayList<>(); 560 for (TlvElement tlv : this) { 561 list.add(Arrays.copyOfRange(tlv.mRefArray, tlv.offset, tlv.offset + tlv.length)); 562 } 563 564 return list; 565 } 566 567 /** 568 * Returns an iterator to step through a TLV formatted byte-array. The 569 * individual elements returned by the iterator are {@link TlvElement}. 570 */ 571 @Override iterator()572 public Iterator<TlvElement> iterator() { 573 return new Iterator<TlvElement>() { 574 private int mOffset = 0; 575 576 @Override 577 public boolean hasNext() { 578 return mOffset < mArrayLength; 579 } 580 581 @Override 582 public TlvElement next() { 583 if (!hasNext()) { 584 throw new NoSuchElementException(); 585 } 586 587 int type = 0; 588 if (mTypeSize == 1) { 589 type = mArray[mOffset]; 590 } else if (mTypeSize == 2) { 591 type = peekShort(mArray, mOffset, mByteOrder); 592 } 593 mOffset += mTypeSize; 594 595 int length = 0; 596 if (mLengthSize == 1) { 597 length = mArray[mOffset]; 598 } else if (mLengthSize == 2) { 599 length = peekShort(mArray, mOffset, mByteOrder); 600 } 601 mOffset += mLengthSize; 602 603 TlvElement tlv = new TlvElement(type, length, mArray, mOffset); 604 tlv.byteOrder = mByteOrder; 605 mOffset += length; 606 return tlv; 607 } 608 609 @Override 610 public void remove() { 611 throw new UnsupportedOperationException(); 612 } 613 }; 614 } 615 } 616 617 /** 618 * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length 619 * fields correctly fill the specified length (and do not overshoot). Uses big-endian 620 * byte ordering. 621 * 622 * @param array The (T)LV array to verify. 623 * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2. 624 * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2. 625 * @return A boolean indicating whether the array is valid (true) or invalid (false). 626 */ isValid(@ullable byte[] array, int typeSize, int lengthSize)627 public static boolean isValid(@Nullable byte[] array, int typeSize, int lengthSize) { 628 return isValidEndian(array, typeSize, lengthSize, ByteOrder.BIG_ENDIAN); 629 } 630 631 /** 632 * Validates that a (T)LV array is constructed correctly. I.e. that its specified Length 633 * fields correctly fill the specified length (and do not overshoot). 634 * 635 * @param array The (T)LV array to verify. 636 * @param typeSize The size (in bytes) of the type field. Valid values are 0, 1, or 2. 637 * @param lengthSize The size (in bytes) of the length field. Valid values are 1 or 2. 638 * @param byteOrder The endianness of the byte array: {@link ByteOrder#BIG_ENDIAN} or 639 * {@link ByteOrder#LITTLE_ENDIAN}. 640 * @return A boolean indicating whether the array is valid (true) or invalid (false). 641 */ isValidEndian(@ullable byte[] array, int typeSize, int lengthSize, ByteOrder byteOrder)642 public static boolean isValidEndian(@Nullable byte[] array, int typeSize, int lengthSize, 643 ByteOrder byteOrder) { 644 if (typeSize < 0 || typeSize > 2) { 645 throw new IllegalArgumentException( 646 "Invalid arguments - typeSize must be 0, 1, or 2: typeSize=" + typeSize); 647 } 648 if (lengthSize <= 0 || lengthSize > 2) { 649 throw new IllegalArgumentException( 650 "Invalid arguments - lengthSize must be 1 or 2: lengthSize=" + lengthSize); 651 } 652 if (array == null) { 653 return true; 654 } 655 656 int nextTlvIndex = 0; 657 while (nextTlvIndex + typeSize + lengthSize <= array.length) { 658 nextTlvIndex += typeSize; 659 if (lengthSize == 1) { 660 nextTlvIndex += lengthSize + array[nextTlvIndex]; 661 } else { 662 nextTlvIndex += lengthSize + peekShort(array, nextTlvIndex, byteOrder); 663 } 664 } 665 666 return nextTlvIndex == array.length; 667 } 668 pokeShort(byte[] dst, int offset, short value, ByteOrder order)669 private static void pokeShort(byte[] dst, int offset, short value, ByteOrder order) { 670 if (order == ByteOrder.BIG_ENDIAN) { 671 dst[offset++] = (byte) ((value >> 8) & 0xff); 672 dst[offset ] = (byte) ((value >> 0) & 0xff); 673 } else { 674 dst[offset++] = (byte) ((value >> 0) & 0xff); 675 dst[offset ] = (byte) ((value >> 8) & 0xff); 676 } 677 } 678 pokeInt(byte[] dst, int offset, int value, ByteOrder order)679 private static void pokeInt(byte[] dst, int offset, int value, ByteOrder order) { 680 if (order == ByteOrder.BIG_ENDIAN) { 681 dst[offset++] = (byte) ((value >> 24) & 0xff); 682 dst[offset++] = (byte) ((value >> 16) & 0xff); 683 dst[offset++] = (byte) ((value >> 8) & 0xff); 684 dst[offset ] = (byte) ((value >> 0) & 0xff); 685 } else { 686 dst[offset++] = (byte) ((value >> 0) & 0xff); 687 dst[offset++] = (byte) ((value >> 8) & 0xff); 688 dst[offset++] = (byte) ((value >> 16) & 0xff); 689 dst[offset ] = (byte) ((value >> 24) & 0xff); 690 } 691 } 692 peekShort(byte[] src, int offset, ByteOrder order)693 private static short peekShort(byte[] src, int offset, ByteOrder order) { 694 if (order == ByteOrder.BIG_ENDIAN) { 695 return (short) ((src[offset] << 8) | (src[offset + 1] & 0xff)); 696 } else { 697 return (short) ((src[offset + 1] << 8) | (src[offset] & 0xff)); 698 } 699 } 700 peekInt(byte[] src, int offset, ByteOrder order)701 private static int peekInt(byte[] src, int offset, ByteOrder order) { 702 if (order == ByteOrder.BIG_ENDIAN) { 703 return ((src[offset++] & 0xff) << 24) 704 | ((src[offset++] & 0xff) << 16) 705 | ((src[offset++] & 0xff) << 8) 706 | ((src[offset ] & 0xff) << 0); 707 } else { 708 return ((src[offset++] & 0xff) << 0) 709 | ((src[offset++] & 0xff) << 8) 710 | ((src[offset++] & 0xff) << 16) 711 | ((src[offset ] & 0xff) << 24); 712 } 713 } 714 } 715