UNPKG

vtf-js

Version:

A javascript IO library for the Valve Texture Format.

244 lines (243 loc) 8.63 kB
const TE = new TextEncoder(); const TD = new TextDecoder(); /** * Wraps DataView with utility functions and pointer offsets. * This class is also available separately in the `stupid-buffer` npm package. */ export class DataBuffer extends Uint8Array { pointer = 0; view; little = true; constructor(buffer, byteOffset, length) { // @ts-expect-error When initializing a Uint8Array from another array, byteOffset and length // are disregarded for some reason. This is just a quick hack to make it work as expected. if (typeof buffer === 'object' && 'buffer' in buffer) buffer = buffer.buffer; // @ts-expect-error JUST MAKE IT WORK. super(buffer, byteOffset, length); this.view = new DataView(this.buffer, this.byteOffset, this.byteLength); } /** Sets the default endianness of the DataBuffer. */ set_endian(little) { this.little = little; } /** Creates a new DataBuffer within the specified bounds. */ ref(start = 0, length = this.length - start) { const buf = new DataBuffer(this.buffer, start + this.byteOffset, length); buf.set_endian(this.little); return buf; } /** Moves the pointer to the specified position. */ seek(position) { this.pointer = position; } /** Increments the pointer by the specified number of bytes. */ pad(length) { this.pointer += length; } /** Aligns the pointer to the nearest multiple specified, and pads a number of bytes if specified. */ align(multiple, offset) { this.pointer = (offset ?? 0) + this.pointer + (multiple - this.pointer % multiple) % multiple; } read_u8(length) { const start = this.pointer; if (length === undefined) { this.pointer++; return this.view.getUint8(start); } this.pointer += length; return new Uint8Array(this.slice(start, this.pointer)); } write_u8(value) { const start = this.pointer; if (typeof value === 'number') { this.pointer++; return this.view.setUint8(start, value); } this.pointer += value.length; this.set(value, start); return; } read_u16(length, little = this.little) { const start = this.pointer; if (length === undefined) { this.pointer += 2; return this.view.getUint16(start, little); } this.pointer += length * 2; const arr = new Uint16Array(length); for (let i = 0; i < length; i++) arr[i] = this.view.getUint16(start + i * 2, little); return arr; } write_u16(value, little = this.little) { const start = this.pointer; if (typeof value === 'number') { this.pointer += 2; return this.view.setUint16(start, value, little); } this.pointer += value.length * 2; for (let i = 0; i < value.length; i++) this.view.setUint16(start + i * 2, value[i], little); return; } read_u32(length, little = this.little) { const start = this.pointer; if (length === undefined) { this.pointer += 4; return this.view.getUint32(start, little); } this.pointer += length * 4; const arr = new Uint32Array(length); for (let i = 0; i < length; i++) arr[i] = this.view.getUint32(start + i * 4, little); return arr; } write_u32(value, little = this.little) { const start = this.pointer; if (typeof value === 'number') { this.pointer += 4; return this.view.setUint32(start, value, little); } this.pointer += value.length * 4; for (let i = 0; i < value.length; i++) this.view.setUint32(start + i * 4, value[i], little); return; } read_i8(length) { const start = this.pointer; if (length === undefined) { this.pointer++; return this.view.getInt8(start); } this.pointer += length; return new Int8Array(this.slice(start, this.pointer)); } write_i8(value) { const start = this.pointer; if (typeof value === 'number') { this.pointer++; return this.view.setInt8(start, value); } this.pointer += value.length; this.set(value, start); return; } read_i16(length, little = this.little) { const start = this.pointer; if (length === undefined) { this.pointer += 2; return this.view.getInt16(start, little); } this.pointer += length * 2; const arr = new Int16Array(length); for (let i = 0; i < length; i++) arr[i] = this.view.getInt16(start + i * 2, little); return arr; } write_i16(value, little = this.little) { const start = this.pointer; if (typeof value === 'number') { this.pointer += 2; return this.view.setInt16(start, value, little); } this.pointer += value.length * 2; for (let i = 0; i < value.length; i++) this.view.setInt16(start + i * 2, value[i], little); return; } read_i32(length, little = this.little) { const start = this.pointer; if (length === undefined) { this.pointer += 4; return this.view.getInt32(start, little); } this.pointer += length * 4; const arr = new Int32Array(length); for (let i = 0; i < length; i++) arr[i] = this.view.getInt32(start + i * 4, little); return arr; } write_i32(value, little = this.little) { const start = this.pointer; if (typeof value === 'number') { this.pointer += 4; return this.view.setInt32(start, value, little); } this.pointer += value.length * 4; for (let i = 0; i < value.length; i++) this.view.setInt32(start + i * 4, value[i], little); return; } read_f32(length, little = this.little) { const start = this.pointer; if (length === undefined) { this.pointer += 4; return this.view.getFloat32(start, little); } this.pointer += length * 4; const arr = new Float32Array(length); for (let i = 0; i < length; i++) arr[i] = this.view.getFloat32(start + i * 4, little); return arr; } write_f32(value, little = this.little) { const start = this.pointer; if (typeof value === 'number') { this.pointer += 4; return this.view.setFloat32(start, value, little); } this.pointer += value.length * 4; for (let i = 0; i < value.length; i++) this.view.setFloat32(start + i * 4, value[i], little); return; } read_f64(length, little = this.little) { const start = this.pointer; if (length === undefined) { this.pointer += 8; return this.view.getFloat64(start, little); } this.pointer += length * 8; const arr = new Float64Array(length); for (let i = 0; i < length; i++) arr[i] = this.view.getFloat64(start + i * 8, little); return arr; } write_f64(value, little = this.little) { const start = this.pointer; if (typeof value === 'number') { this.pointer += 8; return this.view.setFloat64(start, value, little); } this.pointer += value.length * 8; for (let i = 0; i < value.length; i++) this.view.setFloat64(start + i * 8, value[i], little); return; } read_str(length) { const start = this.pointer; let end = start + length; if (length === undefined) { for (end = start; end < this.length; end++) { if (this.view.getUint8(end) == 0) break; } this.pointer++; } this.pointer += end - start; return TD.decode(this.slice(start, end)); } write_str(str, length) { const start = this.pointer; this.pointer += str.length; this.set(TE.encode(str), start); if (length === undefined) { this.view.setUint8(this.pointer, 0); this.pointer++; } else if (str.length !== length) { throw RangeError('String of length ' + str.length + ' does not match write length of ' + length + '!'); } } }