• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 com.android.timezone.location.storage.block.read;
18 
19 import com.android.timezone.location.storage.util.BitwiseUtils;
20 
21 import java.nio.ByteBuffer;
22 import java.nio.ByteOrder;
23 import java.util.Objects;
24 
25 /**
26  * Provides typed, absolute position, random access to a block's data.
27  *
28  * <p>See also {@link com.android.timezone.location.storage.io.read.TypedInputStream} for a streamed
29  * equivalent.
30  */
31 public final class BlockData {
32 
33     private final ByteBuffer mDataBytes;
34 
35     /** Wraps a read-only, big-endian {@link ByteBuffer}. */
BlockData(ByteBuffer dataBytes)36     public BlockData(ByteBuffer dataBytes) {
37         if (!dataBytes.isReadOnly()) {
38             throw new IllegalArgumentException("dataBytes must be readonly");
39         }
40         if (dataBytes.order() != ByteOrder.BIG_ENDIAN) {
41             throw new IllegalArgumentException("dataBytes must be big-endian");
42         }
43         mDataBytes = Objects.requireNonNull(dataBytes);
44     }
45 
46     /** Returns a copy of the underlying {@link ByteBuffer}. */
getByteBuffer()47     public ByteBuffer getByteBuffer() {
48         return mDataBytes.duplicate();
49     }
50 
51     /** Returns the value of the byte at the specified position. */
getByte(int byteOffset)52     public byte getByte(int byteOffset) {
53         return mDataBytes.get(byteOffset);
54     }
55 
56     /** Returns the value of the byte at the specified position as an unsigned value. */
getUnsignedByte(int byteOffset)57     public int getUnsignedByte(int byteOffset) {
58         return mDataBytes.get(byteOffset) & 0xFF;
59     }
60 
61     /** Returns the value of the 16-bit char at the specified position as an unsigned value. */
getChar(int byteOffset)62     public char getChar(int byteOffset) {
63         return mDataBytes.getChar(byteOffset);
64     }
65 
66     /** Returns the value of the 32-bit int at the specified position as an signed value. */
getInt(int byteOffset)67     public int getInt(int byteOffset) {
68         return mDataBytes.getInt(byteOffset);
69     }
70 
71     /** Returns the value of the 64-bit long at the specified position as an signed value. */
getLong(int byteOffset)72     public long getLong(int byteOffset) {
73         return mDataBytes.getLong(byteOffset);
74     }
75 
76     /**
77      * Returns a tiny (<= 255 entries) array of signed bytes starting at the specified position,
78      * where the length is encoded in the data.
79      */
getTinyByteArray(int byteOffset)80     public byte[] getTinyByteArray(int byteOffset) {
81         int size = getUnsignedByte(byteOffset);
82         return getBytes(byteOffset + 1, size);
83     }
84 
85     /**
86      * Returns an array of signed bytes starting at the specified position.
87      */
getBytes(int byteOffset, int byteCount)88     public byte[] getBytes(int byteOffset, int byteCount) {
89         byte[] bytes = new byte[byteCount];
90         for (int i = 0; i < byteCount; i++) {
91             bytes[i] = mDataBytes.get(byteOffset + i);
92         }
93         return bytes;
94     }
95 
96     /**
97      * Returns a tiny (<= 255 entries) array of chars starting at the specified position, where the
98      * length is encoded in the data.
99      */
getTinyCharArray(int byteOffset)100     public char[] getTinyCharArray(int byteOffset) {
101         int size = getUnsignedByte(byteOffset);
102         return getChars(byteOffset + 1, size);
103     }
104 
105     /**
106      * Returns an array of chars starting at the specified position.
107      */
getChars(int byteOffset, int charCount)108     public char[] getChars(int byteOffset, int charCount) {
109         char[] array = new char[charCount];
110         for (int i = 0; i < charCount; i++) {
111             array[i] = getChar(byteOffset);
112             byteOffset += Character.BYTES;
113         }
114         return array;
115     }
116 
117     /**
118      * Returns 1-8 bytes ({@code valueSizeBytes}) starting as the specified position as a
119      * {@code long}. The value can be interpreted as signed or unsigned depending on
120      * {@code signExtend}.
121      */
getValueAsLong(int valueSizeBytes, int byteOffset, boolean signExtend)122     public long getValueAsLong(int valueSizeBytes, int byteOffset, boolean signExtend) {
123         if (valueSizeBytes < 0 || valueSizeBytes > Long.BYTES) {
124             throw new IllegalArgumentException("valueSizeBytes must be <= 8 bytes");
125         }
126         return getValueInternal(valueSizeBytes, byteOffset, signExtend);
127     }
128 
129     /** Returns the size of the block data. */
getSize()130     public int getSize() {
131         return mDataBytes.limit();
132     }
133 
getValueInternal(int valueSizeBytes, int byteOffset, boolean signExtend)134     private long getValueInternal(int valueSizeBytes, int byteOffset, boolean signExtend) {
135         if (byteOffset < 0) {
136             throw new IllegalArgumentException(
137                     "byteOffset=" + byteOffset + " must not be negative");
138         }
139 
140         // High bytes read first.
141         long value = 0;
142         int bytesRead = 0;
143         while (bytesRead++ < valueSizeBytes) {
144             value <<= 8;
145             value |= (mDataBytes.get(byteOffset++) & 0xFF);
146         }
147         if (valueSizeBytes < 8 && signExtend) {
148             int entrySizeBits = valueSizeBytes * Byte.SIZE;
149             value = BitwiseUtils.signExtendToLong(entrySizeBits, value);
150         }
151         return value;
152     }
153 }
154