...

Text file src/github.com/google/flatbuffers/ts/byte-buffer.ts

Documentation: github.com/google/flatbuffers/ts

     1import { FILE_IDENTIFIER_LENGTH, SIZEOF_INT } from "./constants.js";
     2import { int32, isLittleEndian, float32, float64 } from "./utils.js";
     3import { Offset, Table, IGeneratedObject, IUnpackableObject } from "./types.js";
     4import { Encoding } from "./encoding.js";
     5
     6export class ByteBuffer {
     7    private position_ = 0;
     8    private text_decoder_ = new TextDecoder();
     9  
    10    /**
    11     * Create a new ByteBuffer with a given array of bytes (`Uint8Array`)
    12     */
    13    constructor(private bytes_: Uint8Array) { }
    14  
    15    /**
    16     * Create and allocate a new ByteBuffer with a given size.
    17     */
    18    static allocate(byte_size: number): ByteBuffer {
    19      return new ByteBuffer(new Uint8Array(byte_size));
    20    }
    21  
    22    clear(): void {
    23      this.position_ = 0;
    24    }
    25  
    26    /**
    27     * Get the underlying `Uint8Array`.
    28     */
    29    bytes(): Uint8Array {
    30      return this.bytes_;
    31    }
    32  
    33    /**
    34     * Get the buffer's position.
    35     */
    36    position(): number {
    37      return this.position_;
    38    }
    39  
    40    /**
    41     * Set the buffer's position.
    42     */
    43    setPosition(position: number): void {
    44      this.position_ = position;
    45    }
    46  
    47    /**
    48     * Get the buffer's capacity.
    49     */
    50    capacity(): number {
    51      return this.bytes_.length;
    52    }
    53  
    54    readInt8(offset: number): number {
    55      return this.readUint8(offset) << 24 >> 24;
    56    }
    57  
    58    readUint8(offset: number): number {
    59      return this.bytes_[offset];
    60    }
    61  
    62    readInt16(offset: number): number {
    63      return this.readUint16(offset) << 16 >> 16;
    64    }
    65  
    66    readUint16(offset: number): number {
    67      return this.bytes_[offset] | this.bytes_[offset + 1] << 8;
    68    }
    69  
    70    readInt32(offset: number): number {
    71      return this.bytes_[offset] | this.bytes_[offset + 1] << 8 | this.bytes_[offset + 2] << 16 | this.bytes_[offset + 3] << 24;
    72    }
    73  
    74    readUint32(offset: number): number {
    75      return this.readInt32(offset) >>> 0;
    76    }
    77  
    78    readInt64(offset: number): bigint {
    79      return BigInt.asIntN(64, BigInt(this.readUint32(offset)) + (BigInt(this.readUint32(offset + 4)) << BigInt(32)));
    80    }
    81  
    82    readUint64(offset: number): bigint {
    83      return BigInt.asUintN(64, BigInt(this.readUint32(offset)) + (BigInt(this.readUint32(offset + 4)) << BigInt(32)));
    84    }
    85  
    86    readFloat32(offset: number): number {
    87      int32[0] = this.readInt32(offset);
    88      return float32[0];
    89    }
    90  
    91    readFloat64(offset: number): number {
    92      int32[isLittleEndian ? 0 : 1] = this.readInt32(offset);
    93      int32[isLittleEndian ? 1 : 0] = this.readInt32(offset + 4);
    94      return float64[0];
    95    }
    96  
    97    writeInt8(offset: number, value: number): void {
    98      this.bytes_[offset] = value;
    99    }
   100  
   101    writeUint8(offset: number, value: number): void {
   102      this.bytes_[offset] = value;
   103    }
   104  
   105    writeInt16(offset: number, value: number): void {
   106      this.bytes_[offset] = value;
   107      this.bytes_[offset + 1] = value >> 8;
   108    }
   109  
   110    writeUint16(offset: number, value: number): void {
   111      this.bytes_[offset] = value;
   112      this.bytes_[offset + 1] = value >> 8;
   113    }
   114  
   115    writeInt32(offset: number, value: number): void {
   116      this.bytes_[offset] = value;
   117      this.bytes_[offset + 1] = value >> 8;
   118      this.bytes_[offset + 2] = value >> 16;
   119      this.bytes_[offset + 3] = value >> 24;
   120    }
   121  
   122    writeUint32(offset: number, value: number): void {
   123      this.bytes_[offset] = value;
   124      this.bytes_[offset + 1] = value >> 8;
   125      this.bytes_[offset + 2] = value >> 16;
   126      this.bytes_[offset + 3] = value >> 24;
   127    }
   128  
   129    writeInt64(offset: number, value: bigint): void {
   130      this.writeInt32(offset, Number(BigInt.asIntN(32, value)));
   131      this.writeInt32(offset + 4, Number(BigInt.asIntN(32, value >> BigInt(32))));
   132    }
   133  
   134    writeUint64(offset: number, value: bigint): void {
   135      this.writeUint32(offset, Number(BigInt.asUintN(32, value)));
   136      this.writeUint32(offset + 4, Number(BigInt.asUintN(32, value >> BigInt(32))));
   137    }
   138  
   139    writeFloat32(offset: number, value: number): void {
   140      float32[0] = value;
   141      this.writeInt32(offset, int32[0]);
   142    }
   143  
   144    writeFloat64(offset: number, value: number): void {
   145      float64[0] = value;
   146      this.writeInt32(offset, int32[isLittleEndian ? 0 : 1]);
   147      this.writeInt32(offset + 4, int32[isLittleEndian ? 1 : 0]);
   148    }
   149  
   150    /**
   151     * Return the file identifier.   Behavior is undefined for FlatBuffers whose
   152     * schema does not include a file_identifier (likely points at padding or the
   153     * start of a the root vtable).
   154     */
   155    getBufferIdentifier(): string {
   156      if (this.bytes_.length < this.position_ + SIZEOF_INT +
   157          FILE_IDENTIFIER_LENGTH) {
   158        throw new Error(
   159            'FlatBuffers: ByteBuffer is too short to contain an identifier.');
   160      }
   161      let result = "";
   162      for (let i = 0; i < FILE_IDENTIFIER_LENGTH; i++) {
   163        result += String.fromCharCode(
   164            this.readInt8(this.position_ + SIZEOF_INT + i));
   165      }
   166      return result;
   167    }
   168  
   169    /**
   170     * Look up a field in the vtable, return an offset into the object, or 0 if the
   171     * field is not present.
   172     */
   173    __offset(bb_pos: number, vtable_offset: number): Offset {
   174      const vtable = bb_pos - this.readInt32(bb_pos);
   175      return vtable_offset < this.readInt16(vtable) ? this.readInt16(vtable + vtable_offset) : 0;
   176    }
   177  
   178    /**
   179     * Initialize any Table-derived type to point to the union at the given offset.
   180     */
   181    __union(t: Table, offset: number): Table {
   182      t.bb_pos = offset + this.readInt32(offset);
   183      t.bb = this;
   184      return t;
   185    }
   186  
   187    /**
   188     * Create a JavaScript string from UTF-8 data stored inside the FlatBuffer.
   189     * This allocates a new string and converts to wide chars upon each access.
   190     *
   191     * To avoid the conversion to string, pass Encoding.UTF8_BYTES as the
   192     * "optionalEncoding" argument. This is useful for avoiding conversion when
   193     * the data will just be packaged back up in another FlatBuffer later on.
   194     *
   195     * @param offset
   196     * @param opt_encoding Defaults to UTF16_STRING
   197     */
   198    __string(offset: number, opt_encoding?: Encoding): string | Uint8Array {
   199      offset += this.readInt32(offset);
   200      const length = this.readInt32(offset);
   201      offset += SIZEOF_INT;
   202      const utf8bytes = this.bytes_.subarray(offset, offset + length);
   203      if (opt_encoding === Encoding.UTF8_BYTES)
   204        return utf8bytes;
   205      else
   206        return this.text_decoder_.decode(utf8bytes);
   207    }
   208  
   209    /**
   210     * Handle unions that can contain string as its member, if a Table-derived type then initialize it, 
   211     * if a string then return a new one
   212     * 
   213     * WARNING: strings are immutable in JS so we can't change the string that the user gave us, this 
   214     * makes the behaviour of __union_with_string different compared to __union
   215     */
   216    __union_with_string(o: Table | string, offset: number) : Table | string {
   217      if(typeof o === 'string') {
   218        return this.__string(offset) as string;
   219      } 
   220      return this.__union(o, offset);
   221    }
   222  
   223    /**
   224     * Retrieve the relative offset stored at "offset"
   225     */
   226    __indirect(offset: Offset): Offset {
   227      return offset + this.readInt32(offset);
   228    }
   229  
   230    /**
   231     * Get the start of data of a vector whose offset is stored at "offset" in this object.
   232     */
   233    __vector(offset: Offset): Offset {
   234      return offset + this.readInt32(offset) + SIZEOF_INT; // data starts after the length
   235    }
   236  
   237    /**
   238     * Get the length of a vector whose offset is stored at "offset" in this object.
   239     */
   240    __vector_len(offset: Offset): Offset {
   241      return this.readInt32(offset + this.readInt32(offset));
   242    }
   243  
   244    __has_identifier(ident: string): boolean {
   245      if (ident.length != FILE_IDENTIFIER_LENGTH) {
   246        throw new Error('FlatBuffers: file identifier must be length ' +
   247                        FILE_IDENTIFIER_LENGTH);
   248      }
   249      for (let i = 0; i < FILE_IDENTIFIER_LENGTH; i++) {
   250        if (ident.charCodeAt(i) != this.readInt8(this.position() + SIZEOF_INT + i)) {
   251          return false;
   252        }
   253      }
   254      return true;
   255    }
   256
   257    /**
   258     * A helper function for generating list for obj api
   259     */
   260    createScalarList<T>(listAccessor: (i: number) => T | null, listLength: number): T[] {
   261      const ret: T[]  = [];
   262      for(let i = 0; i < listLength; ++i) {
   263        const val = listAccessor(i);
   264        if(val !== null) {
   265          ret.push(val);
   266        }
   267      }
   268      return ret;
   269    }
   270
   271    /**
   272     * A helper function for generating list for obj api
   273     * @param listAccessor function that accepts an index and return data at that index
   274     * @param listLength listLength
   275     * @param res result list
   276     */
   277    createObjList<T1 extends IUnpackableObject<T2>, T2 extends IGeneratedObject>(listAccessor: (i: number) => T1 | null, listLength: number): T2[] {
   278      const ret: T2[] = [];
   279      for(let i = 0; i < listLength; ++i) {
   280        const val = listAccessor(i);
   281        if(val !== null) {
   282          ret.push(val.unpack());
   283        }
   284      }
   285      return ret;
   286    }
   287  }

View as plain text