• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 package com.android.internal.widget.remotecompose.core;
17 
18 import android.annotation.NonNull;
19 
20 import java.util.Arrays;
21 
22 /** The base communication buffer capable of encoding and decoding various types */
23 public class WireBuffer {
24     private static final int BUFFER_SIZE = 1024 * 1024 * 1;
25     int mMaxSize;
26     @NonNull byte[] mBuffer;
27     int mIndex = 0;
28     int mStartingIndex = 0;
29     int mSize = 0;
30 
31     /**
32      * Create a wire buffer
33      *
34      * @param size the initial size of the buffer
35      */
WireBuffer(int size)36     public WireBuffer(int size) {
37         mMaxSize = size;
38         mBuffer = new byte[mMaxSize];
39     }
40 
41     /** Create a wire buffer of default size */
WireBuffer()42     public WireBuffer() {
43         this(BUFFER_SIZE);
44     }
45 
resize(int need)46     private void resize(int need) {
47         if (mSize + need >= mMaxSize) {
48             mMaxSize = Math.max(mMaxSize * 2, mSize + need);
49             mBuffer = Arrays.copyOf(mBuffer, mMaxSize);
50         }
51     }
52 
53     /**
54      * get the wire buffer's underlying byte array. Note the array will be bigger that the used
55      * portion
56      *
57      * @return byte array of the wire buffer
58      */
getBuffer()59     public @NonNull byte[] getBuffer() {
60         return mBuffer;
61     }
62 
63     /**
64      * The current mix size of the buffer
65      *
66      * @return max size
67      */
getMax_size()68     public int getMax_size() {
69         return mMaxSize;
70     }
71 
72     /**
73      * The current point in the buffer which will be written to
74      *
75      * @return index pointing into the buffer
76      */
getIndex()77     public int getIndex() {
78         return mIndex;
79     }
80 
81     /**
82      * The size of the buffer
83      *
84      * @return the size of the buffer
85      */
getSize()86     public int getSize() {
87         return mSize;
88     }
89 
90     /**
91      * Reposition the pointer
92      *
93      * @param index the new position of the index
94      */
setIndex(int index)95     public void setIndex(int index) {
96         this.mIndex = index;
97     }
98 
99     /**
100      * Write a byte representing the command into the buffer
101      *
102      * @param type the command id
103      */
start(int type)104     public void start(int type) {
105         mStartingIndex = mIndex;
106         writeByte(type);
107     }
108 
109     /**
110      * Unused Todo remove?
111      *
112      * @param type the type of object to write
113      */
startWithSize(int type)114     public void startWithSize(int type) {
115         mStartingIndex = mIndex;
116         writeByte(type);
117         mIndex += 4; // skip ahead for the future size
118     }
119 
120     /** Unused Todo remove? */
endWithSize()121     public void endWithSize() {
122         int size = mIndex - mStartingIndex;
123         int currentIndex = mIndex;
124         mIndex = mStartingIndex + 1; // (type)
125         writeInt(size);
126         mIndex = currentIndex;
127     }
128 
129     /**
130      * Reset the internal buffer
131      *
132      * @param expectedSize provided hint for the buffer size
133      */
reset(int expectedSize)134     public void reset(int expectedSize) {
135         mIndex = 0;
136         mStartingIndex = 0;
137         mSize = 0;
138         if (expectedSize >= mMaxSize) {
139             resize(expectedSize);
140         }
141     }
142 
143     /**
144      * return the size of the buffer todo rename to getSize
145      *
146      * @return the size of the buffer
147      */
size()148     public int size() {
149         return mSize;
150     }
151 
152     /**
153      * Bytes available
154      *
155      * @return the size - index
156      */
available()157     public boolean available() {
158         return mSize - mIndex > 0;
159     }
160 
161     ///////////////////////////////////////////////////////////////////////////
162     // Read values
163     ///////////////////////////////////////////////////////////////////////////
164 
165     /**
166      * read the operation type (reads a single byte)
167      *
168      * @return the byte cast to an integer
169      */
readOperationType()170     public int readOperationType() {
171         return readByte();
172     }
173 
174     /**
175      * Read a boolean (stored as a byte 1 = true)
176      *
177      * @return boolean of the byte
178      */
readBoolean()179     public boolean readBoolean() {
180         byte value = mBuffer[mIndex];
181         mIndex++;
182         return (value == 1);
183     }
184 
185     /**
186      * read a single byte byte
187      *
188      * @return byte from 0..255 as an Integer
189      */
readByte()190     public int readByte() {
191         int value = 0xFF & mBuffer[mIndex];
192         mIndex++;
193         return value;
194     }
195 
196     /**
197      * read a short [byte n] << 8 | [byte n+1]; index increast by 2
198      *
199      * @return return a short cast as an integer
200      */
readShort()201     public int readShort() {
202         int v1 = (mBuffer[mIndex++] & 0xFF) << 8;
203         int v2 = (mBuffer[mIndex++] & 0xFF) << 0;
204         return v1 + v2;
205     }
206 
207     /**
208      * Read an integer without incrementing the index
209      *
210      * @return the integer
211      */
peekInt()212     public int peekInt() {
213         int tmp = mIndex;
214         int v1 = (mBuffer[tmp++] & 0xFF) << 24;
215         int v2 = (mBuffer[tmp++] & 0xFF) << 16;
216         int v3 = (mBuffer[tmp++] & 0xFF) << 8;
217         int v4 = (mBuffer[tmp++] & 0xFF) << 0;
218         return v1 + v2 + v3 + v4;
219     }
220 
221     /**
222      * Read an integer. index increased by 4
223      *
224      * @return integer
225      */
readInt()226     public int readInt() {
227         int v1 = (mBuffer[mIndex++] & 0xFF) << 24;
228         int v2 = (mBuffer[mIndex++] & 0xFF) << 16;
229         int v3 = (mBuffer[mIndex++] & 0xFF) << 8;
230         int v4 = (mBuffer[mIndex++] & 0xFF) << 0;
231         return v1 + v2 + v3 + v4;
232     }
233 
234     /**
235      * Read a long index is increased by 8
236      *
237      * @return long
238      */
readLong()239     public long readLong() {
240         long v1 = (mBuffer[mIndex++] & 0xFFL) << 56;
241         long v2 = (mBuffer[mIndex++] & 0xFFL) << 48;
242         long v3 = (mBuffer[mIndex++] & 0xFFL) << 40;
243         long v4 = (mBuffer[mIndex++] & 0xFFL) << 32;
244         long v5 = (mBuffer[mIndex++] & 0xFFL) << 24;
245         long v6 = (mBuffer[mIndex++] & 0xFFL) << 16;
246         long v7 = (mBuffer[mIndex++] & 0xFFL) << 8;
247         long v8 = (mBuffer[mIndex++] & 0xFFL) << 0;
248         return v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8;
249     }
250 
251     /**
252      * Read a 32 bit float IEEE standard index is increased by 4
253      *
254      * @return the float
255      */
readFloat()256     public float readFloat() {
257         return java.lang.Float.intBitsToFloat(readInt());
258     }
259 
260     /**
261      * Read a 64 bit double index is increased by 8
262      *
263      * @return double
264      */
readDouble()265     public double readDouble() {
266         return java.lang.Double.longBitsToDouble(readLong());
267     }
268 
269     /**
270      * Read a byte buffer bytes are encoded as 4 byte length followed by length bytes index is
271      * increased by 4 + number of bytes
272      *
273      * @return byte array
274      */
readBuffer()275     public @NonNull byte[] readBuffer() {
276         int count = readInt();
277         byte[] b = Arrays.copyOfRange(mBuffer, mIndex, mIndex + count);
278         mIndex += count;
279         return b;
280     }
281 
282     /**
283      * Read a byte buffer limited to max size. bytes are encoded as 4 byte length followed by length
284      * bytes index is increased by 4 + number of bytes Throw an exception if the read excedes the
285      * max size. This is the preferred form of read buffer.
286      *
287      * @return byte array
288      */
readBuffer(int maxSize)289     public @NonNull byte[] readBuffer(int maxSize) {
290         int count = readInt();
291         if (count < 0 || count > maxSize) {
292             throw new RuntimeException(
293                     "attempt read a buff of invalid size 0 <= " + count + " > " + maxSize);
294         }
295         byte[] b = Arrays.copyOfRange(mBuffer, mIndex, mIndex + count);
296         mIndex += count;
297         return b;
298     }
299 
300     /**
301      * Read a string encoded in UTF8 The buffer is red with readBuffer and converted to a String
302      *
303      * @return unicode string
304      */
305     @NonNull
readUTF8()306     public String readUTF8() {
307         byte[] stringBuffer = readBuffer();
308         return new String(stringBuffer);
309     }
310 
311     /**
312      * Read a string encoded in UTF8 The buffer is red with readBuffer and converted to a String
313      * This is the preferred readUTF8 because it catches errors
314      *
315      * @return unicode string
316      */
317     @NonNull
readUTF8(int maxSize)318     public String readUTF8(int maxSize) {
319         byte[] stringBuffer = readBuffer(maxSize);
320         return new String(stringBuffer);
321     }
322 
323     ///////////////////////////////////////////////////////////////////////////
324     // Write values
325     ///////////////////////////////////////////////////////////////////////////
326 
327     /**
328      * Write a boolean value. (written as a byte 1=true)
329      *
330      * @param value value to write
331      */
writeBoolean(boolean value)332     public void writeBoolean(boolean value) {
333         resize(1);
334         mBuffer[mIndex++] = (byte) (value ? 1 : 0);
335         mSize++;
336     }
337 
338     /**
339      * Write a byte value
340      *
341      * @param value value to write
342      */
writeByte(int value)343     public void writeByte(int value) {
344         resize(1);
345         mBuffer[mIndex++] = (byte) value;
346         mSize++;
347     }
348 
349     /**
350      * Write a short value
351      *
352      * @param value value to write
353      */
writeShort(int value)354     public void writeShort(int value) {
355         int need = 2;
356         resize(need);
357         mBuffer[mIndex++] = (byte) (value >>> 8 & 0xFF);
358         mBuffer[mIndex++] = (byte) (value & 0xFF);
359         mSize += need;
360     }
361 
362     /**
363      * Write a int (4 byte) value
364      *
365      * @param value value to write
366      */
writeInt(int value)367     public void writeInt(int value) {
368         int need = 4;
369         resize(need);
370         mBuffer[mIndex++] = (byte) (value >>> 24 & 0xFF);
371         mBuffer[mIndex++] = (byte) (value >>> 16 & 0xFF);
372         mBuffer[mIndex++] = (byte) (value >>> 8 & 0xFF);
373         mBuffer[mIndex++] = (byte) (value & 0xFF);
374         mSize += need;
375     }
376 
377     /**
378      * Write a long (8 byte) value
379      *
380      * @param value value to write
381      */
writeLong(long value)382     public void writeLong(long value) {
383         int need = 8;
384         resize(need);
385         mBuffer[mIndex++] = (byte) (value >>> 56 & 0xFF);
386         mBuffer[mIndex++] = (byte) (value >>> 48 & 0xFF);
387         mBuffer[mIndex++] = (byte) (value >>> 40 & 0xFF);
388         mBuffer[mIndex++] = (byte) (value >>> 32 & 0xFF);
389         mBuffer[mIndex++] = (byte) (value >>> 24 & 0xFF);
390         mBuffer[mIndex++] = (byte) (value >>> 16 & 0xFF);
391         mBuffer[mIndex++] = (byte) (value >>> 8 & 0xFF);
392         mBuffer[mIndex++] = (byte) (value & 0xFF);
393         mSize += need;
394     }
395 
396     /**
397      * Write a 32 bit IEEE float value
398      *
399      * @param value value to write
400      */
writeFloat(float value)401     public void writeFloat(float value) {
402         writeInt(Float.floatToRawIntBits(value));
403     }
404 
405     /**
406      * Write a 64 bit IEEE double value
407      *
408      * @param value value to write
409      */
writeDouble(double value)410     public void writeDouble(double value) {
411         writeLong(Double.doubleToRawLongBits(value));
412     }
413 
414     /**
415      * Write a buffer The buffer length is first written followed by the bytes
416      *
417      * @param b array of bytes write
418      */
writeBuffer(@onNull byte[] b)419     public void writeBuffer(@NonNull byte[] b) {
420         resize(b.length + 4);
421         writeInt(b.length);
422         for (int i = 0; i < b.length; i++) {
423             mBuffer[mIndex++] = b[i];
424         }
425         mSize += b.length;
426     }
427 
428     /**
429      * Write a string is encoded as UTF8
430      *
431      * @param content the string to write
432      */
writeUTF8(@onNull String content)433     public void writeUTF8(@NonNull String content) {
434         byte[] buffer = content.getBytes();
435         writeBuffer(buffer);
436     }
437 }
438