UNPKG

unpak.js

Version:

Modern TypeScript library for reading Unreal Engine pak files and assets, inspired by CUE4Parse

303 lines 8.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FArchive = void 0; const Exceptions_1 = require("../../exceptions/Exceptions"); const FName_1 = require("../objects/uobject/FName"); const VersionContainer_1 = require("../versions/VersionContainer"); /** * Generic UE4 Reader * @abstract */ class FArchive { constructor(versions = VersionContainer_1.VersionContainer.DEFAULT) { this.versions = versions; } /** * Contains versions * @type {VersionContainer} * @public */ versions; /** * Game that is used with this reader * @type {number} * @public */ get game() { return this.versions.game; } set game(v) { this.versions.game = v; } /** * Version that is used with this reader * @type {number} * @public */ get ver() { return this.versions.ver; } set ver(v) { this.versions.ver = v; } /** * Whether tagged property serialization is replaced by faster unversioned serialization * This assumes writer and reader share the same property definitions * @type {boolean} * @public */ useUnversionedPropertySerialization = false; /** * Whether editor only properties are being filtered from the archive (or has been filtered) * @type {boolean} * @public */ isFilterEditorOnly = true; /** * Reads an amount of bytes and returns them * @param {number} size Amount to read * @returns {Buffer} Read bytes or a byte if size not provided * @public * @abstract */ read(size) { const res = Buffer.alloc(size); this.readToBuffer(res); return res; } /** * Reads an 8-bit integer * @returns {number} Result * @public */ readInt8() { return this.read(1).readInt8(); } /** * Reads an unsigned 8-bit integer * @returns {number} Result * @public */ readUInt8() { return this.read(1).readUInt8(); } /** * Reads a 16-bit integer * @returns {number} Result * @public */ readInt16() { const b = this.read(2); return this.littleEndian ? b.readInt16LE() : b.readInt16BE(); } /** * Reads an unsigned 16-bit integer * @returns {number} Result * @public */ readUInt16() { const b = this.read(2); return this.littleEndian ? b.readUInt16LE() : b.readUInt16BE(); } /** * Reads a 32-bit integer * @returns {number} Result * @public */ readInt32() { const b = this.read(4); return this.littleEndian ? b.readInt32LE() : b.readInt32BE(); } /** * Reads an unsigned 32-bit integer * @returns {number} Result * @public */ readUInt32() { const b = this.read(4); return this.littleEndian ? b.readUInt32LE() : b.readUInt32BE(); } /** * Reads a 64-bit integer * @returns {bigint} Result * @public */ readInt64() { const b = this.read(8); return this.littleEndian ? b.readBigInt64LE() : b.readBigInt64BE(); } /** * Reads an unsigned 64-bit integer * @returns {bigint} Result * @public */ readUInt64() { const b = this.read(8); return this.littleEndian ? b.readBigUInt64LE() : b.readBigUInt64BE(); } /** * Reads bits * @param {Buffer} b Buffer to read * @param {number} offBytes Offset to use * @param {number} lenBits Amount of bits to read * @returns {void} * @public */ readBits(b, offBytes, lenBits) { this.readToBuffer(b, offBytes, (lenBits + 7) / 8); if (lenBits % 8) { b[offBytes + lenBits / 8] = b[offBytes + lenBits / 8] & (1 << (lenBits & 7)) - 1; } } /** * Reads a 32-bit float * @returns {number} Result * @public */ readFloat32() { const b = this.read(4); return this.littleEndian ? b.readFloatLE() : b.readFloatBE(); } /** * Reads a double * @returns {number} Result * @public */ readDouble() { const b = this.read(8); return this.littleEndian ? b.readDoubleLE() : b.readDoubleBE(); } /** * Reads a boolean * @returns {boolean} Result * @public */ readBoolean() { const int = this.readInt32(); if (int !== 0 && int !== 1) throw new Exceptions_1.ParserException(`Invalid boolean value (${int})`, this); return int !== 0; } /** * Reads a flag * @returns {boolean} Result * @public */ readFlag() { const int = this.readUInt8(); if (int !== 0 && int !== 1) throw new Exceptions_1.ParserException(`Invalid boolean value (${int})`, this); return int !== 0; } /** * Reads 32-bit int packed * @returns {number} Int * @public */ readIntPacked() { let value = 0; let cnt = 0; let more = true; while (more) { let nextByte = this.readUInt8(); more = (nextByte & 1) != 0; // Check 1 bit to see if theres more after this nextByte = nextByte >> 1; // Shift to get actual 7 bit value value += nextByte << (7 * cnt++); // Add to total value } return value; } /** * Reads a FString * @returns {string} Result * @public */ readString() { const length = this.readInt32(); if (length < -65536 || length > 65536) throw new Exceptions_1.ParserException(`Invalid String length '${length}'`, this); if (length < 0) { const utf16length = -length; const arrLength = utf16length - 1; const dat = []; for (let i = 0; i < arrLength; ++i) dat.push(this.readUInt16()); if (this.readUInt16() !== 0) throw new Exceptions_1.ParserException("Serialized FString is not null-terminated", this); return Buffer.from(dat).toString("utf16le"); } else { if (length === 0) return ""; const str = this.read(length - 1).toString("utf-8"); if (this.readUInt8() !== 0) throw new Exceptions_1.ParserException("Serialized FString is not null-terminated", this); return str; } } /** * Reads FName * @returns {FName} * @public */ readFName() { return FName_1.FName.NAME_None; } /** * Gets a custom version from guid * @param {FGuid} guid GUID of version to look for * @returns {number} Custom version */ customVersion(guid) { const ver = this.versions.customVersions ?.find(it => it.key.equals(guid))?.version; return ver == null ? -1 : ver; // '||' would replace 0 with -1, so check for null } /** * Reads a bulk array using the given callback * NOTICE: Lambdas usually decrease performance * @param {any} init Callback method to use for initiating array entries * @returns {any[]} Read array * @public */ readBulkArray(init) { const elementSize = this.readInt32(); const elementCount = this.readInt32(); const savePos = this.pos; const array = new Array(elementCount); for (let i = 0; i < elementCount; ++i) array[i] = init(i); if (this.pos != savePos + array.length * elementSize) throw new Exceptions_1.ParserException(`RawArray item size mismatch: expected ${elementSize}, serialized ${(this.pos - savePos) / array.length}`); return array; } /** * Reads a bulk array of bytes * NOTICE: Lambdas usually decrease performance * @returns {Buffer} Read Bytes * @see {readBulkArray} * @public */ readBulkByteArray() { const elemSize = this.readInt32(); const elemCount = this.readInt32(); return this.read(elemCount); } } exports.FArchive = FArchive; //# sourceMappingURL=FArchive.js.map