• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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