All files / src/common/buffer buffer-reader.ts

58.69% Statements 27/46
50% Branches 7/14
57.14% Functions 8/14
59.09% Lines 26/44

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127      68x 68x 68x     68x           66x 66x 66x                   396x     396x                 396x           396x     396x     396x 396x     396x       492x 492x     492x 492x 492x         46x         341x         9x                                                                             333x 333x 333x            
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
// TODO: make modern
import { bytesToHex } from '../encoding-hex';
import { checkOffsetOrLengthValue, isEnum } from './buffer-utils';
import { ERRORS } from './buffer-constants';
 
// this is a combo of the buffer-reader class found in stacks.js and `smart-buffer`
export class BufferReader {
  buffer: Uint8Array;
  view: DataView;
  _readOffset = 0;
 
  constructor(buff?: Uint8Array) {
    if (buff) {
      this.buffer = buff;
      this.view = new DataView(buff.buffer, buff.byteOffset, buff.byteLength);
    } else E{
      const buffer = new Uint8Array();
      this.buffer = buffer;
      this.view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
    }
  }
 
  private ensureReadable(length: number, offset?: number) {
    // Offset value defaults to managed read offset.
    let offsetVal = this._readOffset;
 
    // If an offset was provided, use it.
    Iif (typeof offset !== 'undefined') {
      // Checks for valid numberic value;
      checkOffsetOrLengthValue(offset, true);
 
      // Override with custom offset.
      offsetVal = offset;
    }
 
    // Checks if offset is below zero, or the offset+length offset is beyond the total length of the managed data.
    Iif (offsetVal < 0 || offsetVal + length > this.buffer.length) {
      throw new Error(ERRORS.INVALID_READ_BEYOND_BOUNDS);
    }
  }
 
  private _readNumberValue<T>(func: (offset: number) => T, byteSize: number, offset?: number): T {
    this.ensureReadable(byteSize, offset);
 
    // Call Buffer.readXXXX();
    const value = func.call(this.view, typeof offset === 'number' ? offset : this._readOffset);
 
    // Adjust internal read offset if an optional read offset was not provided.
    if (typeof offset === 'undefined') {
      this._readOffset += byteSize;
    }
 
    return value;
  }
 
  readBuffer(length?: number): Uint8Array {
    const lengthVal = typeof length === 'number' ? length : this.buffer.length;
    const endPoint = Math.min(this.buffer.length, this._readOffset + lengthVal);
 
    // Read buffer value
    const value = this.buffer.slice(this.buffer.byteOffset + this._readOffset, endPoint);
    this._readOffset = endPoint;
    return value;
  }
 
  readUInt32BE(offset?: number): number {
    // eslint-disable-next-line @typescript-eslint/unbound-method
    return this._readNumberValue(this.view.getUint32, 4, offset);
  }
 
  readUInt8(offset?: number): number {
    // eslint-disable-next-line @typescript-eslint/unbound-method
    return this._readNumberValue(this.view.getUint8, 1, offset);
  }
 
  readUInt16BE(offset?: number): number {
    // eslint-disable-next-line @typescript-eslint/unbound-method
    return this._readNumberValue(this.view.getUint16, 2, offset);
  }
 
  readBigUIntLE(length: number): BigInt {
    const buffer = Uint8Array.from(this.readBuffer(length)).reverse();
    const hex = bytesToHex(buffer);
    return BigInt(`0x${hex}`);
  }
 
  readBigUIntBE(length: number): BigInt {
    const buffer = this.readBuffer(length);
    const hex = bytesToHex(buffer);
    return BigInt(`0x${hex}`);
  }
 
  readBigUInt64BE(offset?: number): bigint {
    Iif (typeof BigInt === 'undefined') {
      throw new Error('Platform does not support JS BigInt type.');
    }
    // eslint-disable-next-line @typescript-eslint/unbound-method
    return this._readNumberValue(this.view.getBigUint64, 8, offset);
  }
 
  get readOffset(): number {
    return this._readOffset;
  }
 
  set readOffset(val: number) {
    this._readOffset = val;
  }
 
  get internalBuffer(): ArrayBuffer {
    return this.buffer.buffer;
  }
 
  readUInt8Enum<T extends string, TEnumValue extends number>(
    enumVariable: { [key in T]: TEnumValue },
    invalidEnumErrorFormatter: (val: number) => Error
  ): TEnumValue {
    const num = this.readUInt8();
    if (isEnum(enumVariable, num)) {
      return num;
    } else E{
      throw invalidEnumErrorFormatter(num);
    }
  }
}