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

59.4% Statements 60/101
23.33% Branches 7/30
42.85% Functions 9/21
58.33% Lines 56/96

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 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 21668x   68x 11x 11x 11x 11x     68x               68x 22x 22x 22x 22x 22x     68x         68x         68x                   68x                 68x                 68x                   68x                   68x 116x 116x 116x 116x 116x 116x 116x             298x                 68x 149x       149x   149x 149x   149x 149x 145x 145x 145x       149x 105x             68x                       346x 32x 333x       68x                                     68x       365x 365x 333x   32x 32x 32x             68x                 68x                   68x                    
import { ERRORS } from './buffer-constants';
 
export function writeUInt8(buffer: Uint8Array, value: number, offset: number): number {
  value = +value;
  offset = offset >>> 0;
  buffer[offset] = value & 0xff;
  return offset + 1;
}
 
export function writeUInt16LE(buffer: Uint8Array, value: number, offset: number): number {
  value = +value;
  offset = offset >>> 0;
  buffer[offset] = value & 0xff;
  buffer[offset + 1] = value >>> 8;
  return offset + 2;
}
 
export function writeUInt16BE(buffer: Uint8Array, value: number, offset: number): number {
  value = +value;
  offset = offset >>> 0;
  buffer[offset] = value >>> 8;
  buffer[offset + 1] = value & 0xff;
  return offset + 2;
}
 
export function readUInt8(buffer: Uint8Array, offset: number) {
  offset = offset >>> 0;
  return buffer[offset];
}
 
export function readUInt16LE(buffer: Uint8Array, offset: number) {
  offset = offset >>> 0;
  return buffer[offset] | (buffer[offset + 1] << 8);
}
 
export function readInt32LE(buffer: Uint8Array, offset: number): number {
  offset >>>= 0;
  return (
    buffer[offset] |
    (buffer[offset + 1] << 8) |
    (buffer[offset + 2] << 16) |
    (buffer[offset + 3] << 24)
  );
}
 
export function readUInt32LE(buffer: Uint8Array, offset: number): number {
  offset = offset >>> 0;
 
  return (
    (buffer[offset] | (buffer[offset + 1] << 8) | (buffer[offset + 2] << 16)) +
    buffer[offset + 3] * 0x1000000
  );
}
 
export function readUInt32BE(buffer: Uint8Array, offset: number) {
  offset = offset >>> 0;
 
  return (
    buffer[offset] * 0x1000000 +
    ((buffer[offset + 1] << 16) | (buffer[offset + 2] << 8) | buffer[offset + 3])
  );
}
 
export function writeUInt32LE(buffer: Uint8Array, value: number, offset: number): number {
  value = +value;
  offset >>>= 0;
  buffer[offset + 3] = value >>> 24;
  buffer[offset + 2] = value >>> 16;
  buffer[offset + 1] = value >>> 8;
  buffer[offset] = value & 0xff;
  return offset + 4;
}
 
export function writeInt32LE(buffer: Uint8Array, value: number, offset: number): number {
  value = +value;
  offset >>>= 0;
  buffer[offset] = value & 0xff;
  buffer[offset + 1] = value >>> 8;
  buffer[offset + 2] = value >>> 16;
  buffer[offset + 3] = value >>> 24;
  return offset + 4;
}
 
export function writeUInt32BE(buffer: Uint8Array, value: number, offset: number): number {
  value = +value;
  offset >>>= 0;
  buffer[offset] = value >>> 24;
  buffer[offset + 1] = value >>> 16;
  buffer[offset + 2] = value >>> 8;
  buffer[offset + 3] = value & 0xff;
  return offset + 4;
}
 
// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass
// the `instanceof` check but they should be treated as of that type.
// See: https://github.com/feross/buffer/issues/166
function isInstance(obj: any, type: any) {
  return (
    obj instanceof type ||
    (obj != null &&
      obj.constructor != null &&
      obj.constructor.name != null &&
      obj.constructor.name === type.name)
  );
}
 
export function compare(a: Uint8Array, b: Uint8Array) {
  Iif (!isInstance(a, Uint8Array) || !isInstance(b, Uint8Array)) {
    throw new TypeError('The "buf1", "buf2" arguments must be one of type Uint8Array');
  }
 
  Iif (a === b) return 0;
 
  let x = a.length;
  let y = b.length;
 
  for (let i = 0, len = Math.min(x, y); i < len; ++i) {
    if (a[i] !== b[i]) {
      x = a[i];
      y = b[i];
      break;
    }
  }
 
  if (x < y) return -1;
  if (y < x) return 1;
  return 0;
}
 
/**
 * Reads a Uint8Array from the internal read position.
 */
export function readBuffer(buffer: Uint8Array, length?: number): Uint8Array {
  const lengthVal = typeof length === 'number' ? length : buffer.length;
  const endPoint = Math.min(buffer.length, buffer.byteOffset + lengthVal);
 
  // Read buffer value
  return buffer.slice(buffer.byteOffset, endPoint);
}
 
function createEnumChecker<T extends string, TEnumValue extends number>(enumVariable: {
  [key in T]: TEnumValue;
}): (value: number) => value is TEnumValue {
  // Create a set of valid enum number values.
  const enumValues = Object.values<number>(enumVariable).filter(v => typeof v === 'number');
  const enumValueSet = new Set<number>(enumValues);
  return (value: number): value is TEnumValue => enumValueSet.has(value);
}
 
// eslint-disable-next-line @typescript-eslint/ban-types
const enumCheckFunctions = new Map<object, (value: number) => boolean>();
 
/**
 * Type guard to check if a given value is a valid enum value.
 * @param enumVariable - Literal `enum` type.
 * @param value - A value to check against the enum's values.
 * @example
 * ```ts
 * enum Color {
 *   Purple = 3,
 *   Orange = 5
 * }
 * const val: number = 3;
 * if (isEnum(Color, val)) {
 *   // `val` is known as enum type `Color`, e.g.:
 *   const colorVal: Color = val;
 * }
 * ```
 */
export function isEnum<T extends string, TEnumValue extends number>(
  enumVariable: { [key in T]: TEnumValue },
  value: number
): value is TEnumValue {
  const checker = enumCheckFunctions.get(enumVariable);
  if (checker !== undefined) {
    return checker(value);
  }
  const newChecker = createEnumChecker(enumVariable);
  enumCheckFunctions.set(enumVariable, newChecker);
  return isEnum(enumVariable, value);
}
 
/**
 * Determines whether a given number is a integer.
 * @param value The number to check.
 */
export function isInteger(value: number) {
  return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
}
 
/**
 * Checks if a given number is a finite integer. (Throws an exception if check fails)
 *
 * @param { Number } value The number value to check.
 */
export function isFiniteInteger(value: number): boolean {
  return typeof value === 'number' && isFinite(value) && isInteger(value);
}
 
/**
 * Checks if an offset/length value is valid. (Throws an exception if check fails)
 *
 * @param value The value to check.
 * @param offset True if checking an offset, false if checking a length.
 */
export function checkOffsetOrLengthValue(value: any, offset: boolean) {
  if (typeof value === 'number') {
    // Check for non finite/non integers
    Iif (!isFiniteInteger(value) || value < 0) {
      throw new Error(offset ? ERRORS.INVALID_OFFSET : ERRORS.INVALID_LENGTH);
    }
  } else {
    throw new Error(offset ? ERRORS.INVALID_OFFSET_NON_NUMBER : ERRORS.INVALID_LENGTH_NON_NUMBER);
  }
}