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