qvdjs 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/QvdErrors.js","../src/QvdSymbol.js","../src/util/validatePath.js","../src/util/bitUtils.js","../src/QvdFileWriter.js","../src/util/memoryUtils.js","../src/util/validationUtils.js","../src/util/symbolParser.js","../src/QvdColumnTable.js","../src/QvdFileReader.js","../src/QvdDataFrame.js","../src/index.js"],"names":["QvdError","QvdParseError","QvdValidationError","QvdIOError","QvdCorruptedError","QvdSecurityError","QvdSymbol","path","fs","QvdFileWriter","assert","crypto","xml","v8","os","QvdColumn","QvdColumnTable","QvdFileReader","QvdDataFrame"],"mappings":"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","file":"index.cjs","sourcesContent":["// @ts-check\n\n/**\n * Base error class for all QVD-related errors.\n * Provides structured error information with error codes and context.\n */\nexport class QvdError extends Error {\n /**\n * Constructs a new QVD error.\n *\n * @param {string} message The error message.\n * @param {string} code The error code.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, code, context = {}) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n this.context = context;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when parsing a QVD file fails.\n * Used for issues during XML header parsing, symbol table parsing, or index table parsing.\n */\nexport class QvdParseError extends QvdError {\n /**\n * Constructs a new QVD parse error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_PARSE_ERROR', context);\n }\n}\n\n/**\n * Error thrown when input validation fails.\n * Used for invalid parameters, out of bounds access, or missing required data.\n */\nexport class QvdValidationError extends QvdError {\n /**\n * Constructs a new QVD validation error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_VALIDATION_ERROR', context);\n }\n}\n\n/**\n * Error thrown when file system operations fail.\n * Used for issues reading or writing QVD files.\n */\nexport class QvdIOError extends QvdError {\n /**\n * Constructs a new QVD IO error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_IO_ERROR', context);\n }\n}\n\n/**\n * Error thrown when a QVD file is corrupted or malformed.\n * Used for missing headers, invalid data structures, or corrupted data.\n */\nexport class QvdCorruptedError extends QvdError {\n /**\n * Constructs a new QVD corrupted error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_CORRUPTED_ERROR', context);\n }\n}\n\n/**\n * Error thrown when security violations occur.\n * Used for path traversal attempts, XXE attacks, or other security issues.\n */\nexport class QvdSecurityError extends QvdError {\n /**\n * Constructs a new QVD security error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_SECURITY_ERROR', context);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * Represents a Qlik symbol/value, stored in a QVD file.\n */\nexport class QvdSymbol {\n /**\n * Constructs a new QVD symbol.\n *\n * @param {number|null} intValue The integer value.\n * @param {number|null} doubleValue The double value.\n * @param {string|null} stringValue The string value.\n */\n constructor(intValue, doubleValue, stringValue) {\n this._intValue = intValue;\n\n this._doubleValue = doubleValue;\n\n this._stringValue = stringValue;\n }\n\n /**\n * Returns the integer value of this symbol.\n *\n * @return {number|null} The integer value.\n */\n get intValue() {\n return this._intValue;\n }\n\n /**\n * Returns the double value of this symbol.\n *\n * @return {number|null} The double value.\n */\n get doubleValue() {\n return this._doubleValue;\n }\n\n /**\n * Returns the string value of this symbol.\n *\n * @return {string|null} The string value.\n */\n get stringValue() {\n return this._stringValue;\n }\n\n /**\n * Retrieves the primary value of this symbol. The primary value is descriptive raw value.\n * It is either the string value, the integer value or the double value, prioritized in this order.\n *\n * @return {number|string|null} The primary value.\n */\n toPrimaryValue() {\n if (null != this._stringValue) {\n return this._stringValue;\n } else if (null != this._intValue) {\n return this._intValue;\n } else if (null != this._doubleValue) {\n return this._doubleValue;\n } else {\n return null;\n }\n }\n\n /**\n * Converts the symbol to its byte representation.\n *\n * @return {Buffer} The byte representation of the symbol.\n */\n toByteRepresentation() {\n if (this._intValue !== null && this._stringValue !== null) {\n const intBuffer = Buffer.alloc(4);\n intBuffer.writeInt32LE(this._intValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n const stringBuffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([5]), intBuffer, stringBuffer]);\n } else if (this._doubleValue !== null && this._stringValue !== null) {\n const floatBuffer = Buffer.alloc(8);\n floatBuffer.writeDoubleLE(this._doubleValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n const stringBuffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([6]), floatBuffer, stringBuffer]);\n } else if (this._intValue !== null) {\n const buffer = Buffer.alloc(4);\n buffer.writeInt32LE(this._intValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([1]), buffer]);\n } else if (this._doubleValue !== null) {\n const buffer = Buffer.alloc(8);\n buffer.writeDoubleLE(this._doubleValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([2]), buffer]);\n } else if (this._stringValue !== null) {\n // @ts-ignore - Buffer.concat type compatibility\n const buffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([4]), buffer]);\n } else {\n throw new QvdValidationError('The symbol does not contain any value.', {\n intValue: this._intValue,\n doubleValue: this._doubleValue,\n stringValue: this._stringValue,\n });\n }\n }\n\n /**\n * Checks if this symbol is equal to another symbol.\n *\n * @param {*} value The object to compare with.\n * @return {boolean} True if the objects are equal, false otherwise.\n */\n equals(value) {\n if (!(value instanceof QvdSymbol)) {\n return false;\n }\n\n return (\n this._intValue === value.intValue &&\n this._doubleValue === value.doubleValue &&\n this._stringValue === value.stringValue\n );\n }\n\n /**\n * Constructs a pure integer value symbol.\n *\n * @param {number} intValue The integer value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromIntValue(intValue) {\n return new QvdSymbol(intValue, null, null);\n }\n\n /**\n * Constructs a pure double value symbol.\n *\n * @param {number} doubleValue The double value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDoubleValue(doubleValue) {\n return new QvdSymbol(null, doubleValue, null);\n }\n\n /**\n * Constructs a pure string value symbol.\n *\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromStringValue(stringValue) {\n return new QvdSymbol(null, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from an integer and a string value.\n *\n * @param {number} intValue The integer value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDualIntValue(intValue, stringValue) {\n return new QvdSymbol(intValue, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from a double and a string value.\n *\n * @param {number} doubleValue The double value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDualDoubleValue(doubleValue, stringValue) {\n return new QvdSymbol(null, doubleValue, stringValue);\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport {QvdSecurityError, QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Determines whether a resolved path is contained within a resolved base directory, using only\n * string comparison.\n *\n * This is the fallback for when the filesystem cannot answer the question - in practice, when\n * allowedDir does not exist. It cannot see through symlinks and has to guess at case\n * sensitivity, which is exactly why it is not the primary check.\n *\n * Uses path.relative() rather than a string prefix test, so that filesystem roots\n * ('/', 'C:\\', '\\\\server\\share\\') and base directories with a trailing separator are\n * handled correctly. A prefix test appends path.sep to the base, which produces '//'\n * for a root and therefore matches nothing.\n *\n * @param {string} resolvedBaseDir Absolute, resolved base directory.\n * @param {string} resolvedPath Absolute, resolved candidate path.\n * @return {boolean} True if the path is the base directory itself or lies beneath it.\n */\nfunction isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) {\n // Folding is applied on Windows only. It used to cover darwin as well, on the assumption that\n // macOS is always case-insensitive, but macOS supports case-sensitive APFS and HFS+ volumes on\n // which two names differing only in case are genuinely different directories - so folding there\n // let a sibling directory pass the check. The on-disk comparison below settles case correctly\n // by asking the filesystem, which is why this fallback no longer needs to guess for darwin.\n const isCaseInsensitiveFS = process.platform === 'win32';\n const base = isCaseInsensitiveFS ? resolvedBaseDir.toLowerCase() : resolvedBaseDir;\n const target = isCaseInsensitiveFS ? resolvedPath.toLowerCase() : resolvedPath;\n\n const relative = path.relative(base, target);\n\n // '' means the path IS the base directory. A relative path that starts with '..' escapes\n // the base, and an absolute result means the two are on different roots/drives.\n if (relative === '') {\n return true;\n }\n if (path.isAbsolute(relative)) {\n return false;\n }\n return relative !== '..' && !relative.startsWith(`..${path.sep}`);\n}\n\n/**\n * Resolves the deepest ancestor of a path that actually exists, following symlinks.\n *\n * A path being written to does not exist yet, and neither may some of its parent directories, so\n * realpath() on the full path would simply fail. Walking up to the first component that does\n * exist gives the deepest point the filesystem can vouch for; anything below it is a name that\n * will be created inside that directory.\n *\n * @param {string} target Absolute, lexically resolved path.\n * @return {string|null} Canonical path of the deepest existing ancestor, or null if it could not\n * be determined.\n */\nfunction resolveDeepestExisting(target) {\n let current = target;\n\n for (;;) {\n try {\n return fs.realpathSync(current);\n } catch (error) {\n const code = /** @type {{code?: string}} */ (error)?.code;\n\n // ENOENT: this component does not exist. ENOTDIR: an ancestor is a file, so nothing below\n // it can exist either. Both mean \"keep walking up\". Anything else (EACCES, ELOOP) means the\n // filesystem cannot answer, and the caller falls back to the lexical test - which is safe,\n // because an open() on the same path is about to fail for the same reason.\n if (code !== 'ENOENT' && code !== 'ENOTDIR') {\n return null;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n }\n}\n\n/**\n * Determines whether a path is contained within a base directory by asking the filesystem.\n *\n * Both sides are resolved through symlinks and then compared by identity - device and inode -\n * rather than by name, walking up from the target until the base is found or the root is reached.\n * That settles two questions a string comparison cannot:\n *\n * - Symlinks. A link inside allowedDir pointing outside it resolves to its target, so it is\n * rejected. A lexical check sees only the link's own name, still under allowedDir, and lets it\n * through - which meant arbitrary read via the reader and arbitrary overwrite via the writer.\n * - Case. On a case-insensitive volume 'Qvd' and 'qvd' are one directory and share an inode; on a\n * case-sensitive volume they are two directories with different inodes. Comparing identity gets\n * both right without inferring anything from process.platform, which is what the old code did\n * and got wrong on case-sensitive macOS volumes.\n *\n * This is a check on the path, so it is inherently subject to a race: a symlink swapped in\n * between this call and the subsequent open would defeat it. Closing that would require opening\n * with O_NOFOLLOW and verifying the descriptor, which is a larger change to the reader and\n * writer than this function can make on its own.\n *\n * @param {string} resolvedBaseDir Absolute, lexically resolved base directory.\n * @param {string} resolvedPath Absolute, lexically resolved candidate path.\n * @return {boolean|null} True or false when the filesystem could answer, null when it could not.\n */\nfunction isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {\n /** @type {import('fs').Stats} */\n let baseStat;\n\n try {\n // The base has to exist to be identified. If it does not, there is nothing on disk to compare\n // against and the lexical fallback is all that is left.\n baseStat = fs.statSync(fs.realpathSync(resolvedBaseDir));\n } catch {\n return null;\n }\n\n let current = resolveDeepestExisting(resolvedPath);\n if (current === null) {\n return null;\n }\n\n // realpathSync() returns a fully canonical path, so every ancestor of it is canonical too and\n // walking up with dirname() cannot step through a symlink.\n for (;;) {\n let stat;\n try {\n stat = fs.statSync(current);\n } catch {\n return null;\n }\n\n if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {\n return true;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return false;\n }\n current = parent;\n }\n}\n\n/**\n * Validates that a file path stays inside the allowed directory.\n *\n * Containment is decided by the filesystem wherever it can be: both paths are resolved through\n * symlinks and compared by device and inode. That covers symlink escapes and case sensitivity,\n * neither of which a string comparison can get right. When the base directory does not exist,\n * there is nothing to compare against and a lexical check is used instead.\n *\n * To permit access to an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on\n * Windows). There is deliberately no separate \"disable the check\" value: a null or empty\n * allowedDir falls back to the current working directory, so a caller that accidentally\n * passes one still gets the restriction rather than silently losing it.\n *\n * @param {string} filePath The path to validate.\n * @param {string|null} [allowedDir] Optional allowed directory path. Defaults to the current\n * working directory to prevent path traversal attacks.\n * @throws {QvdValidationError} If filePath is not a non-empty string, or allowedDir is not a\n * string, null or undefined.\n * @throws {QvdSecurityError} If path traversal is detected.\n * @return {string} The resolved absolute path. This is the lexically resolved path, not the\n * canonical one, so callers see the path they asked for.\n */\nexport function validatePath(filePath, allowedDir) {\n // Validate argument types up front, so callers get a typed error instead of a bare TypeError\n // from deep inside the function (e.g. 'filePath.includes is not a function').\n if (typeof filePath !== 'string' || filePath.length === 0) {\n throw new QvdValidationError('filePath must be a non-empty string', {\n provided: filePath,\n type: typeof filePath,\n });\n }\n\n if (allowedDir !== undefined && allowedDir !== null && typeof allowedDir !== 'string') {\n throw new QvdValidationError('allowedDir must be a string, null or undefined', {\n provided: allowedDir,\n type: typeof allowedDir,\n });\n }\n\n // Check for null bytes which can be used in path traversal attacks\n if (filePath.includes('\\0')) {\n throw new QvdSecurityError('Path traversal detected: Null byte in path', {\n path: filePath,\n reason: 'null_byte',\n });\n }\n\n const resolvedPath = path.resolve(filePath);\n\n // Default to the current working directory when no allowed directory is specified. This\n // prevents path traversal attacks by ensuring files can only be accessed within the CWD\n // or a more restrictive allowed directory.\n //\n // null and '' deliberately fall back to the CWD rather than meaning \"no restriction\":\n // callers routinely produce them from optional config or a JSON round trip, and silently\n // dropping the sandbox in that case would be a security hole. A caller that genuinely wants\n // an entire volume passes its root ('/' or 'C:\\\\'), which the containment test supports.\n const baseDir = allowedDir || process.cwd();\n const resolvedBaseDir = path.resolve(baseDir);\n\n const onDisk = isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath);\n const contained = onDisk === null ? isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) : onDisk;\n\n if (!contained) {\n throw new QvdSecurityError('Path traversal detected: Access denied', {\n path: filePath,\n resolvedPath,\n allowedDir: resolvedBaseDir,\n reason: 'outside_allowed_directory',\n // Says which check refused, so a rejection of a path that looks contained is traceable to\n // a symlink or a case difference rather than looking like a bug.\n check: onDisk === null ? 'lexical' : 'filesystem',\n });\n }\n\n return resolvedPath;\n}\n","// @ts-check\n\n/**\n * Largest `BitWidth` a field may declare.\n *\n * A stored index is an offset into the field's symbol table, and it is kept in an `Int32Array`,\n * so it has to fit in a positive 32-bit integer. 31 bits addresses 2,147,483,647 symbols in a\n * single field - orders of magnitude beyond anything the rest of the library will load, since\n * the symbol table for that many values would be terabytes and the memory guard refuses long\n * before. A file declaring more is refused rather than decoded: at 32 bits the top of the range\n * wraps to a negative index, and a negative index means NULL, so the failure would be silently\n * wrong values instead of an error. That is the shape of bug #113 was.\n */\nexport const MAX_BIT_WIDTH = 31;\n\n/**\n * Powers of two up to 2^39, the widest window a field can span: at most 7 bits of byte\n * misalignment plus `MAX_BIT_WIDTH`. Every value here is exactly representable as a double, and\n * so is every intermediate the decoder forms, which is why the arithmetic below can use `/` and\n * `%` on Numbers rather than 32-bit bitwise operators - those would overflow at 32 bits.\n */\nconst POW2 = Array.from({length: 41}, (_, exponent) => 2 ** exponent);\n\n/**\n * Where a field's bits sit inside a record.\n *\n * Both directions need this, and they must not derive it separately. Two copies of\n * `(shift + bitWidth + 7) >> 3` that drift apart write files this library cannot read, and\n * nothing throws - the decode simply starts a byte early and every field after the first\n * straddling one is misaligned. That is #113's failure shape pointed the other way, so the\n * derivation lives here and the encoder, the decoder and their tests all call it.\n *\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits; zero means it occupies no bits at all.\n * @return {{byteStart: number, shift: number, byteCount: number}} The field's byte window:\n * where it starts, how far into that byte it begins, and how many bytes it touches (0 when\n * the width is zero, otherwise 1 to 5).\n */\nexport function fieldGeometry(bitOffset, bitWidth) {\n const shift = bitOffset & 7;\n\n return {\n byteStart: bitOffset >>> 3,\n shift,\n byteCount: bitWidth === 0 ? 0 : (shift + bitWidth + 7) >>> 3,\n };\n}\n\n/**\n * Decodes one bit-packed field out of every record of an index table.\n *\n * ## The layout\n *\n * A record is `recordSize` bytes. Numbering its bits `p = 0, 1, 2, ...`, bit `p` is\n * `(byte[p >> 3] >> (p & 7)) & 1` - little-endian, least significant bit of each byte first. A\n * field occupies `bitWidth` consecutive bits starting at `bitOffset`, least significant bit\n * first, and `Bias` is then added to the value read.\n *\n * This is the same layout the previous implementation produced, by a much longer route: it\n * reversed the record's bytes, concatenated their binary spellings into a string of\n * `recordSize * 8` characters, split that into an array of one number per bit, reversed it, then\n * sliced the array per field and summed `bit * Math.pow(2, index)`. Several arrays the length of\n * the record in *bits*, built and discarded for every row, which is where roughly 98% of a full\n * read went.\n *\n * ## Why the arithmetic is not bitwise\n *\n * JavaScript's `<<`, `>>>` and `&` coerce to 32 bits, and a field can span up to 39 bits once\n * byte misalignment is counted. `Math.floor(acc / 2**shift) % 2**bitWidth` is exact for every\n * value this can form, because the widest accumulator is under 2^40 and doubles are exact to\n * 2^53.\n *\n * @param {Buffer|Uint8Array} buffer The index table, starting at the first record.\n * @param {number} recordSize Bytes per record.\n * @param {number} rowCount Number of records to decode.\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits. Zero means the field holds a single\n * distinct value and occupies no bits at all.\n * @param {number} bias Added to every decoded value. Qlik writes -2 for a field containing\n * NULLs, where stored index 0 means NULL and real symbols start at 2.\n * @param {Int32Array} out Destination, at least `rowCount` long.\n * @return {Int32Array} `out`.\n */\nexport function decodeIndexColumn(buffer, recordSize, rowCount, bitOffset, bitWidth, bias, out) {\n // A single-distinct-value column occupies zero bits, so there is nothing to read: every row\n // holds stored index 0, which is `bias` once the bias is applied.\n if (bitWidth === 0) {\n out.fill(bias, 0, rowCount);\n return out;\n }\n\n const {byteStart, shift, byteCount} = fieldGeometry(bitOffset, bitWidth);\n\n const divisor = POW2[shift];\n const modulus = POW2[bitWidth];\n\n // byteStart + byteCount is at most recordSize - validateFieldBitMetadata has already required\n // bitOffset + bitWidth <= recordSize * 8 - so every read below is inside the record, and the\n // caller has established that `rowCount` whole records are present.\n let base = byteStart;\n\n for (let row = 0; row < rowCount; row++, base += recordSize) {\n let acc = buffer[base];\n\n if (byteCount > 1) acc += buffer[base + 1] * 0x100;\n if (byteCount > 2) acc += buffer[base + 2] * 0x10000;\n if (byteCount > 3) acc += buffer[base + 3] * 0x1000000;\n if (byteCount > 4) acc += buffer[base + 4] * 0x100000000;\n\n out[row] = (Math.floor(acc / divisor) % modulus) + bias;\n }\n\n return out;\n}\n\n/**\n * Writes one bit-packed field into one record. The inverse of `decodeIndexColumn`.\n *\n * Same layout, written the other way: bit `p` of a record is `(byte[p >> 3] >> (p & 7)) & 1`,\n * so a value is shifted left by the field's `shift` and OR-ed across the bytes it touches. The\n * buffer must start zeroed and fields must not overlap, which the caller guarantees by\n * allocating it with `Buffer.alloc` and laying columns out by prefix sum of their widths.\n *\n * Multiplication rather than `<<` for the same reason the decoder divides rather than `>>>`: a\n * field can span 39 bits once misalignment is counted, and JavaScript's bitwise operators stop\n * at 32. Every intermediate here is under 2^40, well inside what a double represents exactly.\n *\n * It takes the geometry rather than a `bitOffset`, so the caller cannot derive the byte window\n * differently from the way `decodeIndexColumn` derives it - see `fieldGeometry`. A zero-width\n * field writes nothing, matching the decoder's zero-width branch, which reads nothing; the\n * first byte used to be written unconditionally, so a `byteCount` of 0 put the value into the\n * next column's bits.\n *\n * @param {Buffer|Uint8Array} buffer The index table being built.\n * @param {number} recordBase Index of the record's first byte.\n * @param {{byteStart: number, shift: number, byteCount: number}} geometry From `fieldGeometry`.\n * @param {number} value The stored index. Must fit in the field's width; the caller checks.\n */\nexport function writeBitField(buffer, recordBase, geometry, value) {\n const {byteStart, shift, byteCount} = geometry;\n\n if (byteCount === 0) {\n return;\n }\n\n const base = recordBase + byteStart;\n const shifted = value * POW2[shift];\n\n buffer[base] |= shifted % 0x100;\n\n if (byteCount > 1) buffer[base + 1] |= Math.floor(shifted / 0x100) % 0x100;\n if (byteCount > 2) buffer[base + 2] |= Math.floor(shifted / 0x10000) % 0x100;\n if (byteCount > 3) buffer[base + 3] |= Math.floor(shifted / 0x1000000) % 0x100;\n if (byteCount > 4) buffer[base + 4] |= Math.floor(shifted / 0x100000000) % 0x100;\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\nimport xml from 'xml2js';\nimport assert from 'assert';\nimport {QvdSymbol} from './QvdSymbol.js';\nimport {QvdValidationError} from './QvdErrors.js';\nimport {validatePath} from './util/validatePath.js';\nimport {fieldGeometry, writeBitField} from './util/bitUtils.js';\n\n/**\n * @typedef {import('./QvdDataFrame.js').QvdDataFrame} QvdDataFrame\n */\n\n/**\n * Persists a QVD file to disk.\n */\nexport class QvdFileWriter {\n /**\n * Constructs a new QVD file writer.\n *\n * @param {string} filePath The path to the QVD file to write.\n * @param {QvdDataFrame} df The data frame to write to the QVD file.\n * @param {Object} [options={}] Options for the writer.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function.\n */\n constructor(filePath, df, options = {}) {\n const {allowedDir, onProgress} = options;\n this._path = validatePath(filePath, allowedDir);\n this._df = df;\n this._onProgress = onProgress;\n this._header = null;\n this._symbolBuffer = null;\n /** @type {Array<Array<import('./QvdSymbol.js').QvdSymbol>>|null} */\n this._symbolTable = null;\n /** @type {Array<any>|null} */\n this._symbolTableMetadata = null;\n this._indexBuffer = null;\n /**\n * Stored index for each distinct value of each column, keyed by the raw value.\n *\n * Built while the symbol table is, because that pass already decides the order symbols are\n * written in and therefore what each index is. The alternative - re-deriving it here from\n * a QvdSymbol and a template-literal key per cell - meant converting every cell twice and\n * allocating 34 million strings on the taxi fixture to look up something already known.\n *\n * @type {Array<Map<any, number>>|null}\n */\n this._symbolIndexByValue = null;\n /** @type {Array<any>|null} */\n this._indexTableMetadata = null;\n /** Rows written, kept because the index table is no longer an array to count. @type {number} */\n this._recordCount = 0;\n this._recordByteSize = null;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * @param {string} stage The current stage of the operation.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n this._onProgress({\n stage,\n current,\n total,\n percent,\n });\n }\n }\n\n /**\n * Writes the data to the QVD file.\n */\n async _writeData() {\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolBuffer, 'The QVD file symbol table has not been parsed.');\n assert(this._indexBuffer, 'The QVD file index table has not been parsed.');\n\n this._emitProgress('write', 0, 1);\n\n // @ts-ignore - Buffer.concat type compatibility\n const headerBuffer = Buffer.concat([Buffer.from(this._header, 'utf-8'), Buffer.from([0])]);\n\n let fd;\n try {\n fd = await fs.promises.open(this._path, 'w');\n await fd.write(headerBuffer, 0, headerBuffer.length, 0);\n await fd.write(this._symbolBuffer, 0, this._symbolBuffer.length, headerBuffer.length);\n await fd.write(this._indexBuffer, 0, this._indexBuffer.length, headerBuffer.length + this._symbolBuffer.length);\n this._emitProgress('write', 1, 1);\n } finally {\n if (fd) {\n await fd.close();\n }\n }\n }\n\n /**\n * Builds the XML header of the QVD file.\n */\n _buildHeader() {\n this._emitProgress('header', 0, 1);\n const creationDate = new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '');\n /** @type {import('./QvdDataFrame.js').QvdMetadata|null} */\n const existingMetadata = this._df.metadata;\n\n // Use existing metadata if available, otherwise create default values\n const baseMetadata = existingMetadata\n ? {\n QvBuildNo: existingMetadata.QvBuildNo || 50667,\n CreatorDoc: existingMetadata.CreatorDoc || crypto.randomUUID(),\n CreateUtcTime: existingMetadata.CreateUtcTime || creationDate,\n SourceCreateUtcTime: existingMetadata.SourceCreateUtcTime || '',\n SourceFileUtcTime: existingMetadata.SourceFileUtcTime || '',\n SourceFileSize: existingMetadata.SourceFileSize || -1,\n StaleUtcTime: existingMetadata.StaleUtcTime || '',\n TableName: existingMetadata.TableName || path.basename(this._path, path.extname(this._path)),\n Compression: existingMetadata.Compression || '',\n Comment: existingMetadata.Comment || '',\n EncryptionInfo: existingMetadata.EncryptionInfo || '',\n TableTags: existingMetadata.TableTags || '',\n ProfilingData: existingMetadata.ProfilingData || '',\n Lineage: existingMetadata.Lineage || {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n }\n : {\n QvBuildNo: 50667,\n CreatorDoc: crypto.randomUUID(),\n CreateUtcTime: creationDate,\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: path.basename(this._path, path.extname(this._path)),\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n };\n\n // Get existing field metadata if available\n /** @type {any[]} */\n let existingFields = [];\n if (existingMetadata && existingMetadata.Fields && existingMetadata.Fields.QvdFieldHeader) {\n existingFields = Array.isArray(existingMetadata.Fields.QvdFieldHeader)\n ? existingMetadata.Fields.QvdFieldHeader\n : [existingMetadata.Fields.QvdFieldHeader];\n }\n\n const xmlObject = {\n QvdTableHeader: {\n ...baseMetadata,\n Fields: {\n QvdFieldHeader: this._df.columns.map((/** @type {any} */ column, /** @type {number} */ index) => {\n // Find existing field metadata for this column\n const existingField = existingFields.find((/** @type {any} */ f) => f.FieldName === column);\n\n return {\n FieldName: column,\n BitOffset: this._indexTableMetadata?.[index][0],\n BitWidth: this._indexTableMetadata?.[index][1],\n Bias: this._indexTableMetadata?.[index][2],\n NoOfSymbols: this._symbolTable?.[index].length,\n Offset: this._symbolTableMetadata?.[index][0],\n Length: this._symbolTableMetadata?.[index][1],\n Comment: existingField?.Comment || '',\n NumberFormat: existingField?.NumberFormat || {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: existingField?.Tags || {},\n };\n }),\n },\n NoOfRecords: this._recordCount,\n RecordByteSize: this._recordByteSize,\n Offset:\n this._symbolTableMetadata && this._symbolTableMetadata.length > 0\n ? this._symbolTableMetadata[this._symbolTableMetadata.length - 1][0] +\n this._symbolTableMetadata[this._symbolTableMetadata.length - 1][1]\n : 0,\n Length: this._indexBuffer?.length,\n },\n };\n\n const builder = new xml.Builder({\n renderOpts: {\n pretty: true,\n newline: '\\r\\n',\n indent: ' ',\n },\n });\n this._header = builder.buildObject(xmlObject) + '\\r\\n';\n this._emitProgress('header', 1, 1);\n }\n\n /**\n * Builds the symbol table of the QVD file.\n *\n * PERFORMANCE OPTIMIZATION: This method uses a single-pass algorithm to build\n * symbol tables for all columns simultaneously. This reduces time complexity from\n * O(n×m×s) to O(n×m) where n=rows, m=columns, s=symbols per column.\n *\n * Algorithm:\n * 1. Initialize a Set for each column to collect unique values\n * 2. Single pass through all data rows, adding values to corresponding Sets\n * 3. Convert Sets to arrays and create QvdSymbol instances\n * 4. Serialize symbols to binary format and update metadata\n *\n * This approach provides:\n * - 80-90% performance improvement for large datasets (100K+ rows)\n * - Better cache locality (process all columns in one data traversal)\n * - Lower memory pressure (no intermediate arrays per column)\n *\n * @private\n */\n _buildSymbolTable() {\n this._symbolTable = [];\n this._symbolTableMetadata = [];\n this._symbolIndexByValue = [];\n\n // A table with no fields is not a QVD. Writing one produced a 741-byte file with an empty\n // `<Fields/>` element that this same library refuses to load, which is the worst of both:\n // the write reports success and the failure surfaces later, somewhere else.\n if (this._df.columns.length === 0) {\n throw new QvdValidationError('A QVD file must have at least one field', {\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numColumns = columns.length;\n const numRows = data.length;\n\n this._emitProgress('symbol-table', 0, numColumns);\n\n // One Map per column, from raw value to the stored index that value will get, built in the\n // single pass over the data that also discovers the distinct values.\n //\n // This used to be a Set per column, then `Array.from` on it, then a Map built from the\n // array - three structures each holding a reference to every distinct value, where one is\n // needed. On a column whose values are all distinct that was roughly 30MB of duplication\n // per million rows, and it bought nothing: a Map preserves insertion order exactly as a Set\n // does, so the indices it hands out are the same ones the array walk produced.\n /** @type {Array<Map<any, number>>} */\n const indexByValue = columns.map(() => new Map());\n /** @type {Array<boolean>} */\n const containsNull = columns.map(() => false);\n\n // A counted loop, not `data.forEach`. forEach skips array holes and the index table's loop\n // does not, so a sparse `data` array made the two passes disagree about how many rows\n // exist: a five-element array with one row set wrote a five-row file in which four rows\n // carried a real value copied from the fifth, and a hole between two rows threw a bare\n // TypeError. A hole reads as `undefined`, which is what this writer already treats as NULL\n // everywhere else, so both passes now see the same rows and a hole becomes a NULL row.\n for (let row = 0; row < numRows; row++) {\n const values = data[row];\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n containsNull[column] = true;\n continue;\n }\n\n const map = indexByValue[column];\n\n if (!map.has(value)) {\n map.set(value, map.size);\n }\n }\n }\n\n // Serialised per column and concatenated once. Concatenating onto an accumulating buffer\n // instead re-copies every byte written so far on each column - O(bytes x columns), which\n // measured 26ms against 14ms on a 67MB symbol table and gets worse linearly with the column\n // count, while transiently holding two copies of everything written so far.\n /** @type {Array<Buffer>} */\n const columnBuffers = [];\n let symbolsOffset = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const symbols = Array.from(indexByValue[column].keys(), (value) => QvdFileWriter._convertRawToSymbol(value));\n\n // @ts-ignore - Symbol byte representation\n const columnBuffer = Buffer.concat(symbols.map((symbol) => symbol.toByteRepresentation()));\n\n columnBuffers.push(columnBuffer);\n this._symbolTableMetadata?.push([symbolsOffset, columnBuffer.length, containsNull[column]]);\n // @ts-ignore - Symbol array type compatibility\n this._symbolTable?.push(symbols);\n this._symbolIndexByValue.push(indexByValue[column]);\n\n symbolsOffset += columnBuffer.length;\n\n this._emitProgress('symbol-table', column + 1, numColumns);\n }\n\n // @ts-ignore - Buffer.concat type compatibility\n this._symbolBuffer = Buffer.concat(columnBuffers);\n }\n\n /**\n * Builds the bit-packed index table of the QVD file.\n *\n * A record is `recordByteSize` bytes. Each column occupies `bitWidth` consecutive bits at\n * `bitOffset`, least significant bit first, where bit `p` of a record is\n * `(byte[p >> 3] >> (p & 7)) & 1`. `Bias` is -2 for a column containing NULLs: stored index 0\n * means NULL, and real symbols start at 2. This is exactly what the reader's\n * `decodeIndexColumn` undoes, and `writeBitField` is its inverse.\n *\n * The previous implementation went the long way round. Per cell it converted the raw value to\n * a QvdSymbol - a second time, the symbol table pass having already done it - to build a\n * template-literal lookup key, then turned the resulting index into a string of bits via\n * `toString(2).split('').map().reverse().concat().slice().reverse()`. Per row it kept an array\n * of those strings, padded each with `padStart`, reversed and joined them, split the result\n * with `/.{1,8}/g`, and allocated a Buffer; then `Buffer.concat` over one Buffer per row. On\n * the 1.7M-row taxi fixture that is 34 million symbols, 34 million key strings, 34 million bit\n * strings and 1.7 million Buffers, and it accounted for 98% of a write.\n *\n * Now: the widths are derived from the symbol counts, the offsets by prefix sum, one Buffer is\n * allocated for the whole table, and each value is OR-ed into place as an integer.\n *\n * @private\n */\n _buildIndexTable() {\n assert(this._symbolTable, 'The QVD file symbol table has not been built.');\n assert(this._symbolTableMetadata, 'The QVD file symbol table metadata has not been built.');\n assert(this._symbolIndexByValue, 'The QVD file symbol index has not been built.');\n\n this._indexTableMetadata = [];\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numRows = data.length;\n const numColumns = columns.length;\n\n this._recordCount = numRows;\n this._emitProgress('index-table', 0, numRows);\n\n // Layout, one entry per column, hoisted out of the row loop so the inner loop does\n // arithmetic into a buffer and nothing else.\n /** @type {Array<{geometry: {byteStart: number, shift: number, byteCount: number}, nullShift: number}>} */\n const layout = [];\n\n let totalBits = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const fieldContainsNull = this._symbolTableMetadata[column][2];\n const symbolCount = this._symbolTable[column].length;\n const nullShift = fieldContainsNull ? 2 : 0;\n\n // The largest stored index is (symbolCount - 1), shifted by 2 when the column contains\n // NULLs (index 0 denotes NULL and indices start at 2, which is what Bias=-2 encodes).\n //\n // Deriving the width this way is O(1) per column instead of O(rows), and it avoids\n // Math.max(...oneArgumentPerRow), which overflows the call stack somewhere around\n // 120k rows and made toQvd() unusable for realistic table sizes.\n const maxStoredIndex = symbolCount === 0 ? 0 : symbolCount - 1 + nullShift;\n\n // A single distinct value needs no bits at all, which matches what Qlik emits.\n const bitWidth = maxStoredIndex === 0 ? 0 : 32 - Math.clz32(maxStoredIndex);\n\n // Every index the row loop can write, checked once per column rather than once per cell.\n //\n // The row loop writes either 0, for NULL, or a value from this map, so validating the\n // map validates every write - 28,512 checks on the taxi fixture instead of 34 million,\n // and it covers the zero-width columns the per-cell check used to skip past. The bound is\n // the symbol count, not the field's capacity: a per-cell `storedIndex >= 2 ** bitWidth`\n // admitted indices in the gap between the two, which address no symbol and read back as\n // NULL with nothing thrown.\n for (const index of this._symbolIndexByValue[column].values()) {\n if (index + nullShift > maxStoredIndex) {\n throw new QvdValidationError('The symbol table and the index table are out of sync', {\n field: columns[column],\n storedIndex: index + nullShift,\n maxStoredIndex,\n symbolCount,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n }\n\n layout.push({geometry: fieldGeometry(totalBits, bitWidth), nullShift});\n\n this._indexTableMetadata.push([totalBits, bitWidth, fieldContainsNull ? -2 : 0]);\n\n totalBits += bitWidth;\n }\n\n // Every column may have a bit width of 0 - each holds a single distinct value, or only\n // NULLs - leaving no bits at all. Qlik still uses a one-byte record in that situation, and\n // a zero-byte record would be rejected on read.\n const recordByteSize = Math.max(1, Math.ceil(totalBits / 8));\n\n this._recordByteSize = recordByteSize;\n this._indexBuffer = Buffer.alloc(numRows * recordByteSize);\n\n const progressInterval = Math.max(1, Math.floor(numRows / 100)); // Report progress every 1%\n\n for (let row = 0, recordBase = 0; row < numRows; row++, recordBase += recordByteSize) {\n const values = data[row];\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n // NULL is stored index 0, which the bias turns back into a negative index on read.\n // Nothing to write: the buffer is already zeroed.\n continue;\n }\n\n const index = this._symbolIndexByValue[column].get(value);\n\n // A value the symbol table never saw. Unreachable while both passes walk the same rows,\n // which is the point of them sharing a counted loop - but the old code absorbed this\n // with `?? 0`, writing the first real symbol in place of the missing value, so a whole\n // column could read back as some other value with nothing thrown.\n if (index === undefined) {\n throw new QvdValidationError('A value is missing from the symbol table', {\n field: columns[column],\n row,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n\n writeBitField(this._indexBuffer, recordBase, layout[column].geometry, index + layout[column].nullShift);\n }\n\n // Report progress periodically\n if ((row + 1) % progressInterval === 0 || row + 1 === numRows) {\n this._emitProgress('index-table', row + 1, numRows);\n }\n }\n\n // The maps are dead once the table is packed, and the writer stays alive through the header\n // build and the file write - the point at which the symbol buffer and the index buffer are\n // both resident.\n this._symbolIndexByValue = null;\n }\n\n /**\n * Converts a raw value/literal to a QVD symbol.\n *\n * @param {any} raw The raw value/literal to convert.\n * @return {QvdSymbol|null} The converted QVD symbol.\n */\n static _convertRawToSymbol(raw) {\n if (raw === null || raw === undefined) {\n return null;\n }\n\n const INT32_MIN = -2147483648;\n const INT32_MAX = 2147483647;\n\n const isInteger = typeof raw === 'number' && Number.isInteger(raw);\n const isFloat = typeof raw === 'number' && !Number.isInteger(raw);\n const isWithinInt32Range = typeof raw === 'number' && raw >= INT32_MIN && raw <= INT32_MAX;\n\n if (isInteger && isWithinInt32Range) {\n return QvdSymbol.fromDualIntValue(raw, raw.toString());\n } else if (isFloat || (isInteger && !isWithinInt32Range)) {\n return QvdSymbol.fromDualDoubleValue(raw, raw.toString());\n } else {\n return QvdSymbol.fromStringValue(raw);\n }\n }\n\n /**\n * Persists the data frame to a QVD file.\n */\n async save() {\n this._buildSymbolTable();\n this._buildIndexTable();\n this._buildHeader();\n await this._writeData();\n }\n}\n","// @ts-check\n\nimport os from 'os';\nimport v8 from 'v8';\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Gets the configured V8 heap size limit for the current Node.js process.\n * This respects the --max-old-space-size flag if set.\n *\n * @returns {number} Heap size limit in bytes\n */\nexport function getHeapLimit() {\n return v8.getHeapStatistics().heap_size_limit;\n}\n\n/**\n * Whether v8.getHeapStatistics().heap_size_limit means what it says on this runtime.\n *\n * Bun reports its *current* heap there rather than a ceiling - 229MB on a machine with 128GB of\n * RAM - so treating it as a limit rejects almost everything. It cannot be detected structurally\n * either: Bun spoofs both process.versions.v8 and process.versions.node, so the runtime's own\n * key is the only reliable signal.\n *\n * @return {boolean} True when the heap limit is a real limit.\n */\nfunction heapLimitIsMeaningful() {\n return !process.versions.bun && !process.versions.deno;\n}\n\n/**\n * Works out how much memory this process may actually use, and which limit decided it.\n *\n * Only two things can bind, and the smaller wins:\n *\n * - The V8 heap ceiling, which is what an allocation actually fails against, fatally and\n * uncatchably. V8 sizes it from physical memory by default, so it already scales down on a\n * small machine.\n * - A container memory limit, from process.constrainedMemory(). This is the case os.freemem()\n * gets dangerously wrong: inside a cgroup it reports the *host's* free memory, so a 2GB\n * container on a large host sails past the check and is then killed by the OOM killer with\n * exit 137 and no JavaScript error to catch.\n *\n * What the OS reports as free or available is deliberately *not* one of them. It is recorded for\n * diagnostics and ignored for the decision, because it does not describe a wall the process can\n * hit - a machine with virtual memory gets slower, not fatal - and because the number itself is\n * not trustworthy. os.freemem() counts only free and speculative pages, excluding the inactive\n * and file-cache pages the OS reclaims on demand. process.availableMemory() is meant to fix that\n * and does on Linux, but on macOS it depends on the libuv version underneath: Node 24 reported\n * 63GB on a 128GB machine here while Node 22 on a macOS CI runner reported 74MB, which refused a\n * 45MB load on a machine that had ample room for it. Letting either bind is what made the same\n * file load or fail from one minute, or one Node version, to the next.\n *\n * @return {{bytes: number, limitedBy: string, candidates: Array<{source: string, bytes: number}>,\n * observed: Array<{source: string, bytes: number}>}} The budget, the name of the limit that\n * bound it, what was allowed to bind, and what was recorded but not used.\n */\nexport function getMemoryBudget() {\n /** @type {Array<{source: string, bytes: number}>} */\n const candidates = [];\n\n if (heapLimitIsMeaningful()) {\n candidates.push({source: 'V8 heap limit', bytes: usableOldSpaceLimit()});\n }\n\n // Node returns 0 when the process is not constrained. Bun returns os.totalmem() instead, which\n // is not a constraint either, so anything at or above total memory is discarded rather than\n // treated as a container limit.\n const constrained = typeof process.constrainedMemory === 'function' ? process.constrainedMemory() : 0;\n if (constrained > 0 && constrained < os.totalmem()) {\n candidates.push({source: 'container memory limit', bytes: constrained});\n }\n\n // Bun outside a container has neither a usable heap limit nor a container limit, so without\n // this there would be no ceiling at all. Total memory is at least a real upper bound.\n if (candidates.length === 0) {\n candidates.push({source: 'total system memory', bytes: os.totalmem()});\n }\n\n /** @type {Array<{source: string, bytes: number}>} */\n const observed = [{source: 'free memory (os.freemem)', bytes: os.freemem()}];\n if (typeof process.availableMemory === 'function') {\n observed.push({source: 'available memory', bytes: process.availableMemory()});\n }\n\n const binding = candidates.reduce((lowest, candidate) => (candidate.bytes < lowest.bytes ? candidate : lowest));\n\n return {bytes: binding.bytes, limitedBy: binding.source, candidates, observed};\n}\n\n/**\n * What `heap_size_limit` overstates the usable old-space limit by, in bytes.\n *\n * `v8.getHeapStatistics().heap_size_limit` counts new space, code space and the trusted spaces\n * as well as old space, and it is old space that a row-materialising load exhausts. Measured on\n * this platform the gap is a flat 192MB at every configured size - `--max-old-space-size=96`\n * reports 288, 512 reports 704, 2048 reports 2240 - so it is an absolute offset, not a\n * proportion, and a safety factor cannot express it. At a 4GB heap it is under 5% and a factor\n * absorbs it; at a heap configured down to a couple of hundred megabytes it is most of the\n * budget, which is where an under-sized estimate turned into a crash.\n *\n * It used to be absorbed into the per-row constants instead, which made those constants\n * describe two unrelated things at once and left them four to six times larger than the memory\n * they were supposed to model. Subtracting it here lets the row model be a row model.\n *\n * V8 exposes no per-space limit - `getHeapSpaceStatistics()` reports current sizes, not\n * ceilings - so this is an observed constant rather than a derived one. If it is wrong on some\n * platform it is wrong in the safe direction on a large heap, and the safety factor still\n * applies underneath.\n */\nconst HEAP_LIMIT_OVERSTATEMENT_BYTES = 192 * 1024 * 1024;\n\n/**\n * Smallest budget worth reporting, in bytes.\n *\n * This is a damage limiter for a platform where the 192MB offset does not hold, not a\n * description of a real ceiling. Subtracting an offset that does not apply would leave a budget\n * near zero and refuse everything, so the floor catches that.\n *\n * It has to leave room for `BASE_BYTES` plus a small load *after* the safety factor, or it\n * achieves the opposite of its purpose. An earlier value of 16MB was exactly `BASE_BYTES`, so at\n * the floor the estimate always exceeded the budget and even `misc/small.qvd` - 606 rows, 29KB -\n * was refused on a runtime where it demonstrably loads. 64MB clears `BASE_BYTES` four times\n * over.\n *\n * It over-claims only where the true old-space limit is under 64MB, which is not a configuration\n * this library can serve: the fixed cost of reading any file at all is 15MB of that.\n */\nconst MINIMUM_BUDGET_BYTES = 64 * 1024 * 1024;\n\n/**\n * The heap limit, less the spaces a row load cannot use.\n *\n * A plain subtraction, because the overstatement is a flat offset at every configured size:\n * `--max-old-space-size=47` reports 239, 96 reports 288, 4096 reports 4288. An earlier version\n * of this only subtracted when the reported limit exceeded twice the offset and otherwise\n * returned half of it, which was meant to avoid a non-positive result. It instead produced the\n * wrong answer across the whole range the correction exists for: at a 47MB heap it returned\n * 119MB, so the guard admitted a load that needed 63MB and the process aborted - the exact\n * failure this function is here to prevent, reintroduced by the fallback rather than by the\n * rule.\n *\n * @return {number} Usable bytes.\n */\nfunction usableOldSpaceLimit() {\n const usable = getHeapLimit() - HEAP_LIMIT_OVERSTATEMENT_BYTES;\n\n return usable > MINIMUM_BUDGET_BYTES ? usable : MINIMUM_BUDGET_BYTES;\n}\n\n/**\n * Estimates the memory usage for loading a QVD file with given parameters.\n * Takes into account Phase 2.5 optimization which skips parsing unused symbols.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @returns {number} Estimated memory usage in bytes\n */\n/**\n * What a row-materialising load costs, in bytes.\n *\n * `BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columns)`.\n *\n * Recalibrated 2026-09-11, after the bitwise decode (#134) stopped the reader allocating an\n * array per row and several per cell. The method is the one the original calibration used:\n * generate N rows x C columns where every value is `(i + j) % 100`, so the symbol table stays\n * negligible and only row geometry moves, then binary-search the smallest\n * `--max-old-space-size` at which the load completes.\n *\n * shape cells was (pre-#134) now model\n * 400,000 x 10 4M 118 MB 63 77\n * 800,000 x 5 4M 237 MB 87 106\n * 200,000 x 40 8M 142 MB 79 62\n * 400,000 x 40 16M 307 MB 151 109\n * 800,000 x 20 16M 484 MB 175 202\n * 1,600,000 x 10 16M 520 MB 215 259\n *\n * and against two real files, which the original calibration did not cover:\n *\n * lego/inventory_parts 580,251 x 5 63 MB 81\n * chicago_taxi_rides 2016_01 1,705,805 x 20 367 MB 412\n *\n * The reader needs roughly 2.4x less heap than it did, which is why the old constants - 360 and\n * 34 - over-estimated a taxi read by 4.8x and refused loads that fit comfortably.\n *\n * Two of the model's figures sit *below* the measurement (200,000 x 40 and 400,000 x 40). That\n * is not an under-estimate of the rows: those two shapes are dominated by the fixed cost of\n * reading a file at all, which `BASE_BYTES` covers and which the per-row terms should not be\n * inflated to absorb. Every shape's total prediction is above its measured minimum.\n *\n * The constants are what the geometry implies rather than fitted numbers: a row is a JSArray\n * with a separate backing store, so it costs two object headers plus slack, and a cell is one\n * pointer. Fitting the eight measurements above gives 55-64 and 7.1-7.3; 72 and 8 clear every\n * one of them by 13-26%, which is the margin. Under-estimating means an uncatchable abort,\n * over-estimating means a catchable refusal, so the margin is deliberately one-sided.\n *\n * `BASE_BYTES` is what a load costs before any rows exist - the interpreter, the parsed header,\n * the decoded index columns. Measured as the floor of the binary search: a columnar read of any\n * of these files, which builds no rows at all, completes at 15MB.\n */\nconst BASE_BYTES = 16 * 1024 * 1024;\nconst ROW_BASE_BYTES = 72;\nconst PER_CELL_BYTES = 8;\n\n/**\n * Bytes a read allocates *outside* the V8 heap, in bytes.\n *\n * The decoder builds one `Int32Array` of stored indices per field, and a TypedArray's backing\n * store is external memory: it does not consume old space, so `--max-old-space-size` does not\n * bound it and the V8 heap budget must not be charged for it. A columnar read of the 38MB taxi\n * fixture completes in a 15MB heap for exactly this reason.\n *\n * A cgroup counts it, though, and exceeding a container limit is a SIGKILL - uncatchable, and\n * strictly worse than the heap abort this module exists to prevent. So it is estimated, and\n * checked against the container budget rather than the heap one.\n *\n * Both paths allocate it. A row read builds the codes and then the rows from them, so during\n * the load both are live; a columnar read keeps only the codes. The file buffer is external\n * too, but its size is not known here, and the codes dominate on the shapes that get close to\n * a limit.\n *\n * @param {number} rows Rows that will be decoded.\n * @param {number} columnCount Columns per row.\n * @return {number} Estimated external bytes.\n */\nexport function estimateExternalMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0 || !rows || rows <= 0) {\n return 0;\n }\n\n return rows * columnCount * Int32Array.BYTES_PER_ELEMENT;\n}\n\n/**\n * Estimates the heap a row-materialising load will need, in bytes.\n *\n * @param {number} rows Rows that will be materialised.\n * @param {number} columnCount Columns per row. Zero disables the term, for callers that do not\n * know the geometry yet.\n * @return {number} Estimated bytes.\n */\nfunction estimateRowMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0) {\n return 0;\n }\n return BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columnCount);\n}\n\nexport function estimateMemoryUsage(symbolTableSize, maxRows, totalRows, columnCount = 0, materialisesRows = true) {\n // Memory overhead multipliers based on empirical testing\n const FULL_PARSE_OVERHEAD = 6.0; // Baseline: JavaScript objects have 6x overhead\n const MINIMAL_OVERHEAD = 0.01; // Skipped symbols: minimal null placeholder overhead\n\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n\n // The rows themselves. This term used to be missing entirely, which is what made the guard\n // useless for the commonest Qlik shape: many rows over low-cardinality fields. A 150MB file\n // with a 0.43MB symbol table was estimated at 2.6MB and then killed a default heap.\n //\n // A columnar read materialises none of them, and what it does allocate - one Int32Array of\n // codes per field - is a TypedArray backing store, which lives outside the V8 heap this\n // budget describes. That is not a modelling nicety: binary-searching the smallest\n // --max-old-space-size at which a columnar read completes gives 15MB for every file tried,\n // from a 4MB fixture to the 38MB taxi one, because almost nothing it allocates is on the\n // heap. Charging it the row cost refused columnar reads that need a fortieth of the budget.\n const rowMemory = materialisesRows ? estimateRowMemory(rowsToLoad, columnCount) : BASE_BYTES;\n\n if (maxRows === null || maxRows >= totalRows) {\n // Loading all rows - need all symbols, no filtering benefit\n return symbolTableSize * FULL_PARSE_OVERHEAD + rowMemory;\n }\n\n // Estimate what percentage of symbols we'll need\n // Symbol usage grows slower than linear (diminishing returns as you add rows)\n // Use square root scaling as empirical approximation\n const rowPercentage = maxRows / totalRows;\n const symbolPercentage = Math.sqrt(rowPercentage);\n\n // Calculate memory for kept symbols (full overhead) + skipped symbols (minimal overhead)\n const keptSymbolsMemory = symbolTableSize * symbolPercentage * FULL_PARSE_OVERHEAD;\n const skippedSymbolsMemory = symbolTableSize * (1 - symbolPercentage) * MINIMAL_OVERHEAD;\n\n return keptSymbolsMemory + skippedSymbolsMemory + rowMemory;\n}\n\n/**\n * Finds the largest row count whose estimate fits inside a budget.\n *\n * The estimate is monotonic in rows but not invertible in closed form - the symbol term scales\n * with sqrt(rows/totalRows) while the row term scales linearly - so this bisects instead, and\n * the answer is therefore a value the caller can actually use. The previous implementation\n * inverted the square-root term alone and suggested row counts that the same check rejected on\n * the next call.\n *\n * @param {number} budget Bytes available.\n * @param {number} symbolTableSize Size of the symbol table in bytes.\n * @param {number} totalRows Rows the file declares.\n * @param {number} columnCount Columns per row.\n * @return {number} A row count whose estimate fits the budget, or 0 when none does.\n */\nexport function recommendedRowsFor(budget, symbolTableSize, totalRows, columnCount, materialisesRows = true) {\n if (estimateMemoryUsage(symbolTableSize, totalRows, totalRows, columnCount, materialisesRows) <= budget) {\n return totalRows;\n }\n\n // The bisection below treats `low` as a value known to fit, so that has to be true of its\n // starting point. It is not automatic: the estimate charges 1% of the symbol table even when\n // no rows are requested, so a symbol table two orders of magnitude larger than the budget\n // leaves nothing that fits. Clamping the answer up to 1 in that case produced a suggestion\n // the caller could not use - `maxRows: 1` threw the same error it had just been offered as\n // the fix for.\n if (estimateMemoryUsage(symbolTableSize, 0, totalRows, columnCount, materialisesRows) > budget) {\n return 0;\n }\n\n let low = 0;\n let high = totalRows;\n while (high - low > 1) {\n const mid = Math.floor((low + high) / 2);\n if (estimateMemoryUsage(symbolTableSize, mid, totalRows, columnCount, materialisesRows) <= budget) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Validates that there is sufficient memory available to load a QVD file safely.\n * Considers both available system RAM and the configured V8 heap limit.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} [safetyFactor=0.8] Fraction of the memory budget to use (0.0-1.0). Zero\n * disables the check entirely.\n *\n * The default was 0.3 while the estimate counted only the symbol table - a proxy that\n * understated real cost by around a hundredfold for the commonest Qlik shape, so the factor was\n * quietly compensating for it. Now that the estimate models the rows too, 0.3 would double-count\n * that margin and refuse loads with four times the headroom they need. The estimate sits about\n * 1.2-1.6x above the measured requirement, so 0.8 still leaves V8 room to collect.\n * @param {number} [columnCount=0] Columns per row, so the estimate can account for the row\n * arrays. Zero omits that term, which is what the old symbol-table-only estimate did.\n * @throws {QvdValidationError} If insufficient memory is available\n */\nexport function validateMemoryAvailability(\n symbolTableSize,\n maxRows,\n totalRows,\n filePath,\n safetyFactor = 0.8,\n columnCount = 0,\n materialisesRows = true,\n) {\n if (typeof safetyFactor !== 'number' || safetyFactor < 0 || safetyFactor > 1) {\n throw new QvdValidationError('safetyFactor must be a number between 0.0 and 1.0', {safetyFactor});\n }\n\n // Zero disables the check. It used to mean a budget of zero bytes, which refused every file\n // however small - not something any caller can have wanted - so the only reading that makes it\n // useful is \"I will manage memory myself\". This is the documented escape hatch for runtimes\n // whose limits cannot be measured, and for callers who know better than the estimate.\n if (safetyFactor === 0) {\n return;\n }\n\n const budget = getMemoryBudget();\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n const heapMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows, columnCount, materialisesRows);\n const externalMemory = estimateExternalMemory(rowsToLoad, columnCount);\n\n // Each candidate is measured against the memory it actually bounds. The V8 heap limit bounds\n // old space, which TypedArray backing stores do not occupy; a container limit bounds the\n // process, which they do. Checking one figure against both was wrong in both directions at\n // once: it refused columnar reads that fit the heap forty times over, and - once that was\n // fixed by not charging them for rows - it admitted a columnar read allocating 130MB of codes\n // inside a container with less than that, where the kernel answers with a SIGKILL.\n const bounded = budget.candidates.map((candidate) => {\n const heapOnly = candidate.source === 'V8 heap limit';\n\n return {\n ...candidate,\n needs: heapOnly ? heapMemory : heapMemory + externalMemory,\n allowed: candidate.bytes * safetyFactor,\n bounds: heapOnly ? 'the V8 heap' : 'the whole process',\n };\n });\n\n const exceeded = bounded.filter((candidate) => candidate.needs > candidate.allowed);\n const binding = exceeded.reduce(\n (worst, candidate) => (candidate.needs / candidate.allowed > worst.needs / worst.allowed ? candidate : worst),\n exceeded[0],\n );\n\n const heapLimit = getHeapLimit();\n const availableMemory = binding ? binding.bytes : budget.bytes;\n const estimatedMemory = binding ? binding.needs : heapMemory;\n const maxAllowedMemory = binding ? binding.allowed : budget.bytes * safetyFactor;\n\n if (binding) {\n // Bisected against the same estimate this check uses, so the suggestion is one the caller\n // can act on. It used to invert the square-root symbol term alone and could suggest a row\n // count that the very next call rejected.\n const recommendedMaxRows = recommendedRowsFor(\n maxAllowedMemory,\n symbolTableSize,\n totalRows,\n columnCount,\n materialisesRows,\n );\n\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const availableMB = Math.round(maxAllowedMemory / 1024 / 1024);\n // The usable figure, not the reported one. These differ by the 192MB of non-old-space\n // that heap_size_limit counts, and printing the reported one next to a budget breakdown\n // carrying the corrected one told the reader two different things about the same limit -\n // in the one diagnostic whose job is to say which knob to turn.\n const heapLimitMB = Math.round(usableOldSpaceLimit() / 1024 / 1024);\n const reportedHeapLimitMB = Math.round(heapLimit / 1024 / 1024);\n const availableRamMB = Math.round(availableMemory / 1024 / 1024);\n\n // Naming the limit that bound the decision is the difference between an actionable error and\n // a puzzling one: raising --max-old-space-size fixes a heap-bound refusal and does nothing\n // for a container-bound one, where it makes the OOM kill more likely rather than less.\n // The bare source name, because callers match it against memoryBudget[].source - a test\n // pins that. What the limit bounds goes in its own field and into the prose.\n const limitingFactor = binding.source;\n const limitingScope = binding.bounds;\n const budgetBreakdown = budget.candidates\n .map((candidate) => `${candidate.source} ${Math.round(candidate.bytes / 1024 / 1024)}MB`)\n .join(', ');\n const observedBreakdown = budget.observed\n .map((entry) => `${entry.source} ${Math.round(entry.bytes / 1024 / 1024)}MB`)\n .join(', ');\n\n // Saying \"try maxRows: N\" when no N fits sends the caller round a loop, so that case gets its\n // own advice rather than a number that will be rejected on the next call.\n const nothingFits = recommendedMaxRows === 0;\n const containerBound = binding.source === 'container memory limit';\n\n let advice;\n if (nothingFits) {\n advice =\n `No row count fits this budget - the symbol table alone exceeds it, so maxRows cannot help. ` +\n (containerBound\n ? `Raise the container's memory limit.`\n : `Raise the heap with --max-old-space-size, or raise memorySafetyFactor.`);\n } else if (containerBound) {\n advice = `The binding limit is the container's, so raising --max-old-space-size would let V8 grow past it and be killed by the OOM killer instead. Set it below the container limit, raise the limit, or load fewer rows with maxRows (recommended: ${recommendedMaxRows.toLocaleString()} rows or less).`;\n } else {\n advice = `Try loading fewer rows using the maxRows parameter (recommended: ${recommendedMaxRows.toLocaleString()} rows or less), or raise the heap with --max-old-space-size.`;\n }\n\n throw new QvdValidationError(\n `Insufficient memory to load file safely. ` +\n `Symbol table: ${sizeMB}MB, Estimated memory needed: ${estimatedMB}MB, Available: ${availableMB}MB (limited by ${limitingFactor}, which bounds ${limitingScope}; considered: ${budgetBreakdown}; observed but not used: ${observedBreakdown}). ` +\n advice,\n {\n file: filePath,\n symbolTableSize,\n symbolTableSizeMB: sizeMB,\n estimatedMemoryMB: estimatedMB,\n availableMemoryMB: availableMB,\n heapLimitMB,\n reportedHeapLimitMB,\n availableRamMB,\n limitingFactor,\n limitingScope,\n memoryBudget: budget.candidates,\n memoryObserved: budget.observed,\n columnCount,\n totalRows,\n maxRows,\n recommendedMaxRows,\n },\n );\n }\n}\n\n/**\n * Emits a warning for large symbol tables when loading all rows.\n * Warning threshold scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {number} [columnCount=0] Columns per row, so the reported figure matches the check\n */\nexport function warnLargeSymbolTable(symbolTableSize, maxRows, totalRows, columnCount = 0, materialisesRows = true) {\n // Dynamic warning threshold: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n // 12.5% of the budget the check uses, not of the figure v8 reports. Thresholding on the\n // reported limit made the warning fire later than the refusal it is meant to precede, and by\n // the widest margin on the small heaps where the 192MB of non-old-space is most of it.\n const LARGE_SYMBOL_TABLE_WARNING = usableOldSpaceLimit() * 0.125;\n\n if (symbolTableSize > LARGE_SYMBOL_TABLE_WARNING && (maxRows === null || maxRows >= totalRows)) {\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n // Same estimate the check uses. Without columnCount this printed the symbol table's cost\n // alone - roughly 3.6GB where the check had just computed 5.2GB - and a caller sizing\n // --max-old-space-size from the warning would pick a heap far too small.\n const estimatedMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows, columnCount, materialisesRows);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const warnMB = Math.round(LARGE_SYMBOL_TABLE_WARNING / 1024 / 1024);\n\n console.warn(\n `⚠️ Large symbol table detected (${sizeMB}MB > ${warnMB}MB threshold). Loading all ${totalRows.toLocaleString()} rows will use ~${estimatedMB}MB RAM. ` +\n `Consider using the maxRows parameter for better performance and lower memory usage.`,\n );\n }\n}\n","// @ts-check\n\nimport {QvdCorruptedError, QvdValidationError} from '../QvdErrors.js';\nimport {getHeapLimit} from './memoryUtils.js';\nimport {MAX_BIT_WIDTH} from './bitUtils.js';\n\n/**\n * Validates symbol table size during initial file read (early check).\n * This is the first-pass validation in _readData for lazy loading.\n * Limit scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdValidationError} If symbol table exceeds dynamic limit\n */\nexport function validateSymbolTableSizeEarly(symbolTableLength, filePath) {\n // Dynamic limit: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n const heapLimit = getHeapLimit();\n const MAX_SYMBOL_TABLE_SIZE = heapLimit * 0.125;\n\n if (symbolTableLength > MAX_SYMBOL_TABLE_SIZE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(MAX_SYMBOL_TABLE_SIZE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table too large (${sizeMB}MB exceeds ${maxMB}MB limit for lazy loading). ` +\n `This QVD file contains extremely high-cardinality fields. ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 12.5% = ${maxMB}MB). ` +\n `Consider: (1) loading the full file without maxRows, (2) increasing heap size with --max-old-space-size, or (3) aggregating high-cardinality fields.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: MAX_SYMBOL_TABLE_SIZE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 12.5,\n },\n );\n }\n}\n\n/**\n * Validates symbol table size limits to prevent out-of-memory conditions.\n * This is the comprehensive validation in _parseSymbolTable.\n * Absolute ceiling scales with configured heap size (50% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} totalRows Total number of rows in the file\n * @throws {QvdValidationError} If symbol table exceeds safety limits\n */\nexport function validateSymbolTableSize(symbolTableLength, filePath, totalRows) {\n // Dynamic absolute ceiling: 50% of configured heap size\n // Examples: 4GB heap = 2GB, 8GB heap = 4GB, 16GB heap = 8GB, 32GB heap = 16GB\n const heapLimit = getHeapLimit();\n const ABSOLUTE_MAX_SYMBOL_TABLE = heapLimit * 0.5;\n\n if (symbolTableLength > ABSOLUTE_MAX_SYMBOL_TABLE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(ABSOLUTE_MAX_SYMBOL_TABLE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table exceeds absolute maximum size (${sizeMB}MB > ${maxMB}MB). ` +\n `This QVD file has pathological cardinality (likely a data modeling issue). ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 50% = ${maxMB}MB). ` +\n `Consider: (1) increasing heap size with --max-old-space-size, (2) aggregating high-cardinality fields, (3) splitting the data, or (4) using a different format.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: ABSOLUTE_MAX_SYMBOL_TABLE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 50,\n totalRows,\n },\n );\n }\n}\n\n/**\n * Validates field metadata before processing to prevent buffer overflow attacks.\n *\n * @param {any} field Field metadata object\n * @param {number} symbolBufferLength Length of the symbol buffer\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field metadata is invalid\n */\nexport function validateFieldMetadata(field, symbolBufferLength, filePath) {\n const symbolsOffset = parseInt(field['Offset'], 10);\n const symbolsLength = parseInt(field['Length'], 10);\n\n // Validate offset is a valid number and within bounds\n if (isNaN(symbolsOffset) || !Number.isSafeInteger(symbolsOffset) || symbolsOffset < 0) {\n throw new QvdCorruptedError('Invalid symbol offset', {\n field: field['FieldName'],\n offset: symbolsOffset,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate length is a valid number and non-negative\n if (isNaN(symbolsLength) || !Number.isSafeInteger(symbolsLength) || symbolsLength < 0) {\n throw new QvdCorruptedError('Invalid symbol length', {\n field: field['FieldName'],\n length: symbolsLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate that offset + length doesn't exceed buffer size\n if (symbolsOffset + symbolsLength > symbolBufferLength) {\n throw new QvdCorruptedError('Symbol data extends beyond buffer', {\n field: field['FieldName'],\n offset: symbolsOffset,\n length: symbolsLength,\n bufferSize: symbolBufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n}\n\n/**\n * Validates a header's declared record count.\n *\n * Extracted so the metadata-only read applies exactly the same rule as a load. When they were\n * separate, `readMetadata` coerced an unusable `NoOfRecords` to zero while `fromQvd` refused the\n * same file - so a header with the element deleted reported \"0 rows\" rather than \"this header is\n * broken\", which is indistinguishable from a genuinely empty QVD at the call site.\n *\n * @param {number} totalRows The parsed NoOfRecords.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} [stage='parseIndexTable'] Stage name recorded in the error context.\n * @throws {QvdCorruptedError} If the count is not a non-negative safe integer.\n */\nexport function validateRecordCount(totalRows, filePath, stage = 'parseIndexTable') {\n if (isNaN(totalRows) || !Number.isSafeInteger(totalRows) || totalRows < 0) {\n throw new QvdCorruptedError('Invalid number of records', {\n totalRows,\n file: filePath,\n stage,\n });\n }\n}\n\n/**\n * Validates index table metadata and bounds.\n *\n * @param {number} recordSize Size of a single record in bytes\n * @param {number} totalRows Total number of rows\n * @param {number} indexTableLength Length of the index table\n * @param {number} indexTableOffset Offset to the index table\n * @param {number} bufferLength Length of the buffer\n * @param {number} rowsToLoad Number of rows to load\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number|null} [fileSize] Actual size of the file on disk, when known. Used to detect a\n * header that describes more data than the file contains.\n * @throws {QvdCorruptedError} If index table metadata is invalid\n */\nexport function validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n indexTableOffset,\n bufferLength,\n rowsToLoad,\n filePath,\n fileSize = null,\n) {\n // Validate recordSize\n if (isNaN(recordSize) || !Number.isSafeInteger(recordSize) || recordSize < 0) {\n throw new QvdCorruptedError('Invalid record byte size', {\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n validateRecordCount(totalRows, filePath);\n\n // Allow recordSize of 0 or 1 only when there are no records (empty QVD)\n // Qlik Sense uses recordSize=1 for empty QVDs\n if (recordSize === 0 && totalRows > 0) {\n throw new QvdCorruptedError('Record byte size cannot be zero when records exist', {\n recordSize,\n totalRows,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate recordSize is reasonable (max 1MB per record)\n if (recordSize > 1048576) {\n throw new QvdCorruptedError('Record byte size exceeds maximum', {\n recordSize,\n maxSize: 1048576,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table length\n if (isNaN(indexTableLength) || !Number.isSafeInteger(indexTableLength) || indexTableLength < 0) {\n throw new QvdCorruptedError('Invalid index table length', {\n length: indexTableLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table start offset doesn't extend beyond buffer\n if (indexTableOffset > bufferLength) {\n throw new QvdCorruptedError('Index table offset beyond buffer', {\n indexTableOffset,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // The index table must be exactly as long as the record count implies. Every QVD produced by\n // Qlik or by this library satisfies this, so a mismatch means the header is inconsistent.\n // Checking it catches corrupt headers that would otherwise decode misaligned rows.\n if (indexTableLength !== totalRows * recordSize) {\n throw new QvdCorruptedError('Index table length inconsistent with record count', {\n indexTableLength,\n expectedLength: totalRows * recordSize,\n totalRows,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate the index table against the actual file when its size is known.\n //\n // Comparing against the in-memory buffer instead is wrong in both directions: during a lazy\n // load the buffer is deliberately truncated, so valid large files were rejected as corrupt,\n // while a truncated file whose header claims more data was accepted and silently returned\n // fewer rows than the header declares.\n if (fileSize !== null) {\n if (indexTableOffset + indexTableLength > fileSize) {\n throw new QvdCorruptedError('Index table extends beyond the end of the file', {\n indexTableOffset,\n indexTableLength,\n fileSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n }\n\n // Ensure the loaded buffer actually holds the rows we were asked to parse.\n const requiredIndexBytes = rowsToLoad * recordSize;\n if (indexTableOffset + requiredIndexBytes > bufferLength) {\n throw new QvdCorruptedError('Index table truncated', {\n indexTableOffset,\n requiredBytes: requiredIndexBytes,\n availableBytes: Math.max(0, bufferLength - indexTableOffset),\n rowsToLoad,\n recordSize,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Ensure the index table length is sufficient for the number of rows to load\n if (indexTableLength < requiredIndexBytes) {\n throw new QvdCorruptedError('Index table length smaller than required', {\n indexTableLength,\n requiredBytes: requiredIndexBytes,\n rowsToLoad,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n\n/**\n * Validates field bit offset and bit width for index table parsing.\n *\n * @param {any} field Field metadata object\n * @param {number} recordSize Size of a single record in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field bit metadata is invalid\n */\nexport function validateFieldBitMetadata(field, recordSize, filePath) {\n const bitOffset = parseInt(field['BitOffset'], 10);\n const bitWidth = parseInt(field['BitWidth'], 10);\n\n // Validate bitOffset\n if (isNaN(bitOffset) || !Number.isSafeInteger(bitOffset) || bitOffset < 0) {\n throw new QvdCorruptedError('Invalid bit offset', {\n field: field['FieldName'],\n bitOffset,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth\n if (isNaN(bitWidth) || !Number.isSafeInteger(bitWidth) || bitWidth < 0) {\n throw new QvdCorruptedError('Invalid bit width', {\n field: field['FieldName'],\n bitWidth,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias.\n //\n // It is added to every decoded index inside an Int32Array, and Int32Array coerces NaN to 0 -\n // so an absent or non-numeric Bias made a file read back as plausible wrong values rather\n // than as an error. A blank <Bias> on a nullable column turned every NULL and every symbol\n // above the first into the first symbol, silently. Validated here alongside the other two\n // because the three travel together and are trusted together.\n const bias = parseInt(field['Bias'], 10);\n\n if (isNaN(bias) || !Number.isSafeInteger(bias)) {\n throw new QvdCorruptedError('Invalid bias', {\n field: field['FieldName'],\n bias: field['Bias'],\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth against what a stored index can be.\n //\n // Indices are kept in an Int32Array, so the value has to fit in a positive 32-bit integer.\n // The bound is not a limitation in practice - 31 bits addresses two billion symbols in one\n // field - and refusing is the safe direction: a 32-bit width lets the top of the range wrap\n // to a negative index, and a negative index means NULL, so the file would read back with\n // plausible wrong values rather than an error.\n if (bitWidth > MAX_BIT_WIDTH) {\n throw new QvdCorruptedError('Bit width exceeds maximum', {\n field: field['FieldName'],\n bitWidth,\n maxBitWidth: MAX_BIT_WIDTH,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitOffset + bitWidth doesn't exceed record size in bits\n const recordSizeInBits = recordSize * 8;\n if (bitOffset + bitWidth > recordSizeInBits) {\n throw new QvdCorruptedError('Bit field extends beyond record size', {\n field: field['FieldName'],\n bitOffset,\n bitWidth,\n recordSizeInBits,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n","// @ts-check\n\nimport {QvdSymbol} from '../QvdSymbol.js';\nimport {QvdCorruptedError, QvdParseError} from '../QvdErrors.js';\n\n/**\n * Parses an integer symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for an integer\n if (pointer + 4 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading integer symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const byteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 4));\n const value = Buffer.from(byteData).readIntLE(0, byteData.length);\n return {symbol: QvdSymbol.fromIntValue(value), bytesRead: 4};\n}\n\n/**\n * Parses a double symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for a double\n if (pointer + 8 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading double symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const byteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 8));\n const value = Buffer.from(byteData).readDoubleLE(0);\n return {symbol: QvdSymbol.fromDoubleValue(value), bytesRead: 8};\n}\n\n/**\n * Parses a string symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n const startPointer = pointer;\n const maxStringLength = 1048576; // 1MB max string size to prevent memory exhaustion\n let stringLength = 0;\n\n // Find the null terminator\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('String symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n // Ensure we found the null terminator\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('String symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const value = symbolBuffer.subarray(startPointer, pointer).toString('utf-8');\n return {symbol: QvdSymbol.fromStringValue(value), bytesRead: pointer - startPointer + 1};\n}\n\n/**\n * Skips a string symbol in the buffer without parsing it.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {number} Bytes to skip\n */\nexport function skipStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n const startPointer = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('String symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('String symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return pointer - startPointer + 1;\n}\n\n/**\n * Parses a dual integer symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDualIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for an integer\n if (pointer + 4 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading dual integer symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const intByteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 4));\n const intValue = Buffer.from(intByteData).readIntLE(0, intByteData.length);\n pointer += 4;\n\n // Parse the string portion\n const stringStart = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const stringValue = symbolBuffer.subarray(stringStart, pointer).toString('utf-8');\n return {symbol: QvdSymbol.fromDualIntValue(intValue, stringValue), bytesRead: pointer - (stringStart - 4) + 1};\n}\n\n/**\n * Parses a dual double symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDualDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for a double\n if (pointer + 8 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading dual double symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const doubleByteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 8));\n const doubleValue = Buffer.from(doubleByteData).readDoubleLE(0);\n pointer += 8;\n\n // Parse the string portion\n const stringStart = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const stringValue = symbolBuffer.subarray(stringStart, pointer).toString('utf-8');\n return {\n symbol: QvdSymbol.fromDualDoubleValue(doubleValue, stringValue),\n bytesRead: pointer - (stringStart - 8) + 1,\n };\n}\n\n/**\n * Skips a dual symbol (integer or double) in the buffer without parsing it.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {number} numericBytes Number of bytes for the numeric portion (4 for int, 8 for double)\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {number} Bytes to skip\n */\nexport function skipDualSymbol(symbolBuffer, pointer, bufferLength, numericBytes, fieldName, filePath) {\n if (pointer + numericBytes > bufferLength) {\n throw new QvdCorruptedError(`Buffer overflow reading dual symbol`, {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const startPointer = pointer;\n pointer += numericBytes;\n\n // Skip the string portion\n const maxStringLength = 1048576;\n let stringLength = 0;\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return pointer - startPointer + 1;\n}\n\n/**\n * Parses a symbol based on the type byte.\n *\n * @param {number} typeByte The type byte\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position (after type byte)\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {boolean} shouldParse Whether to parse the symbol (true) or skip it (false)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol (or null if skipped) and bytes read\n */\nexport function parseSymbol(typeByte, symbolBuffer, pointer, bufferLength, fieldName, filePath, shouldParse) {\n switch (typeByte) {\n case 1: {\n // Integer value (4 Bytes)\n if (shouldParse) {\n return parseIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n return {symbol: null, bytesRead: 4};\n }\n case 2: {\n // Double value (8 Bytes)\n if (shouldParse) {\n return parseDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n return {symbol: null, bytesRead: 8};\n }\n case 4: {\n // String value (0 terminated)\n if (shouldParse) {\n return parseStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n case 5: {\n // Dual (Integer format) value (4 bytes), followed by string format\n if (shouldParse) {\n return parseDualIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipDualSymbol(symbolBuffer, pointer, bufferLength, 4, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n case 6: {\n // Dual (Double format) value (8 bytes), followed by string format\n if (shouldParse) {\n return parseDualDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipDualSymbol(symbolBuffer, pointer, bufferLength, 8, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n default: {\n throw new QvdParseError('Unknown symbol type byte', {\n typeByte: typeByte.toString(16),\n offset: pointer - 1,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * One column of a QVD, as the file stores it: a code per row and a dictionary of values.\n *\n * This is the shape the format already has. A QVD does not store a value per cell; it stores a\n * table of distinct symbols per field and an array of indices into it. Keeping that shape is\n * what makes a column cheap - four bytes per row, plus one entry per *distinct* value - and it\n * is why none of the questions that dog a per-row typed array arise here:\n *\n * - A mixed column needs no decision, because nothing per row is typed. On the bundled taxi\n * fixture **no column at all is strictly numeric**: `dropoff_census_tract` is 43% empty\n * strings, and four columns are 100% strings. A `Float64Array` of values would put NaN in\n * 43% of that column and erase Qlik's distinction between a blank and a number.\n * - NULL is a property of the position, not of the value: `codes[row] < 0`. No sentinel is\n * invented, so no sentinel can collide with real data.\n * - An all-null column, a single-valued column and a zero-row column are the same code path.\n */\nexport class QvdColumn {\n /**\n * @param {string} name The field name.\n * @param {Int32Array} codes One stored index per row, bias applied. Negative means NULL.\n * @param {Array<any>} symbols The field's distinct values, indexed by code.\n */\n constructor(name, codes, symbols) {\n this._name = name;\n this._codes = codes;\n this._symbols = symbols;\n\n Object.freeze(this);\n }\n\n /** @return {string} The field name. */\n get name() {\n return this._name;\n }\n\n /** @return {number} Rows in the column. */\n get length() {\n return this._codes.length;\n }\n\n /**\n * The stored index of each row. Negative means NULL.\n *\n * The table's own array, not a copy - it is the thing that makes this cheap, and copying it\n * per call would defeat the point. Treat it as read-only.\n *\n * @return {Int32Array} One code per row.\n */\n get codes() {\n return this._codes;\n }\n\n /**\n * The field's distinct values, indexed by the codes.\n *\n * One entry per distinct value, not per row: a few thousand entries for a column of millions.\n *\n * @return {ReadonlyArray<any>} The dictionary.\n */\n get symbols() {\n return this._symbols;\n }\n\n /**\n * The value of one row.\n *\n * @param {number} row The row index.\n * @return {any} The value, or null where the file stores NULL.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n at(row) {\n if (!Number.isInteger(row) || row < 0 || row >= this._codes.length) {\n throw new QvdValidationError('Row index out of bounds', {\n column: this._name,\n row,\n length: this._codes.length,\n });\n }\n\n const code = this._codes[row];\n\n return code < 0 ? null : this._symbols[code];\n }\n\n /**\n * Iterates the column's values without materialising it.\n *\n * @return {Iterator<any>} An iterator over the values, NULLs included as null.\n */\n [Symbol.iterator]() {\n const codes = this._codes;\n const symbols = this._symbols;\n let row = 0;\n\n return {\n next() {\n if (row >= codes.length) {\n return {done: true, value: undefined};\n }\n\n const code = codes[row++];\n\n return {done: false, value: code < 0 ? null : symbols[code]};\n },\n };\n }\n\n /**\n * The column as a plain array of values, one per row.\n *\n * Lossless, and cell-for-cell what `QvdDataFrame.data[row][column]` would hold. The caller\n * owns the result; the table keeps no reference to it, so two calls return two arrays.\n *\n * @return {Array<any>} One value per row.\n */\n toArray() {\n const out = new Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n out[row] = code < 0 ? null : this._symbols[code];\n }\n\n return out;\n }\n\n /**\n * The dictionary as numbers, for scanning without materialising the column.\n *\n * One entry per *distinct* value, not per row - 17 KB for a column of 1.7 million rows with\n * 2,188 symbols - so this is the cheap conversion, where `toFloat64Array()` is the expensive\n * one. Non-numeric symbols become NaN, which is safe here in a way it is not per row: the\n * codes still distinguish NULL, and a caller that wants the blank back still has `symbols`.\n *\n * Scanning `codes` against this is the fastest way to read a column, because both sides are\n * contiguous typed arrays and the dictionary fits in cache:\n *\n * ```js\n * const codes = column.codes;\n * const values = column.numericSymbols();\n * let total = 0;\n * for (let row = 0; row < codes.length; row++) {\n * const code = codes[row];\n * if (code >= 0) {\n * const value = values[code];\n * if (!Number.isNaN(value)) total += value;\n * }\n * }\n * ```\n *\n * @return {Float64Array} One number per distinct symbol, NaN where the symbol is not a number.\n */\n numericSymbols() {\n const out = new Float64Array(this._symbols.length);\n\n for (let index = 0; index < this._symbols.length; index++) {\n const value = this._symbols[index];\n out[index] = typeof value === 'number' ? value : NaN;\n }\n\n return out;\n }\n\n /**\n * The column as a `Float64Array`.\n *\n * Named for what it costs rather than offered as *the* representation, because it is lossy\n * and on real data it is lossy often: it cannot distinguish a blank from a number, and the\n * bundled taxi fixture has a column that is 43% blank. It therefore refuses by default\n * rather than quietly writing NaN over two fifths of a column.\n *\n * @param {Object} [options] Conversion options.\n * @param {'throw'|'nan'} [options.onNonNumeric='throw'] What to do with a value that is not a\n * number - including NULL. `'throw'` refuses and names the offending row; `'nan'` writes\n * NaN, which is the right choice only when the caller knows the column is numeric.\n * @return {Float64Array} One number per row.\n * @throws {QvdValidationError} If a value is not a number and `onNonNumeric` is `'throw'`.\n */\n toFloat64Array(options = {}) {\n const {onNonNumeric = 'throw'} = options;\n\n if (onNonNumeric !== 'throw' && onNonNumeric !== 'nan') {\n throw new QvdValidationError('onNonNumeric must be \"throw\" or \"nan\"', {\n column: this._name,\n provided: onNonNumeric,\n });\n }\n\n const out = new Float64Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n const value = code < 0 ? null : this._symbols[code];\n\n if (typeof value === 'number') {\n out[row] = value;\n continue;\n }\n\n if (onNonNumeric === 'throw') {\n throw new QvdValidationError('Column holds a value that is not a number', {\n column: this._name,\n row,\n value,\n type: value === null ? 'null' : typeof value,\n hint: 'Pass {onNonNumeric: \"nan\"} to write NaN instead, or use toArray() to keep the value.',\n });\n }\n\n out[row] = NaN;\n }\n\n return out;\n }\n}\n\n/**\n * A QVD read as columns rather than as rows.\n *\n * The same file, the same decoder and the same symbol resolution as `QvdDataFrame.fromQvd` -\n * it simply stops before building rows, and keeps what the decoder already produced. Measured\n * on `__tests__/data/chicago_taxi_rides/chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows x 20\n * columns, as `heapUsed + external` either side of a forced collection:\n *\n * | | retained | bytes/cell |\n * | --- | --- | --- |\n * | `QvdDataFrame.fromQvd()` | 352.8 MiB | 10.84 |\n * | `QvdColumnTable.fromQvd()` | 38.6 MiB | 1.18 |\n *\n * It is not a data frame and does not become one. Offering a conversion would let a caller hold\n * both representations at once, which is the one configuration in which this costs more than it\n * saves. Re-reading a file as rows costs what reading it as rows always cost; there is no\n * saving to protect by avoiding that.\n */\nexport class QvdColumnTable {\n /**\n * @param {Object} decoded What the reader decoded.\n * @param {Array<string>} decoded.columns Field names, in file order.\n * @param {Array<Int32Array>} decoded.codesByField One code array per field.\n * @param {Array<Array<any>>} decoded.symbolsByField One dictionary per field.\n * @param {number} decoded.rowCount Rows decoded.\n * @param {any} decoded.metadata The raw QvdTableHeader.\n * @param {any} decoded.loadStats Statistics about the read.\n */\n constructor({columns, codesByField, symbolsByField, rowCount, metadata, loadStats}) {\n this._columns = columns;\n this._codesByField = codesByField;\n this._symbolsByField = symbolsByField;\n this._rowCount = rowCount;\n this._metadata = metadata;\n this._loadStats = loadStats;\n }\n\n /**\n * Reads a QVD file as columns.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Loading options, with the same meanings they have on `fromQvd`.\n * @param {number|null} [options.maxRows] Maximum rows to decode.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor] Fraction of the memory budget a load may use.\n * @param {number} [options.symbolFilteringThreshold] Symbol table size above which a limited\n * read switches to two-pass filtering.\n * @return {Promise<QvdColumnTable>} The file, as columns.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n const reader = new QvdFileReader(path, {\n allowedDir: options.allowedDir,\n memorySafetyFactor: options.memorySafetyFactor,\n symbolFilteringThreshold: options.symbolFilteringThreshold,\n\n // This read builds no rows, so the memory guard must not charge it for them. A columnar\n // read of the 38MB taxi fixture completes in a 15MB heap; charged the row cost it was\n // refused below a 2GB one.\n materialisesRows: false,\n });\n\n return await reader.loadColumnar(options.maxRows !== undefined ? options.maxRows : null);\n }\n\n /** @return {Array<string>} Field names, in file order. */\n get columns() {\n return this._columns;\n }\n\n /** @return {number} Rows decoded. */\n get rowCount() {\n return this._rowCount;\n }\n\n /** @return {Array<number>} `[rows, columns]`, as on a data frame. */\n get shape() {\n return [this._rowCount, this._columns.length];\n }\n\n /** @return {any} The raw `QvdTableHeader`. */\n get metadata() {\n return this._metadata;\n }\n\n /** @return {any} Statistics about the read. */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * One column.\n *\n * @param {string} name The field name.\n * @return {QvdColumn} The column.\n * @throws {QvdValidationError} If the field is not in this file.\n */\n column(name) {\n const index = this._columns.indexOf(name);\n\n if (index === -1) {\n throw new QvdValidationError(`Column '${name}' does not exist`, {\n column: name,\n availableColumns: this._columns,\n });\n }\n\n return new QvdColumn(name, this._codesByField[index], this._symbolsByField[index]);\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport xml from 'xml2js';\nimport assert from 'assert';\nimport {QvdDataFrame} from './QvdDataFrame.js';\nimport {QvdParseError, QvdValidationError, QvdCorruptedError} from './QvdErrors.js';\nimport {validatePath} from './util/validatePath.js';\nimport {decodeIndexColumn} from './util/bitUtils.js';\nimport {validateMemoryAvailability, warnLargeSymbolTable} from './util/memoryUtils.js';\nimport {\n validateSymbolTableSize,\n validateSymbolTableSizeEarly,\n validateFieldMetadata,\n validateIndexTableMetadata,\n validateFieldBitMetadata,\n validateRecordCount,\n} from './util/validationUtils.js';\nimport {parseSymbol} from './util/symbolParser.js';\n\n/**\n * Maximum number of bytes searched for the XML header delimiter before giving up.\n * Real QVD headers are a few kilobytes; the largest observed is well under 100KB.\n */\nconst MAX_HEADER_SIZE = 16 * 1024 * 1024;\n\n/**\n * Maximum length of a single fs.read call. Node's fs.read binding requires the length to fit\n * in an Int32: a larger value aborts the process via a C++ assertion instead of throwing.\n */\nconst READ_CHUNK_SIZE = 512 * 1024 * 1024;\n\n/**\n * Parses a QVD file and loads it into memory.\n */\nexport class QvdFileReader {\n /**\n * Constructs a new QVD file parser.\n *\n * @param {string} filePath The path to the QVD file to load.\n * @param {Object} [options={}] Options for the reader.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.3] Fraction (0.0-1.0) of the memory budget a\n * load may use. The budget is the smallest of the V8 heap limit, any container memory limit,\n * and the memory the OS reports as available. Default is 0.3. **Zero disables the memory\n * check entirely**, which is the escape hatch for runtimes whose limits cannot be measured -\n * Bun reports its current heap as its heap limit - and for callers who would rather manage\n * memory themselves than trust the estimate.\n * @param {boolean} [options.materialisesRows=true] Whether this read will build row arrays.\n * False for a columnar read, whose memory is TypedArray backing stores outside the V8 heap\n * and which must not be charged the row cost.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes,\n * above which a lazy load switches to the two-pass filtering path. The default of 50MB is\n * the point where the extra analysis pass pays for itself; lower it to use filtering on\n * smaller files, raise it to keep the simpler single-pass read for longer.\n */\n constructor(filePath, options = {}) {\n const {\n allowedDir,\n memorySafetyFactor = 0.8,\n symbolFilteringThreshold = 50 * 1024 * 1024,\n materialisesRows = true,\n } = options;\n this._materialisesRows = materialisesRows;\n this._path = validatePath(filePath, allowedDir);\n this._memorySafetyFactor = memorySafetyFactor;\n this._symbolFilteringThreshold = symbolFilteringThreshold;\n this._buffer = null;\n this._headerOffset = null;\n this._symbolTableOffset = null;\n this._indexTableOffset = null;\n this._header = null;\n /** @type {Array<Array<import('./QvdSymbol.js').QvdSymbol>>|null} */\n this._symbolTable = null;\n /**\n * Stored symbol indices, one Int32Array per field rather than one array per row.\n *\n * Column-major because that is what lets the decoder hoist a field's bit offset, width and\n * bias out of the row loop and write straight into a typed array - no allocation per row or\n * per cell. Renamed from `_indexTable` deliberately: the shape changed, and a reader of this\n * code should not have to discover that from the subscripts.\n *\n * @type {Array<Int32Array>|null}\n */\n this._indexColumns = null;\n\n /** Rows actually decoded into `_indexColumns`. @type {number} */\n this._rowsDecoded = 0;\n /** @type {number|null} */\n this._fileSize = null;\n /** Whether the header's declared extent fits inside the file. False until _readData says so. */\n this._headerMatchesFile = false;\n }\n\n /**\n * Reads the binary data of the QVD file.\n *\n * LAZY LOADING OPTIMIZATION: When maxRows is specified, this method implements\n * true lazy loading by reading only the necessary portions of the file from disk.\n *\n * For large files (e.g., 5GB), loading only the first 1000 rows can save significant\n * memory and time:\n * - Full load: 5GB in memory, ~30-60s load time\n * - Lazy load (maxRows=1000): ~1.75-2GB in memory, ~2-5s load time\n *\n * Algorithm for Lazy Loading:\n * 1. Stream-read the file until XML header delimiter is found\n * 2. Parse header to determine symbol table and index table locations\n * 3. Calculate bytes needed: header + full symbol table + partial index table\n * 4. Read only those calculated bytes using fs.open/read\n * 5. Rest of parsing proceeds normally with limited data\n *\n * WHY THIS APPROACH:\n * - Symbol table must be fully loaded (contains all unique values)\n * - Index table can be partially loaded (only rows we need)\n * - Streaming for header finding is efficient for unknown header sizes\n * - Direct byte-range reading for remaining data is fastest\n *\n * @param {number|null} maxRows The maximum number of rows to load. If null, all data is loaded.\n * @param {boolean} [headerOnly=false] Stop once the XML header has been read, leaving the\n * symbol and index tables on disk. This is the metadata-only path: the header is a few\n * kilobytes whatever the file's size, so reading a schema costs the same for a 40MB file as\n * for a 40GB one.\n * @private\n */\n async _readData(maxRows = null, headerOnly = false) {\n // The header is scanned first on both paths, including a full load that is about to read the\n // whole file anyway. It costs a few kilobytes and it is what lets the memory check run\n // *before* the body is read: otherwise a 1.7GB file is loaded into memory in full and only\n // then refused, which is the opposite of what a safety check is for.\n const HEADER_DELIMITER = '\\r\\n\\0';\n const CHUNK_SIZE = 64 * 1024; // 64KB chunks - balance between memory and I/O efficiency\n\n // Use streaming to find the header delimiter dynamically\n // We don't know header size in advance, so we must stream-read\n const stream = fs.createReadStream(this._path, {\n highWaterMark: CHUNK_SIZE,\n });\n\n /** @type {Array<Buffer>} */\n const headerChunks = [];\n let headerBytes = 0;\n /** Last (delimiter length - 1) bytes seen so far, carried across chunk boundaries. */\n let tail = Buffer.alloc(0);\n let headerDelimiterIndex = -1;\n\n try {\n // Read chunks until we find the delimiter.\n //\n // Chunks are collected and concatenated once, and each chunk is searched individually\n // (with a small carry-over so a delimiter straddling a chunk boundary is still found).\n // Concatenating the whole accumulated buffer on every chunk and re-scanning it from the\n // start is quadratic: a 200 MB delimiter-less file cost 43 s and 13 GB of memory.\n for await (const chunk of stream) {\n // Search the new chunk prefixed by the bytes already seen, so a delimiter spanning a\n // chunk boundary is not missed.\n //\n // The carry is kept in `tail` across iterations rather than read back off the previous\n // chunk, because a chunk may be shorter than the delimiter. Taking min(bytesSoFar, 2)\n // bytes from a 1-byte previous chunk yields only 1 byte, which both misses a delimiter\n // spread over three chunks and leaves the reported offset short by the difference.\n const chunkStart = headerBytes;\n const searchBuffer = tail.length > 0 ? Buffer.concat([tail, chunk]) : chunk;\n const foundInSearch = searchBuffer.indexOf(HEADER_DELIMITER);\n\n headerChunks.push(chunk);\n headerBytes += chunk.length;\n\n if (foundInSearch !== -1) {\n // searchBuffer starts tail.length bytes before this chunk does.\n headerDelimiterIndex = chunkStart - tail.length + foundInSearch;\n stream.destroy();\n break;\n }\n\n // Copy the carry instead of keeping a subarray view, which would pin the whole chunk.\n tail = Buffer.from(searchBuffer.subarray(-(HEADER_DELIMITER.length - 1)));\n\n // Real QVD headers are a few kilobytes. Without a cap, a non-QVD or corrupt file is\n // read to its end before the error below is raised, which is a denial-of-service\n // vector for any service that accepts uploaded files.\n if (headerBytes > MAX_HEADER_SIZE) {\n stream.destroy();\n throw new QvdCorruptedError(\n `The XML header delimiter was not found within the first ${MAX_HEADER_SIZE / (1024 * 1024)}MB of the file.`,\n {\n file: this._path,\n bytesSearched: headerBytes,\n maxHeaderSize: MAX_HEADER_SIZE,\n stage: 'readData',\n },\n );\n }\n }\n } catch (error) {\n // Destroying the stream once the delimiter is found surfaces as ERR_STREAM_PREMATURE_CLOSE.\n // That one case is expected and ignored; everything else must propagate.\n //\n // The previous condition also required a 'code' property, so any error without one — a\n // TypeError or RangeError raised in the loop body, or a stream error from a source that\n // does not set a code — was swallowed. Execution then fell through to the generic\n // 'header not properly delimited' error below, reporting file corruption for what was\n // actually a bug or an I/O failure.\n const isExpectedEarlyClose =\n headerDelimiterIndex !== -1 &&\n error !== null &&\n typeof error === 'object' &&\n /** @type {{code?: unknown}} */ (error).code === 'ERR_STREAM_PREMATURE_CLOSE';\n\n if (!isExpectedEarlyClose) {\n throw error;\n }\n }\n\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'readData',\n },\n );\n }\n\n const headerBuffer = Buffer.concat(headerChunks);\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n\n // Parse header to get metadata about symbol and index table locations\n const headerXml = headerBuffer.subarray(0, headerEndIndex).toString();\n const headerObj = await xml.parseStringPromise(headerXml, {explicitArray: false});\n\n if (!headerObj) {\n throw new QvdParseError('The XML header could not be parsed.', {\n file: this._path,\n stage: 'readData',\n });\n }\n\n const symbolTableOffset = headerEndIndex;\n const symbolTableLength = parseInt(headerObj['QvdTableHeader']['Offset'], 10);\n const indexTableOffset = symbolTableOffset + symbolTableLength;\n const recordSize = parseInt(headerObj['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(headerObj['QvdTableHeader']['NoOfRecords'], 10);\n\n if (headerOnly) {\n // The header, and not one byte more. `headerChunks` holds whole 64KB chunks, so the tail\n // of the last one is whatever followed the delimiter; trimming it is what keeps this\n // constant-cost rather than \"the header plus up to 64KB of symbol table\".\n //\n // This returns before the memory check below on purpose. That check sizes the rows a call\n // will materialise, and this call materialises none - running it would let a file too\n // large to load refuse to report its own schema, which is the opposite of the point.\n //\n // _parseHeader runs next and re-derives the offsets from this buffer, exactly as it does\n // on the full path. Nothing downstream of it is reached, because there are no rows.\n this._buffer = headerBuffer.subarray(0, headerEndIndex);\n return;\n }\n\n // Column count drives the largest term in the memory estimate, because what actually\n // exhausts the heap on a many-row file is one array per row plus one slot per cell - not the\n // symbol table, which for the commonest Qlik shape is tiny.\n let headerFields = headerObj['QvdTableHeader']?.['Fields']?.['QvdFieldHeader'];\n if (headerFields && !Array.isArray(headerFields)) {\n headerFields = [headerFields];\n }\n const columnCount = Array.isArray(headerFields) ? headerFields.length : 0;\n\n // SAFETY CHECK: enough memory to materialise the rows this call will produce. Runs here,\n // before any large read, so a file too big to hold is refused rather than read and refused.\n //\n // Two conditions gate it, and both exist so that a corrupt file keeps its accurate diagnosis\n // instead of being reported as an out-of-memory problem.\n //\n // The numbers have to be usable at all - a NaN or negative Offset would produce a nonsense\n // estimate - and they have to be consistent with the file on disk. The estimate is computed\n // from NoOfRecords, so a header that overstates it produces an enormous figure: a truncated\n // 3KB file claiming 900 million rows was refused for needing 530GB of RAM, when what it\n // actually needs is to be re-downloaded. Where the file contradicts its own header, this\n // declines to make a memory claim and lets the structural checks downstream say what is\n // really wrong.\n const headerNumbersUsable = [symbolTableLength, recordSize, totalRows].every(\n (value) => Number.isSafeInteger(value) && value >= 0,\n );\n\n if (headerNumbersUsable) {\n const {size: fileSize} = await fs.promises.stat(this._path);\n this._fileSize = fileSize;\n this._headerMatchesFile = headerEndIndex + symbolTableLength + totalRows * recordSize <= fileSize;\n }\n\n if (headerNumbersUsable && this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolTableLength,\n maxRows,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n columnCount,\n this._materialisesRows,\n );\n }\n\n if (maxRows === null) {\n // Load entire file into memory (original behavior)\n // This is simple and fast for small to medium files\n this._buffer = await fs.promises.readFile(this._path);\n this._fileSize = this._buffer.length;\n return;\n }\n\n const rowsToLoad = Math.min(maxRows, totalRows);\n\n // SAFETY CHECK: Very large symbol tables are still blocked to prevent OOM. Lazy loads only -\n // a full load is bounded by validateSymbolTableSize instead, which allows more.\n validateSymbolTableSizeEarly(symbolTableLength, this._path);\n\n // Validate the header numbers before they are used to size an allocation. Without this,\n // a NaN or negative value reaches Buffer.alloc and surfaces as a raw Node RangeError.\n for (const [name, value] of [\n ['Offset', symbolTableLength],\n ['RecordByteSize', recordSize],\n ['NoOfRecords', totalRows],\n ]) {\n if (!Number.isSafeInteger(value) || Number(value) < 0) {\n throw new QvdCorruptedError(`Invalid header value: ${name}`, {\n name,\n value,\n file: this._path,\n stage: 'readData',\n });\n }\n }\n\n // Calculate how much of the index table we need to read\n const indexTableBytesToRead = rowsToLoad * recordSize;\n\n // Calculate total bytes needed: header + symbol table + partial index table\n const totalBytesToRead = indexTableOffset + indexTableBytesToRead;\n\n // Now read the exact portion we need from the file\n const fd = await fs.promises.open(this._path, 'r');\n try {\n const {size: fileSize} = await fd.stat();\n this._fileSize = fileSize;\n\n // The buffer size is derived entirely from header values, which may not describe the\n // file on disk (truncated download, interrupted copy, file still being written, or a\n // deliberately crafted header). Reading past the end would otherwise leave the tail of\n // the buffer holding whatever memory the allocator handed out, and that memory is then\n // parsed as symbol and index data.\n if (totalBytesToRead > fileSize) {\n throw new QvdCorruptedError('The file is shorter than its header claims.', {\n file: this._path,\n fileSize,\n requiredBytes: totalBytesToRead,\n stage: 'readData',\n });\n }\n\n // Zero-filled rather than allocUnsafe: if any path ever fails to overwrite part of this\n // buffer, the result is zeros instead of leaked process memory.\n this._buffer = Buffer.alloc(totalBytesToRead);\n\n // Read in bounded chunks, checking bytesRead each time. A single fs.read call with a\n // length of 2^31 or more does not throw - it trips a C++ assertion and aborts the whole\n // process, which no try/catch can intercept.\n let position = 0;\n while (position < totalBytesToRead) {\n const length = Math.min(READ_CHUNK_SIZE, totalBytesToRead - position);\n // @ts-ignore - Buffer type compatibility\n const {bytesRead} = await fd.read(this._buffer, position, length, position);\n\n if (bytesRead === 0) {\n throw new QvdCorruptedError('Unexpected end of file while reading QVD data.', {\n file: this._path,\n fileSize,\n bytesRead: position,\n requiredBytes: totalBytesToRead,\n stage: 'readData',\n });\n }\n\n position += bytesRead;\n }\n } finally {\n await fd.close();\n }\n }\n\n /**\n * Parses the XML header of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n */\n async _parseHeader() {\n if (!this._buffer) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const HEADER_DELIMITER = '\\r\\n\\0';\n\n const headerBeginIndex = 0;\n const headerDelimiterIndex = this._buffer.indexOf(HEADER_DELIMITER, headerBeginIndex);\n\n // Check explicitly for -1 (not found) rather than using falsy check (!headerDelimiterIndex)\n // because indexOf() returns 0 when the delimiter is at position 0, which is a valid buffer index.\n // Using !0 would incorrectly treat position 0 as an error.\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n const headerBuffer = this._buffer.subarray(headerBeginIndex, headerEndIndex);\n\n /*\n * The following instruction parses the XML header into a JSON object. It is important to\n * note that the object is a plain JavaScript object and not an instance of representative\n * class. Hence, types are not casted, therefore all raw values are strings, and child nodes\n * that contain an array of objects are not represented directly as an array but as an object\n * with a property, named like the array item tag, that is an array of the actual objects. The\n * same applies to child nodes that contain a single object and the root node.\n *\n * The following XML representation of the QVD header for example...\n *\n * <QvdTableHeader>\n * ...\n * <Fields>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * </Fields>\n * </QvdTableHeader>\n *\n * ...is parsed into the following object:\n *\n * {\n * QvdTableHeader: {\n * ...,\n * Fields: {\n * QvdFieldHeader: [\n * { FieldName: 'Field1', ...},\n * { FieldName: 'Field2', ...}\n * ]\n * }\n * }\n * }\n */\n\n // Note: xml2js (via sax-js) does not support external entity resolution\n // by default, providing inherent protection against XXE attacks.\n this._header = await xml.parseStringPromise(headerBuffer.toString(), {explicitArray: false});\n\n if (!this._header) {\n throw new QvdParseError('The XML header could not be parsed.', {\n file: this._path,\n stage: 'parseHeader',\n });\n }\n\n /*\n * Because the three parts of the QVD file, header, symbol and index table, are seamlessly concatenated,\n * the end of the respective previous part is the beginning of the next part.\n */\n\n // A header with no field elements, validated here rather than at each use.\n //\n // Three places downstream normalise the field list with\n // `if (!Array.isArray(fields)) fields = [fields]`, which turns an absent `<Fields/>` into\n // `[undefined]` and then dereferences it - a bare TypeError from the middle of the reader\n // where readMetadata, which checks, reports the file as corrupt. Checking once, at the\n // point the header becomes available, means every path downstream can assume a field list.\n const fields = this._header['QvdTableHeader']?.['Fields']?.['QvdFieldHeader'];\n const fieldCount = fields === undefined || fields === null ? 0 : Array.isArray(fields) ? fields.length : 1;\n\n if (fieldCount === 0) {\n throw new QvdCorruptedError('The QVD file header declares no fields', {\n file: this._path,\n stage: 'parseHeader',\n });\n }\n\n this._headerOffset = headerBeginIndex;\n this._symbolTableOffset = headerEndIndex;\n this._indexTableOffset = this._symbolTableOffset + parseInt(this._header['QvdTableHeader']['Offset'], 10);\n }\n\n /**\n * Establishes the geometry of the index table, and validates it.\n *\n * Both passes over the index table - the symbol-usage analysis and the decode itself - need\n * exactly this, and they used to derive it separately with two copies of the same bit\n * unpacking. The copies are the reason the bias comment in the analysis pass warns so loudly\n * about keeping the sign in step with the other one: the two could drift, and #113 is what\n * that looks like when they do. There is one copy now.\n *\n * @param {number|null} rowLimit Maximum rows of interest, or null for all of them.\n * @param {string} stage Stage name for any error raised here.\n * @return {{fields: Array<any>, recordSize: number, totalRows: number, rowsToLoad: number,\n * indexBuffer: Buffer}} The record geometry.\n * @private\n */\n _planIndexTable(rowLimit, stage) {\n if (!this._buffer || !this._header || !this._indexTableOffset) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage,\n },\n );\n }\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n // Size of a single row of the index table in bytes\n const recordSize = parseInt(this._header['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n const rowsToLoad = rowLimit !== null ? Math.min(rowLimit, totalRows) : totalRows;\n const indexTableLength = parseInt(this._header['QvdTableHeader']['Length'], 10);\n\n // Validate all index table metadata\n validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n this._indexTableOffset,\n this._buffer.length,\n rowsToLoad,\n this._path,\n this._fileSize,\n );\n\n const indexBuffer = this._buffer.subarray(this._indexTableOffset, this._indexTableOffset + indexTableLength + 1);\n\n // Validate BitOffset and BitWidth for all fields before processing\n for (const field of fields) {\n validateFieldBitMetadata(field, recordSize, this._path);\n }\n\n // The decoder indexes into the buffer without per-row bounds checks, which is only sound\n // because validateIndexTableMetadata has already established that the buffer holds\n // rowsToLoad whole records: it requires indexTableLength >= rowsToLoad * recordSize and\n // indexTableOffset + rowsToLoad * recordSize <= buffer.length, and indexBuffer spans from\n // the offset to the end of the declared table. The row loop this replaced re-checked per\n // record, which was dead code for the same reason.\n //\n // Stated as an assertion rather than dropped, because relaxing any of those checks later\n // would make the decode read past the end - where an out-of-range byte is undefined, the\n // arithmetic yields NaN, and the stored index silently becomes 0. Better to fail here.\n assert(\n rowsToLoad === 0 || recordSize === 0 || Math.floor(indexBuffer.length / recordSize) >= rowsToLoad,\n `The index table holds ${Math.floor(indexBuffer.length / (recordSize || 1))} whole records ` +\n `but ${rowsToLoad} were validated as present.`,\n );\n\n return {fields, recordSize, totalRows, rowsToLoad, indexBuffer};\n }\n\n /**\n * Analyzes the index table to determine which symbols are actually needed.\n * This is used for two-pass symbol filtering optimization.\n *\n * @param {number} maxRows The maximum number of rows to analyze.\n * @return {Promise<Map<string, Set<number>>>} Map of field names to Set of needed symbol indices.\n * @private\n */\n async _analyzeIndexTableSymbolUsage(maxRows) {\n const {fields, recordSize, rowsToLoad, indexBuffer} = this._planIndexTable(maxRows, 'analyzeIndexTableSymbolUsage');\n\n // Map of field name -> Set of symbol indices needed\n /** @type {Map<string, Set<number>>} */\n const symbolUsage = new Map();\n\n // One column's worth of indices, reused across fields: the analysis only needs the distinct\n // values, so there is no reason to keep more than one decoded column alive at a time.\n const column = new Int32Array(rowsToLoad);\n\n fields.forEach((/** @type {any} */ field) => {\n const needed = new Set();\n symbolUsage.set(field['FieldName'], needed);\n\n // The bias is applied inside the decoder, which is the same call the parse pass makes.\n // When these were two separate unpackings, a sign difference here would have recorded the\n // wrong symbols as needed and every affected cell would have read back as undefined -\n // silently, because nothing throws on an index that addresses no symbol.\n decodeIndexColumn(\n indexBuffer,\n recordSize,\n rowsToLoad,\n parseInt(field['BitOffset'], 10),\n parseInt(field['BitWidth'], 10),\n parseInt(field['Bias'], 10),\n column,\n );\n\n for (let row = 0; row < rowsToLoad; row++) {\n // Negative indices denote NULL and reference no symbol, so they never need to be kept.\n if (column[row] >= 0) {\n needed.add(column[row]);\n }\n }\n });\n\n return symbolUsage;\n }\n\n /**\n * Parses the symbol table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * @param {Map<string, Set<number>>|null} symbolsToKeep Optional map of field names to symbol indices to keep.\n * If provided, only these symbols will be parsed (two-pass filtering optimization).\n * @param {number|null} maxRows Optional maximum number of rows being loaded (for memory estimation).\n */\n async _parseSymbolTable(symbolsToKeep = null, maxRows = null) {\n if (!this._buffer || !this._header || !this._symbolTableOffset || !this._indexTableOffset) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseSymbolTable',\n },\n );\n }\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n const symbolBuffer = this._buffer.subarray(this._symbolTableOffset, this._indexTableOffset);\n const symbolTableSize = symbolBuffer.length;\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n\n // SAFETY CHECK 1: Absolute ceiling to prevent pathological cases\n // Phase 2.5 optimization allows much larger symbol tables when using maxRows,\n // but we still need an absolute maximum to prevent truly extreme cases\n validateSymbolTableSize(symbolTableSize, this._path, totalRows);\n\n // SAFETY CHECK 2: Dynamic memory validation, now against the symbol table's real size rather\n // than the size its header declared. _readData already ran this check before reading\n // anything; this is the more accurate second look, and the two agree on a well-formed file.\n //\n // Skipped on the same condition as the early one. This is the call that mattered: the\n // structural checks that identify a truncated file run in _parseIndexTable, after this, so\n // an estimate built on an inflated NoOfRecords would report a memory problem for a file\n // whose real problem is that it is short.\n if (this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolTableSize,\n maxRows,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n Array.isArray(fields) ? fields.length : 1,\n this._materialisesRows,\n );\n }\n\n // WARNING ZONE: Large files without maxRows parameter\n // Educate users about best practices but don't block\n warnLargeSymbolTable(\n symbolTableSize,\n maxRows,\n totalRows,\n Array.isArray(fields) ? fields.length : 1,\n this._materialisesRows,\n );\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n /*\n * The symbol table is a contiguous byte array that contains all possible symbols/values of all fields/columns.\n * The symbols/values of one field are stored consecutively in the same order as the fields/columns are defined\n * in the header. The length of the symbol area as well as it's offset, relativ to the begin of the symbol\n * table, are also defined in the header.\n */\n\n // Validate all field metadata before processing to prevent buffer overflow attacks\n for (const field of fields) {\n validateFieldMetadata(field, symbolBuffer.length, this._path);\n }\n\n // Parse all possible symbols of each field/column\n // Phase 2.5 optimization: Skip parsing entirely for symbols we don't need\n this._symbolTable = fields.map((/** @type {any} */ field) => {\n const symbolsOffset = parseInt(field['Offset'], 10); // Offset of the column's symbol area in the symbol table\n const symbolsLength = parseInt(field['Length'], 10); // Length of the column's symbol area in the symbol table\n\n const fieldName = field['FieldName'];\n const neededSymbols = symbolsToKeep ? symbolsToKeep.get(fieldName) : null;\n const filteringEnabled = neededSymbols !== null;\n\n const symbols = [];\n let symbolIndex = 0; // Track current symbol index as we parse\n\n // Parse all possible values of the current field/column\n for (let pointer = symbolsOffset; pointer < symbolsOffset + symbolsLength; pointer++) {\n // Each stored symbol consists of a type byte and the actual value, which length depends on the type\n const typeByte = symbolBuffer[pointer++];\n\n // Check if we should keep this symbol (filtering mode)\n const shouldKeepSymbol = !filteringEnabled || !!(neededSymbols && neededSymbols.has(symbolIndex));\n\n // Use utility function to parse or skip symbol\n const {symbol, bytesRead} = parseSymbol(\n typeByte,\n symbolBuffer,\n pointer,\n symbolBuffer.length,\n fieldName,\n this._path,\n shouldKeepSymbol,\n );\n\n symbols.push(symbol);\n pointer += bytesRead - 1; // -1 because the loop will increment\n symbolIndex++;\n }\n\n return symbols;\n // @ts-ignore - Symbol table type assignment\n });\n }\n\n /**\n * Parses the bit stuffed index table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * One `Int32Array` per field, filled by `decodeIndexColumn`, replacing an array per row filled\n * a bit at a time. The old route, per row, built an `Int32Array` of the record's bytes,\n * concatenated a binary string of `recordSize * 8` characters, split it into a character\n * array, reversed that, and mapped it to one number per *bit*; then per cell it sliced the\n * result again and summed `bit * Math.pow(2, index)`. Several arrays the length of the record\n * in bits, built and discarded for every row.\n *\n * Column-major is what makes the decode tight: a field's bit offset, width and bias are the\n * same for every row, so they are hoisted out of the loop and the inner loop does arithmetic\n * into a typed array and nothing else. Rows are assembled later, once, in `load()`.\n *\n * @param {number|null} maxRows The maximum number of rows to parse. If null, all rows are parsed.\n */\n async _parseIndexTable(maxRows = null) {\n const {fields, recordSize, rowsToLoad, indexBuffer} = this._planIndexTable(maxRows, 'parseIndexTable');\n\n this._rowsDecoded = rowsToLoad;\n this._indexColumns = fields.map((/** @type {any} */ field) =>\n decodeIndexColumn(\n indexBuffer,\n recordSize,\n rowsToLoad,\n parseInt(field['BitOffset'], 10),\n parseInt(field['BitWidth'], 10),\n parseInt(field['Bias'], 10),\n new Int32Array(rowsToLoad),\n ),\n );\n }\n\n /**\n * Reads the file's schema and header metadata, without touching the symbol or index tables.\n *\n * Constant cost in the size of the file. `fromQvd(path, {maxRows: 0})` is not the same thing\n * and never was: the lazy path reads `headerEnd + symbolTableLength + rowsToLoad * recordSize`\n * bytes, so it still pulls the entire symbol table - 0.4MB on the taxi fixture, but hundreds\n * of megabytes on a high-cardinality file, and it has to be parsed as well as read.\n *\n * The memory check is deliberately not run for this. It sizes the rows a call will\n * materialise, and this materialises none; applying it would let a file too large to load\n * refuse to say what is in it.\n *\n * @return {Promise<import('./QvdDataFrame.js').QvdFileMetadata>} The file's schema and header.\n */\n async loadMetadata() {\n await this._readData(null, true);\n await this._parseHeader();\n\n assert(this._header, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n\n let fields = header['Fields']?.['QvdFieldHeader'] ?? [];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n // A header that declares no fields is a broken header, not a table with no columns, and\n // reporting `columnCount: 0` for it would be the same kind of plausible-but-wrong answer\n // this library keeps having to design against. Loading such a file throws too.\n if (fields.length === 0) {\n throw new QvdCorruptedError('The QVD file header declares no fields', {\n file: this._path,\n stage: 'readMetadata',\n });\n }\n\n const columns = fields.map((/** @type {any} */ field) => field['FieldName']);\n const rowCount = parseInt(header['NoOfRecords'], 10);\n\n // The same rule a load applies, through the same function. Coercing an unusable value to\n // zero here instead would report a damaged 606-row file as empty, and `rowCount` is exactly\n // what a caller is expected to branch on.\n validateRecordCount(rowCount, this._path, 'readMetadata');\n\n // An empty frame carrying the same header, so the camelCase mappings live in one place\n // rather than being spelled out a second time here and drifting from the ones a loaded\n // frame reports.\n const shape = new QvdDataFrame([], columns, header, {\n symbolTableBytes: parseInt(header['Offset'], 10),\n totalRows: rowCount,\n rowsLoaded: 0,\n symbolFiltering: false,\n symbolsKept: null,\n });\n\n return {\n columns,\n rowCount,\n columnCount: columns.length,\n fields: columns.map((/** @type {string} */ name) => shape.getFieldMetadata(name)),\n fileMetadata: shape.fileMetadata,\n metadata: header,\n };\n }\n\n /**\n * Loads the QVD file into memory and parses it.\n *\n * @param {number|null} maxRows The maximum number of rows to load. If null, all rows are loaded.\n * Must be a non-negative integer when given.\n * @throws {QvdValidationError} If maxRows is neither null nor a non-negative integer.\n * @return {Promise<QvdDataFrame>} The loaded QVD file.\n */\n async load(maxRows = null) {\n const {columns, metadata, loadStats, resolvedByField} = await this._decode(maxRows);\n\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n // Rows are built once, here, from the decoded columns. `data` stays eager: of the four ways\n // this library is used - a full read, a preview already bounded by maxRows, writing an\n // array out, and reading metadata - not one is helped by materialising a row only when it\n // is touched, and a lazy accessor would cost a proxy, a cache and mutation semantics to\n // serve none of them. A caller who wants columns without paying for rows uses\n // QvdColumnTable, which stops before this loop.\n const indexColumns = this._indexColumns;\n const fieldCount = indexColumns.length;\n const data = new Array(this._rowsDecoded);\n\n for (let row = 0; row < this._rowsDecoded; row++) {\n const values = new Array(fieldCount);\n\n for (let field = 0; field < fieldCount; field++) {\n const symbolIndex = indexColumns[field][row];\n\n // A negative index is how a bias of -2 encodes NULL: stored index 0 means NULL, and\n // real symbols start at 2. It addresses no symbol.\n values[field] = symbolIndex < 0 ? null : resolvedByField[field][symbolIndex];\n }\n\n data[row] = values;\n }\n\n loadStats.rowsLoaded = data.length;\n\n return new QvdDataFrame(data, columns, metadata, loadStats);\n }\n\n /**\n * Reads and decodes the file, stopping short of building rows.\n *\n * Everything `load()` and `loadColumnar()` have in common, which is everything except the\n * shape of the answer. Two read paths for one binary format is the drift risk #113 is the\n * standing example of - a stored index resolved one way here and another way there returns\n * plausible wrong values and throws nothing - so there is one path, and the two entry points\n * differ only in what they do with what it returns.\n *\n * @param {number|null} maxRows Maximum rows to decode, or null for all of them.\n * @return {Promise<{columns: Array<string>, metadata: any, loadStats: any,\n * resolvedByField: Array<Array<any>>}>} The decoded file.\n * @private\n */\n async _decode(maxRows = null) {\n // Validate before any I/O. Every downstream use is Math.min(maxRows, totalRows), which\n // silently accepts nonsense: a negative value yields a negative row count, NaN makes every\n // comparison false, and a fractional value produces a fractional loop bound. Each of those\n // returns a wrong or empty data frame rather than an error, so reject them up front.\n // undefined never reaches here: the default parameter above turns it into null.\n if (maxRows !== null && (typeof maxRows !== 'number' || !Number.isInteger(maxRows) || maxRows < 0)) {\n throw new QvdValidationError('maxRows must be a non-negative integer, or null to load all rows', {\n provided: maxRows,\n type: typeof maxRows,\n file: this._path,\n });\n }\n\n await this._readData(maxRows);\n await this._parseHeader();\n\n // Determine if we should use two-pass symbol filtering\n // This optimization is beneficial for large symbol tables with limited row access\n let symbolsToKeep = null;\n let symbolsKept = null;\n\n if (maxRows !== null && this._header) {\n const symbolTableLength = parseInt(this._header['QvdTableHeader']['Offset'], 10);\n\n // Use two-pass filtering for symbol tables above the threshold when loading limited rows.\n // The threshold is an option rather than a constant so this path can be exercised with a\n // small fixture: it is the most intricate code in the reader, and the only files large\n // enough to reach the 50MB default are ones no repository should be carrying around.\n if (symbolTableLength > this._symbolFilteringThreshold) {\n // Pass 1: Analyze which symbols are actually needed\n symbolsToKeep = await this._analyzeIndexTableSymbolUsage(maxRows);\n\n // Recorded rather than logged. This used to be a console.log, which a library has no\n // business emitting: callers could not silence it, and it was the only way to find out\n // whether filtering had happened. It is now reported through QvdDataFrame.loadStats,\n // which callers can inspect - and tests can assert on deterministically, where the\n // previous test measured a heapUsed delta and failed on GC timing instead.\n symbolsKept = Array.from(symbolsToKeep.values()).reduce((sum, set) => sum + set.size, 0);\n }\n }\n\n // Pass 2: Parse symbol table (with filtering if enabled)\n await this._parseSymbolTable(symbolsToKeep, maxRows);\n await this._parseIndexTable(maxRows);\n\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolTable, 'The QVD file symbol table has not been parsed.');\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n // Resolve each field's symbols once rather than once per cell.\n //\n // A stored index addresses the same symbol in every row, so the work below - the symbol\n // lookup, toPrimaryValue(), and the numeric-string coercion - depends only on the index.\n // Doing it inside the row loop repeated it 34 million times on the taxi fixture for a\n // symbol table of a few thousand entries.\n //\n // A filtered-out symbol is stored as null by the two-pass path, and an index past the end\n // of the array reads as undefined. Both resolve to undefined here, which is what the\n // per-cell version produced through optional chaining.\n const resolvedByField = this._symbolTable.map((symbols) => {\n const resolved = new Array(symbols.length);\n\n for (let index = 0; index < symbols.length; index++) {\n const value = symbols[index]?.toPrimaryValue();\n\n // Number('') and Number(' ') are 0, which silently turned every blank cell Qlik\n // stored into the number zero - indistinguishable from a real zero, and persisted as\n // one on the next write. Blank strings are never numeric, so exclude them.\n resolved[index] =\n typeof value === 'string' && value.trim() !== '' && !isNaN(Number(value)) ? Number(value) : value;\n }\n\n return resolved;\n });\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const columns = fields.map((/** @type {any} */ field) => field['FieldName']);\n\n // Pass the complete header metadata to the caller\n const metadata = this._header['QvdTableHeader'];\n\n /** @type {import('./QvdDataFrame.js').QvdLoadStats} */\n const loadStats = {\n symbolTableBytes: parseInt(this._header['QvdTableHeader']['Offset'], 10),\n totalRows: parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10),\n rowsLoaded: this._rowsDecoded,\n symbolFiltering: symbolsToKeep !== null,\n symbolsKept,\n };\n\n return {columns, metadata, loadStats, resolvedByField};\n }\n\n /**\n * Reads the file as columns, without ever materialising rows.\n *\n * Shares every step with `load()` up to the point where rows would be built - see `_decode`.\n * What it keeps instead is what the decoder already produced: one `Int32Array` of stored\n * indices per field, and one resolved value per distinct symbol. On the 1.7M x 20 taxi\n * fixture that is 38.6 MiB against the 352.8 MiB `data` retains, because a column costs four\n * bytes per row rather than a boxed value per cell, and the symbols are a few thousand\n * entries shared across every row that uses them.\n *\n * @param {number|null} maxRows The maximum number of rows to decode.\n * @return {Promise<import('./QvdColumnTable.js').QvdColumnTable>} The decoded columns.\n */\n async loadColumnar(maxRows = null) {\n const {columns, metadata, loadStats, resolvedByField} = await this._decode(maxRows);\n const {QvdColumnTable} = await import('./QvdColumnTable.js');\n\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n return new QvdColumnTable({\n columns,\n codesByField: this._indexColumns,\n symbolsByField: resolvedByField,\n rowCount: this._rowsDecoded,\n metadata,\n loadStats,\n });\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * @typedef {Object} QvdNumberFormat\n * @property {string} Type - Number format type\n * @property {string} nDec - Number of decimals\n * @property {string} UseThou - Use thousands separator\n * @property {string} Fmt - Format string\n * @property {string} Dec - Decimal separator\n * @property {string} Thou - Thousands separator\n */\n\n/**\n * @typedef {Object} QvdFieldHeader\n * @property {string} FieldName - The name of the field\n * @property {string|number} [BitOffset] - The bit offset\n * @property {string|number} [BitWidth] - The bit width\n * @property {string|number} [Bias] - The bias value\n * @property {string|number} [NoOfSymbols] - Number of symbols\n * @property {string|number} [Offset] - The offset\n * @property {string|number} [Length] - The length\n * @property {string} [Comment] - Field comment\n * @property {QvdNumberFormat|string} [NumberFormat] - Number format\n * @property {Object|string} [Tags] - Field tags\n */\n\n/**\n * @typedef {Object} QvdFields\n * @property {QvdFieldHeader|QvdFieldHeader[]} QvdFieldHeader - Field header(s)\n */\n\n/**\n * @typedef {Object} QvdMetadata\n * @property {string|number} [QvBuildNo] - QlikView build number\n * @property {string} [CreatorDoc] - Creator document\n * @property {string} [CreateUtcTime] - Creation UTC time\n * @property {string} [SourceCreateUtcTime] - Source creation UTC time\n * @property {string} [SourceFileUtcTime] - Source file UTC time\n * @property {string|number} [SourceFileSize] - Source file size\n * @property {string} [StaleUtcTime] - Stale UTC time\n * @property {string} [TableName] - Table name\n * @property {string|number} [NoOfRecords] - Number of records\n * @property {string|number} [RecordByteSize] - Record byte size\n * @property {string|number} [Offset] - Offset\n * @property {string|number} [Length] - Length\n * @property {string} [Compression] - Compression type\n * @property {string} [Comment] - Comment\n * @property {string} [EncryptionInfo] - Encryption info\n * @property {string} [TableTags] - Table tags\n * @property {string} [ProfilingData] - Profiling data\n * @property {Object|string} [Lineage] - Lineage\n * @property {QvdFields} [Fields] - Fields information\n */\n\n/**\n * A QVD file's schema and header, read without its data.\n *\n * @typedef {Object} QvdFileMetadata\n * @property {Array<string>} columns Field names, in file order.\n * @property {number} rowCount Rows the file declares in its header. Note that this is the\n * file's row count, not a number of rows loaded - nothing was loaded.\n * @property {number} columnCount Number of fields.\n * @property {Array<Object|null>} fields Per-field metadata, in the same shape and order that\n * `getFieldMetadata()` returns for a loaded frame.\n * @property {Object} fileMetadata File-level metadata, in the same shape as the `fileMetadata`\n * accessor on a loaded frame.\n * @property {QvdMetadata} metadata The raw `QvdTableHeader`, as `metadata` gives it.\n */\n\n/**\n * Statistics describing the read that produced a data frame.\n *\n * @typedef {Object} QvdLoadStats\n * @property {number} symbolTableBytes Size of the file's symbol table, in bytes.\n * @property {number} totalRows Rows the file declares in its header.\n * @property {number} rowsLoaded Rows actually materialised.\n * @property {boolean} symbolFiltering Whether the two-pass symbol-filtering path was used.\n * @property {number|null} symbolsKept Symbols retained by that path, or null when it did not run.\n */\n\n/**\n * Represents a loaded QVD file.\n */\nexport class QvdDataFrame {\n /**\n * Represents the data frame stored inside a QVD file.\n * @param {Array<Array<any>>} data The data of the data frame.\n * @param {Array<string>} columns The columns of the data frame.\n * @param {QvdMetadata|null} metadata The metadata from the QVD file header (optional).\n * @param {QvdLoadStats|null} loadStats Statistics about the read (optional).\n */\n constructor(data, columns, metadata = null, loadStats = null) {\n this._data = data;\n this._columns = columns;\n this._metadata = metadata;\n this._loadStats = loadStats;\n }\n\n /**\n * Returns the data of the data frame.\n */\n get data() {\n return this._data;\n }\n\n /**\n * Returns the columns of the data frame.\n */\n get columns() {\n return this._columns;\n }\n\n /**\n * Returns the shape of the data frame.\n */\n get shape() {\n return [this._data.length, this._columns.length];\n }\n\n /**\n * Returns the complete metadata object from the QVD file header.\n * @return {Object|null} The complete metadata object or null if not available.\n */\n get metadata() {\n return this._metadata;\n }\n\n /**\n * Returns statistics about the read that produced this data frame.\n *\n * Only a frame returned by fromQvd() carries these; fromDict(), head() and tail() produce\n * frames that describe no particular read, and report null rather than a stale figure.\n *\n * The main use is confirming that a lazy load actually filtered the symbol table:\n * `symbolFiltering` says whether the two-pass path ran, and `symbolsKept` how many symbols\n * survived it, which for a small maxRows should be a tiny fraction of the file's total.\n *\n * @return {QvdLoadStats|null} Load statistics, or null if this frame did not come from a file.\n */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * Returns file-level metadata from the QVD header.\n * @return {Object} File-level metadata properties.\n */\n get fileMetadata() {\n if (!this._metadata) {\n return {};\n }\n\n const header = this._metadata;\n return {\n qvBuildNo: header.QvBuildNo,\n creatorDoc: header.CreatorDoc,\n createUtcTime: header.CreateUtcTime,\n sourceCreateUtcTime: header.SourceCreateUtcTime,\n sourceFileUtcTime: header.SourceFileUtcTime,\n sourceFileSize: header.SourceFileSize,\n staleUtcTime: header.StaleUtcTime,\n tableName: header.TableName,\n noOfRecords: header.NoOfRecords,\n recordByteSize: header.RecordByteSize,\n offset: header.Offset,\n length: header.Length,\n compression: header.Compression,\n comment: header.Comment,\n encryptionInfo: header.EncryptionInfo,\n tableTags: header.TableTags,\n profilingData: header.ProfilingData,\n lineage: header.Lineage,\n };\n }\n\n /**\n * Returns field-level metadata for a specific field/column.\n * @param {string} fieldName The name of the field.\n * @return {Object|null} Field metadata or null if field not found.\n */\n getFieldMetadata(fieldName) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return null;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const field = fields.find((f) => f.FieldName === fieldName);\n if (!field) {\n return null;\n }\n\n return {\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n };\n }\n\n /**\n * Returns field-level metadata for all fields.\n * @return {Array<Object>} Array of field metadata objects.\n */\n getAllFieldMetadata() {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return [];\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n return fields.map((field) => ({\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n }));\n }\n\n /**\n * @typedef {Object} FileMetadataUpdate\n * @property {string|number} [qvBuildNo] - QlikView build number\n * @property {string} [creatorDoc] - Creator document\n * @property {string} [createUtcTime] - Creation UTC time\n * @property {string} [sourceCreateUtcTime] - Source creation UTC time\n * @property {string} [sourceFileUtcTime] - Source file UTC time\n * @property {string|number} [sourceFileSize] - Source file size\n * @property {string} [staleUtcTime] - Stale UTC time\n * @property {string} [tableName] - Table name\n * @property {string} [compression] - Compression type\n * @property {string} [comment] - Comment\n * @property {string} [encryptionInfo] - Encryption info\n * @property {string} [tableTags] - Table tags\n * @property {string} [profilingData] - Profiling data\n * @property {Object|string} [lineage] - Lineage\n */\n\n /**\n * Sets modifiable file-level metadata. Immutable properties related to data storage are ignored.\n * @param {FileMetadataUpdate} metadata Object containing metadata properties to update.\n */\n setFileMetadata(metadata) {\n if (!this._metadata) {\n // Initialize metadata structure if it doesn't exist\n this._metadata = {\n QvBuildNo: 50667,\n CreatorDoc: '',\n CreateUtcTime: '',\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: '',\n Fields: {\n QvdFieldHeader: this._columns.map((column) => ({\n FieldName: column,\n BitOffset: 0,\n BitWidth: 0,\n Bias: 0,\n NoOfSymbols: 0,\n Offset: 0,\n Length: 0,\n Comment: '',\n NumberFormat: {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: {},\n })),\n },\n NoOfRecords: 0,\n RecordByteSize: 0,\n Offset: 0,\n Length: 0,\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {},\n };\n }\n\n // Only allow modification of certain fields (not Offset, Length, NoOfRecords, RecordByteSize)\n const modifiableFields = [\n 'qvBuildNo',\n 'creatorDoc',\n 'createUtcTime',\n 'sourceCreateUtcTime',\n 'sourceFileUtcTime',\n 'sourceFileSize',\n 'staleUtcTime',\n 'tableName',\n 'compression',\n 'comment',\n 'encryptionInfo',\n 'tableTags',\n 'profilingData',\n 'lineage',\n ];\n\n // Map camelCase to XML property names\n const fieldMapping = {\n qvBuildNo: 'QvBuildNo',\n creatorDoc: 'CreatorDoc',\n createUtcTime: 'CreateUtcTime',\n sourceCreateUtcTime: 'SourceCreateUtcTime',\n sourceFileUtcTime: 'SourceFileUtcTime',\n sourceFileSize: 'SourceFileSize',\n staleUtcTime: 'StaleUtcTime',\n tableName: 'TableName',\n compression: 'Compression',\n comment: 'Comment',\n encryptionInfo: 'EncryptionInfo',\n tableTags: 'TableTags',\n profilingData: 'ProfilingData',\n lineage: 'Lineage',\n };\n\n modifiableFields.forEach((field) => {\n // @ts-ignore - Dynamic property access for metadata mapping\n if (metadata[field] !== undefined) {\n // @ts-ignore - Dynamic property access for metadata mapping\n this._metadata[fieldMapping[field]] = metadata[field];\n }\n });\n }\n\n /**\n * @typedef {Object} FieldMetadataUpdate\n * @property {string} [comment] - Field comment\n * @property {QvdNumberFormat|string} [numberFormat] - Number format\n * @property {Object|string} [tags] - Field tags\n */\n\n /**\n * Sets modifiable field-level metadata for a specific field.\n * Immutable properties related to data storage (Offset, Length, BitOffset, etc.) are ignored.\n * @param {string} fieldName The name of the field.\n * @param {FieldMetadataUpdate} metadata Object containing field metadata properties to update.\n */\n setFieldMetadata(fieldName, metadata) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n this._metadata.Fields.QvdFieldHeader = fields;\n }\n\n const fieldIndex = fields.findIndex((f) => f.FieldName === fieldName);\n if (fieldIndex === -1) {\n return;\n }\n\n // Only allow modification of Comment, NumberFormat, and Tags (not Offset, Length, BitOffset, etc.)\n if (metadata.comment !== undefined) {\n fields[fieldIndex].Comment = metadata.comment;\n }\n if (metadata.numberFormat !== undefined) {\n fields[fieldIndex].NumberFormat = metadata.numberFormat;\n }\n if (metadata.tags !== undefined) {\n fields[fieldIndex].Tags = metadata.tags;\n }\n }\n\n /**\n * Returns the first n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n head(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('head() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(this._data.slice(0, n), this._columns, this._metadata);\n }\n\n /**\n * Returns the last n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n tail(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('tail() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(n === 0 ? [] : this._data.slice(-n), this._columns, this._metadata);\n }\n\n /**\n * Returns the selected rows of the data frame.\n *\n * @param {...number} args The indices of the rows to return.\n * @return {QvdDataFrame} The selected rows of the data frame.\n * @throws {QvdValidationError} If any index is not an integer or is out of bounds.\n */\n rows(...args) {\n for (const index of args) {\n if (typeof index !== 'number' || !Number.isInteger(index)) {\n throw new QvdValidationError('rows() requires integer indices', {\n provided: index,\n type: typeof index,\n });\n }\n if (index < 0 || index >= this._data.length) {\n throw new QvdValidationError(`Row index ${index} out of bounds`, {\n index,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n }\n return new QvdDataFrame(\n args.map((index) => this._data[index]),\n this._columns,\n this._metadata,\n );\n }\n\n /**\n * Returns the value at the specified row and column.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {any} The value at the specified row and column.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n at(row, column) {\n if (typeof row !== 'number' || !Number.isInteger(row)) {\n throw new QvdValidationError('Row index must be an integer', {\n provided: row,\n type: typeof row,\n });\n }\n if (row < 0 || row >= this._data.length) {\n throw new QvdValidationError(`Row index ${row} out of bounds`, {\n index: row,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n return this._data[row][this._columns.indexOf(column)];\n }\n\n /**\n * Selects the specified columns from the data frame.\n *\n * @param {...string} args The names of the columns to select.\n * @return {QvdDataFrame} The selected columns of the data frame.\n * @throws {QvdValidationError} If any column name does not exist.\n */\n select(...args) {\n for (const column of args) {\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n }\n const indices = args.map((arg) => this._columns.indexOf(arg));\n const data = this._data.map((row) => indices.map((index) => row[index]));\n const columns = indices.map((index) => this._columns[index]);\n return new QvdDataFrame(data, columns, this._metadata);\n }\n\n /**\n * Returns the data frame as a dictionary.\n *\n * @return {Promise<{columns: Array<string>, data: Array<Array<any>>}>} The data frame as a dictionary.\n */\n async toDict() {\n return {columns: this._columns, data: this._data};\n }\n\n /**\n * Persists the data frame to a QVD file.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional writing options.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function that receives progress updates during write operations.\n */\n async toQvd(path, options = {}) {\n const {QvdFileWriter} = await import('./QvdFileWriter.js');\n const writerOptions = {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n };\n await new QvdFileWriter(path, this, writerOptions).save();\n }\n\n /**\n * Loads a QVD file and returns its data frame.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional loading options.\n * @param {number|null} [options.maxRows] The maximum number of rows to load. Must be a non-negative\n * integer; if not specified or null, all rows are loaded. Anything else throws a QvdValidationError.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction (0.0-1.0) of the memory budget a load\n * may use. The budget is the smaller of the V8 heap limit and any container memory limit. Default\n * is 0.8; the estimate it scales accounts for the rows and columns being materialised, so this is\n * headroom for garbage collection rather than compensation for an inaccurate figure.\n * **Zero disables the memory check entirely.**\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes, above which\n * a lazy load switches to the two-pass filtering path. Defaults to 50MB.\n * @throws {QvdValidationError} If options.maxRows is neither null/undefined nor a non-negative integer.\n * @return {Promise<QvdDataFrame>} The data frame of the QVD file.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const readerOptions = {\n allowedDir: options.allowedDir,\n memorySafetyFactor: options.memorySafetyFactor,\n symbolFilteringThreshold: options.symbolFilteringThreshold,\n };\n return await new QvdFileReader(path, readerOptions).load(options.maxRows !== undefined ? options.maxRows : null);\n }\n\n /**\n * Reads a QVD file's schema and header metadata, without reading its data.\n *\n * Costs the same whatever the file's size, because it stops at the XML header - a few\n * kilobytes - and never touches the symbol or index tables.\n *\n * This is what `{maxRows: 0}` looks like but is not. That still reads and parses the whole\n * symbol table, which is 0.4MB on a 38MB taxi fixture but hundreds of megabytes on a\n * high-cardinality file. Use this when you want to know what is in a file rather than to\n * read any of it.\n *\n * No data frame comes back, deliberately: one with `data: []` would be indistinguishable\n * from an empty file at the call site.\n *\n * ```js\n * const {columns, rowCount, fields} = await QvdDataFrame.readMetadata('sales.qvd');\n * ```\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional reading options.\n * @param {string} [options.allowedDir] Optional allowed directory path, applied exactly as it\n * is for `fromQvd`.\n * @return {Promise<QvdFileMetadata>} The file's schema and header metadata.\n */\n static async readMetadata(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n return await new QvdFileReader(path, {allowedDir: options.allowedDir}).loadMetadata();\n }\n\n /**\n * Constructs a data frame from a dictionary.\n *\n * @param {{columns: Array<string>, data: Array<Array<any>>}} data The dictionary to construct the data frame from.\n * @return {Promise<QvdDataFrame>} The constructed data frame.\n */\n static async fromDict(data) {\n if (!data.columns) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any columns.', {\n data,\n });\n }\n if (!data.data) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any data.', {\n data,\n });\n }\n\n return new QvdDataFrame(data.data, data.columns);\n }\n}\n","// @ts-check\n\nexport {QvdSymbol} from './QvdSymbol.js';\nexport {QvdDataFrame} from './QvdDataFrame.js';\nexport {QvdColumnTable, QvdColumn} from './QvdColumnTable.js';\nexport {QvdFileReader} from './QvdFileReader.js';\nexport {QvdFileWriter} from './QvdFileWriter.js';\nexport {\n QvdError,\n QvdParseError,\n QvdValidationError,\n QvdIOError,\n QvdCorruptedError,\n QvdSecurityError,\n} from './QvdErrors.js';\n"]}
1
+ {"version":3,"sources":["../src/QvdErrors.js","../src/QvdSymbol.js","../src/util/readOptions.js","../src/util/validatePath.js","../src/util/bitUtils.js","../src/QvdFileWriter.js","../src/util/memoryUtils.js","../src/util/validationUtils.js","../src/util/symbolParser.js","../src/QvdColumnTable.js","../src/QvdFileReader.js","../src/QvdDataFrame.js","../src/index.js"],"names":["QvdError","QvdParseError","QvdValidationError","QvdIOError","QvdCorruptedError","QvdSecurityError","QvdSymbol","path","fs","QvdFileWriter","assert","crypto","xml","v8","os","QvdColumn","QvdColumnTable","QvdFileReader","QvdDataFrame","resolved"],"mappings":"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","file":"index.cjs","sourcesContent":["// @ts-check\n\n/**\n * Base error class for all QVD-related errors.\n * Provides structured error information with error codes and context.\n */\nexport class QvdError extends Error {\n /**\n * Constructs a new QVD error.\n *\n * @param {string} message The error message.\n * @param {string} code The error code.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, code, context = {}) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n this.context = context;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when parsing a QVD file fails.\n * Used for issues during XML header parsing, symbol table parsing, or index table parsing.\n */\nexport class QvdParseError extends QvdError {\n /**\n * Constructs a new QVD parse error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_PARSE_ERROR', context);\n }\n}\n\n/**\n * Error thrown when input validation fails.\n * Used for invalid parameters, out of bounds access, or missing required data.\n */\nexport class QvdValidationError extends QvdError {\n /**\n * Constructs a new QVD validation error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_VALIDATION_ERROR', context);\n }\n}\n\n/**\n * Error thrown when file system operations fail.\n * Used for issues reading or writing QVD files.\n */\nexport class QvdIOError extends QvdError {\n /**\n * Constructs a new QVD IO error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_IO_ERROR', context);\n }\n}\n\n/**\n * Error thrown when a QVD file is corrupted or malformed.\n * Used for missing headers, invalid data structures, or corrupted data.\n */\nexport class QvdCorruptedError extends QvdError {\n /**\n * Constructs a new QVD corrupted error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_CORRUPTED_ERROR', context);\n }\n}\n\n/**\n * Error thrown when security violations occur.\n * Used for path traversal attempts, XXE attacks, or other security issues.\n */\nexport class QvdSecurityError extends QvdError {\n /**\n * Constructs a new QVD security error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_SECURITY_ERROR', context);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * Represents a Qlik symbol/value, stored in a QVD file.\n */\nexport class QvdSymbol {\n /**\n * Constructs a new QVD symbol.\n *\n * @param {number|null} intValue The integer value.\n * @param {number|null} doubleValue The double value.\n * @param {string|null} stringValue The string value.\n */\n constructor(intValue, doubleValue, stringValue) {\n this._intValue = intValue;\n\n this._doubleValue = doubleValue;\n\n this._stringValue = stringValue;\n }\n\n /**\n * Returns the integer value of this symbol.\n *\n * @return {number|null} The integer value.\n */\n get intValue() {\n return this._intValue;\n }\n\n /**\n * Returns the double value of this symbol.\n *\n * @return {number|null} The double value.\n */\n get doubleValue() {\n return this._doubleValue;\n }\n\n /**\n * Returns the string value of this symbol.\n *\n * @return {string|null} The string value.\n */\n get stringValue() {\n return this._stringValue;\n }\n\n /**\n * Retrieves the primary value of this symbol. The primary value is descriptive raw value.\n * It is either the string value, the integer value or the double value, prioritized in this order.\n *\n * @return {number|string|null} The primary value.\n */\n toPrimaryValue() {\n if (null != this._stringValue) {\n return this._stringValue;\n } else if (null != this._intValue) {\n return this._intValue;\n } else if (null != this._doubleValue) {\n return this._doubleValue;\n } else {\n return null;\n }\n }\n\n /**\n * Converts the symbol to its byte representation.\n *\n * @return {Buffer} The byte representation of the symbol.\n */\n toByteRepresentation() {\n if (this._intValue !== null && this._stringValue !== null) {\n const intBuffer = Buffer.alloc(4);\n intBuffer.writeInt32LE(this._intValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n const stringBuffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([5]), intBuffer, stringBuffer]);\n } else if (this._doubleValue !== null && this._stringValue !== null) {\n const floatBuffer = Buffer.alloc(8);\n floatBuffer.writeDoubleLE(this._doubleValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n const stringBuffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([6]), floatBuffer, stringBuffer]);\n } else if (this._intValue !== null) {\n const buffer = Buffer.alloc(4);\n buffer.writeInt32LE(this._intValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([1]), buffer]);\n } else if (this._doubleValue !== null) {\n const buffer = Buffer.alloc(8);\n buffer.writeDoubleLE(this._doubleValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([2]), buffer]);\n } else if (this._stringValue !== null) {\n // @ts-ignore - Buffer.concat type compatibility\n const buffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([4]), buffer]);\n } else {\n throw new QvdValidationError('The symbol does not contain any value.', {\n intValue: this._intValue,\n doubleValue: this._doubleValue,\n stringValue: this._stringValue,\n });\n }\n }\n\n /**\n * Checks if this symbol is equal to another symbol.\n *\n * @param {*} value The object to compare with.\n * @return {boolean} True if the objects are equal, false otherwise.\n */\n equals(value) {\n if (!(value instanceof QvdSymbol)) {\n return false;\n }\n\n return (\n this._intValue === value.intValue &&\n this._doubleValue === value.doubleValue &&\n this._stringValue === value.stringValue\n );\n }\n\n /**\n * Constructs a pure integer value symbol.\n *\n * @param {number} intValue The integer value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromIntValue(intValue) {\n return new QvdSymbol(intValue, null, null);\n }\n\n /**\n * Constructs a pure double value symbol.\n *\n * @param {number} doubleValue The double value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDoubleValue(doubleValue) {\n return new QvdSymbol(null, doubleValue, null);\n }\n\n /**\n * Constructs a pure string value symbol.\n *\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromStringValue(stringValue) {\n return new QvdSymbol(null, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from an integer and a string value.\n *\n * @param {number} intValue The integer value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDualIntValue(intValue, stringValue) {\n return new QvdSymbol(intValue, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from a double and a string value.\n *\n * @param {number} doubleValue The double value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDualDoubleValue(doubleValue, stringValue) {\n return new QvdSymbol(null, doubleValue, stringValue);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * A read's row window: where it starts, and how many rows it covers.\n *\n * @typedef {Object} QvdRowWindow\n * @property {number} offset File row the window starts at.\n * @property {number|null} limit Rows in the window, or null for \"to the end of the file\".\n */\n\n/**\n * Checks a value that has to be a non-negative integer.\n *\n * Every one of these ends up inside a `Math.min(value, totalRows)` somewhere downstream, which\n * accepts nonsense silently: a negative value yields a negative row count, NaN makes every\n * comparison false, and a fraction produces a fractional loop bound. Each returns a wrong or\n * empty frame rather than an error.\n *\n * @param {any} value The value to check.\n * @param {string} name The option's name, for the error.\n * @param {string} filePath The file being read, for the error.\n * @return {number} The value.\n * @throws {QvdValidationError} If it is not a non-negative integer.\n */\nexport function requireRowCount(value, name, filePath) {\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {\n throw new QvdValidationError(`${name} must be a non-negative integer`, {\n option: name,\n provided: value,\n type: typeof value,\n file: filePath,\n });\n }\n\n return value;\n}\n\n/**\n * Normalises a row window from what a caller passed.\n *\n * `maxRows` and `limit` are the same number under two names, and this is the one place that is\n * decided. `maxRows` came first and every released version documents it; `limit` is the spelling\n * that reads correctly beside `offset`, because \"the maximum number of rows\" says nothing about\n * where they start. Neither is deprecated and neither is preferred by the code - they resolve to\n * the same field here, three lines apart, so they cannot drift.\n *\n * Passing both is refused rather than resolved. Any rule for picking a winner - last one wins,\n * the smaller one wins, they have to agree - is a rule a caller has to know, and getting it wrong\n * returns a plausible number of rows rather than an error.\n *\n * @param {number|null|undefined|{offset?: number, limit?: number|null, maxRows?: number|null}} window\n * The window, or a plain row count meaning \"the first N rows\", or null for all of them.\n * @param {string} filePath The file being read, for errors.\n * @return {QvdRowWindow} The normalised window.\n */\nexport function normaliseWindow(window, filePath) {\n if (window === null || window === undefined) {\n return {offset: 0, limit: null};\n }\n\n // The historical spelling: load(5) means the first five rows. Kept exactly, because it is the\n // signature every existing caller uses and `5` and `{offset: 0, limit: 5}` are the same read.\n if (typeof window === 'number') {\n return {offset: 0, limit: requireRowCount(window, 'maxRows', filePath)};\n }\n\n if (typeof window !== 'object' || Array.isArray(window)) {\n throw new QvdValidationError('The row window must be a number, null, or an {offset, limit} object', {\n provided: window,\n type: typeof window,\n file: filePath,\n });\n }\n\n const {offset, limit, maxRows} = window;\n const limitGiven = limit !== undefined && limit !== null;\n const maxRowsGiven = maxRows !== undefined && maxRows !== null;\n\n if (limitGiven && maxRowsGiven) {\n throw new QvdValidationError('maxRows and limit are two names for the same option; pass one of them, not both', {\n maxRows,\n limit,\n file: filePath,\n });\n }\n\n return {\n offset: offset === undefined || offset === null ? 0 : requireRowCount(offset, 'offset', filePath),\n limit: limitGiven\n ? requireRowCount(limit, 'limit', filePath)\n : maxRowsGiven\n ? requireRowCount(maxRows, 'maxRows', filePath)\n : null,\n };\n}\n\n/**\n * Resolves a validated window against the rows a file actually declares.\n *\n * One place, because the answer is used for three different things - which bytes to read, which\n * records to decode, and what to charge the memory guard - and any two of them disagreeing is a\n * silent wrong answer rather than an error.\n *\n * The offset is clamped as well as the count. An offset past the end of the file leaves no rows,\n * which is not an error: it is what a paging loop needs in order to stop, the same way\n * `Array.prototype.slice` answers it. But carrying the unclamped offset forward would have the\n * byte arithmetic demand records the file never had - `{offset: 10_000_000}` on a 135-row file\n * asking for a 30MB read of a 7KB file, and reporting the file as truncated.\n *\n * @param {QvdRowWindow} window The validated window.\n * @param {number} totalRows Rows the file's header declares. An unusable value resolves to an\n * empty window, leaving the structural checks downstream to say what is really wrong with it.\n * @return {QvdRowWindow} The window as it applies to this file: `limit` is now a row count rather\n * than a maximum, and `offset` is inside the file.\n */\nexport function resolveWindow(window, totalRows) {\n const rows = Number.isSafeInteger(totalRows) && totalRows > 0 ? totalRows : 0;\n const offset = Math.min(window.offset, rows);\n\n return {\n offset,\n limit: Math.max(0, Math.min(window.limit === null ? Infinity : window.limit, rows - offset)),\n };\n}\n\n/**\n * Checks a requested field list against the fields a file actually has.\n *\n * Refuses an unknown name rather than dropping it. Returning three columns for a four-name\n * request is the failure shape this library keeps designing against - the caller gets a data\n * frame, the shape looks plausible, and the missing column is discovered somewhere else entirely.\n * A duplicate is refused for the same reason: two columns of one name make `at(row, name)` and\n * `select(name)` answer about the first and ignore the second.\n *\n * The order is the caller's, not the file's, because that is what `QvdDataFrame.select()` already\n * does - `select('b', 'a')` returns `[b, a]` - and one library should not have two answers to the\n * same question.\n *\n * @param {Array<any>} fields Every field header in the file, in file order.\n * @param {Array<string>|null} requested Field names the caller asked for, or null for all.\n * @param {string} filePath The file being read, for errors.\n * @return {Array<any>} The selected field headers, in the caller's order.\n * @throws {QvdValidationError} If a name is unknown, repeated, or the list is empty.\n */\nexport function selectFields(fields, requested, filePath) {\n if (requested === null || requested === undefined) {\n return fields;\n }\n\n if (!Array.isArray(requested)) {\n throw new QvdValidationError('fields must be an array of field names', {\n provided: requested,\n type: typeof requested,\n file: filePath,\n });\n }\n\n const available = fields.map((/** @type {any} */ field) => field['FieldName']);\n\n // A projection of no columns is a frame of N empty rows, whose shape is [N, 0] and whose data\n // answers nothing. Refusing is more useful than returning it.\n if (requested.length === 0) {\n throw new QvdValidationError('fields must name at least one field', {\n availableColumns: available,\n file: filePath,\n });\n }\n\n /** @type {Set<string>} */\n const seen = new Set();\n\n return requested.map((name) => {\n if (typeof name !== 'string') {\n throw new QvdValidationError('Field names must be strings', {\n provided: name,\n type: typeof name,\n availableColumns: available,\n file: filePath,\n });\n }\n\n if (seen.has(name)) {\n throw new QvdValidationError(`Field '${name}' is listed twice`, {\n column: name,\n fields: requested,\n file: filePath,\n });\n }\n\n seen.add(name);\n\n const index = available.indexOf(name);\n\n if (index === -1) {\n throw new QvdValidationError(`Column '${name}' does not exist`, {\n column: name,\n availableColumns: available,\n file: filePath,\n });\n }\n\n return fields[index];\n });\n}\n\n/**\n * The reader options out of a public `fromQvd`-style options object.\n *\n * Split out so that `QvdDataFrame.fromQvd`, `QvdDataFrame.iterate` and `QvdColumnTable.fromQvd`\n * cannot end up supporting three slightly different option sets. They are three answers to the\n * same file with the same knobs; only the shape of what comes back differs.\n *\n * @param {any} options The caller's options.\n * @return {Object} Options for the `QvdFileReader` constructor.\n */\nexport function readerOptionsFrom(options) {\n return {\n allowedDir: options.allowedDir,\n memorySafetyFactor: options.memorySafetyFactor,\n symbolFilteringThreshold: options.symbolFilteringThreshold,\n fields: options.fields === undefined ? null : options.fields,\n onProgress: options.onProgress,\n signal: options.signal,\n };\n}\n\n/**\n * The reader options a header-only read can use.\n *\n * A subset of `readerOptionsFrom`, and expressed here beside it rather than hand-built at the call\n * site, because the subset is the interesting part: it is what stops the two drifting silently.\n * `readMetadata` used to construct `{allowedDir}` inline, so `onProgress` and `signal` were\n * accepted by the caller, ignored by the reader, and documented as shared by every entry point -\n * three statements that only stayed consistent for as long as nobody checked.\n *\n * `offset`, `limit`, `maxRows` and `fields` are absent because they mean nothing here, not because\n * they were forgotten: a read that stops at the XML header has no rows to window and parses no\n * field's symbols to skip. They are ignored rather than refused, so that one options object can be\n * passed to `readMetadata` and to a data read without the caller having to strip it.\n *\n * @param {any} options The caller's options.\n * @return {Object} Options for the `QvdFileReader` constructor.\n */\nexport function metadataOptionsFrom(options) {\n return {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n signal: options.signal,\n };\n}\n\n/**\n * The row window out of a public `fromQvd`-style options object.\n *\n * @param {any} options The caller's options.\n * @return {{offset?: number, limit?: number|null, maxRows?: number|null}} The window, unvalidated\n * - `normaliseWindow` does that, once, inside the reader.\n */\nexport function windowFrom(options) {\n return {offset: options.offset, limit: options.limit, maxRows: options.maxRows};\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport {QvdSecurityError, QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Determines whether a resolved path is contained within a resolved base directory, using only\n * string comparison.\n *\n * This is the fallback for when the filesystem cannot answer the question - in practice, when\n * allowedDir does not exist. It cannot see through symlinks and has to guess at case\n * sensitivity, which is exactly why it is not the primary check.\n *\n * Uses path.relative() rather than a string prefix test, so that filesystem roots\n * ('/', 'C:\\', '\\\\server\\share\\') and base directories with a trailing separator are\n * handled correctly. A prefix test appends path.sep to the base, which produces '//'\n * for a root and therefore matches nothing.\n *\n * @param {string} resolvedBaseDir Absolute, resolved base directory.\n * @param {string} resolvedPath Absolute, resolved candidate path.\n * @return {boolean} True if the path is the base directory itself or lies beneath it.\n */\nfunction isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) {\n // Folding is applied on Windows only. It used to cover darwin as well, on the assumption that\n // macOS is always case-insensitive, but macOS supports case-sensitive APFS and HFS+ volumes on\n // which two names differing only in case are genuinely different directories - so folding there\n // let a sibling directory pass the check. The on-disk comparison below settles case correctly\n // by asking the filesystem, which is why this fallback no longer needs to guess for darwin.\n const isCaseInsensitiveFS = process.platform === 'win32';\n const base = isCaseInsensitiveFS ? resolvedBaseDir.toLowerCase() : resolvedBaseDir;\n const target = isCaseInsensitiveFS ? resolvedPath.toLowerCase() : resolvedPath;\n\n const relative = path.relative(base, target);\n\n // '' means the path IS the base directory. A relative path that starts with '..' escapes\n // the base, and an absolute result means the two are on different roots/drives.\n if (relative === '') {\n return true;\n }\n if (path.isAbsolute(relative)) {\n return false;\n }\n return relative !== '..' && !relative.startsWith(`..${path.sep}`);\n}\n\n/**\n * Resolves the deepest ancestor of a path that actually exists, following symlinks.\n *\n * A path being written to does not exist yet, and neither may some of its parent directories, so\n * realpath() on the full path would simply fail. Walking up to the first component that does\n * exist gives the deepest point the filesystem can vouch for; anything below it is a name that\n * will be created inside that directory.\n *\n * @param {string} target Absolute, lexically resolved path.\n * @return {string|null} Canonical path of the deepest existing ancestor, or null if it could not\n * be determined.\n */\nfunction resolveDeepestExisting(target) {\n let current = target;\n\n for (;;) {\n try {\n return fs.realpathSync(current);\n } catch (error) {\n const code = /** @type {{code?: string}} */ (error)?.code;\n\n // ENOENT: this component does not exist. ENOTDIR: an ancestor is a file, so nothing below\n // it can exist either. Both mean \"keep walking up\". Anything else (EACCES, ELOOP) means the\n // filesystem cannot answer, and the caller falls back to the lexical test - which is safe,\n // because an open() on the same path is about to fail for the same reason.\n if (code !== 'ENOENT' && code !== 'ENOTDIR') {\n return null;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n }\n}\n\n/**\n * Determines whether a path is contained within a base directory by asking the filesystem.\n *\n * Both sides are resolved through symlinks and then compared by identity - device and inode -\n * rather than by name, walking up from the target until the base is found or the root is reached.\n * That settles two questions a string comparison cannot:\n *\n * - Symlinks. A link inside allowedDir pointing outside it resolves to its target, so it is\n * rejected. A lexical check sees only the link's own name, still under allowedDir, and lets it\n * through - which meant arbitrary read via the reader and arbitrary overwrite via the writer.\n * - Case. On a case-insensitive volume 'Qvd' and 'qvd' are one directory and share an inode; on a\n * case-sensitive volume they are two directories with different inodes. Comparing identity gets\n * both right without inferring anything from process.platform, which is what the old code did\n * and got wrong on case-sensitive macOS volumes.\n *\n * This is a check on the path, so it is inherently subject to a race: a symlink swapped in\n * between this call and the subsequent open would defeat it. Closing that would require opening\n * with O_NOFOLLOW and verifying the descriptor, which is a larger change to the reader and\n * writer than this function can make on its own.\n *\n * @param {string} resolvedBaseDir Absolute, lexically resolved base directory.\n * @param {string} resolvedPath Absolute, lexically resolved candidate path.\n * @return {boolean|null} True or false when the filesystem could answer, null when it could not.\n */\nfunction isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {\n /** @type {import('fs').Stats} */\n let baseStat;\n\n try {\n // The base has to exist to be identified. If it does not, there is nothing on disk to compare\n // against and the lexical fallback is all that is left.\n baseStat = fs.statSync(fs.realpathSync(resolvedBaseDir));\n } catch {\n return null;\n }\n\n let current = resolveDeepestExisting(resolvedPath);\n if (current === null) {\n return null;\n }\n\n // realpathSync() returns a fully canonical path, so every ancestor of it is canonical too and\n // walking up with dirname() cannot step through a symlink.\n for (;;) {\n let stat;\n try {\n stat = fs.statSync(current);\n } catch {\n return null;\n }\n\n if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {\n return true;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return false;\n }\n current = parent;\n }\n}\n\n/**\n * Validates that a file path stays inside the allowed directory.\n *\n * Containment is decided by the filesystem wherever it can be: both paths are resolved through\n * symlinks and compared by device and inode. That covers symlink escapes and case sensitivity,\n * neither of which a string comparison can get right. When the base directory does not exist,\n * there is nothing to compare against and a lexical check is used instead.\n *\n * To permit access to an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on\n * Windows). There is deliberately no separate \"disable the check\" value: a null or empty\n * allowedDir falls back to the current working directory, so a caller that accidentally\n * passes one still gets the restriction rather than silently losing it.\n *\n * @param {string} filePath The path to validate.\n * @param {string|null} [allowedDir] Optional allowed directory path. Defaults to the current\n * working directory to prevent path traversal attacks.\n * @throws {QvdValidationError} If filePath is not a non-empty string, or allowedDir is not a\n * string, null or undefined.\n * @throws {QvdSecurityError} If path traversal is detected.\n * @return {string} The resolved absolute path. This is the lexically resolved path, not the\n * canonical one, so callers see the path they asked for.\n */\nexport function validatePath(filePath, allowedDir) {\n // Validate argument types up front, so callers get a typed error instead of a bare TypeError\n // from deep inside the function (e.g. 'filePath.includes is not a function').\n if (typeof filePath !== 'string' || filePath.length === 0) {\n throw new QvdValidationError('filePath must be a non-empty string', {\n provided: filePath,\n type: typeof filePath,\n });\n }\n\n if (allowedDir !== undefined && allowedDir !== null && typeof allowedDir !== 'string') {\n throw new QvdValidationError('allowedDir must be a string, null or undefined', {\n provided: allowedDir,\n type: typeof allowedDir,\n });\n }\n\n // Check for null bytes which can be used in path traversal attacks\n if (filePath.includes('\\0')) {\n throw new QvdSecurityError('Path traversal detected: Null byte in path', {\n path: filePath,\n reason: 'null_byte',\n });\n }\n\n const resolvedPath = path.resolve(filePath);\n\n // Default to the current working directory when no allowed directory is specified. This\n // prevents path traversal attacks by ensuring files can only be accessed within the CWD\n // or a more restrictive allowed directory.\n //\n // null and '' deliberately fall back to the CWD rather than meaning \"no restriction\":\n // callers routinely produce them from optional config or a JSON round trip, and silently\n // dropping the sandbox in that case would be a security hole. A caller that genuinely wants\n // an entire volume passes its root ('/' or 'C:\\\\'), which the containment test supports.\n const baseDir = allowedDir || process.cwd();\n const resolvedBaseDir = path.resolve(baseDir);\n\n const onDisk = isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath);\n const contained = onDisk === null ? isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) : onDisk;\n\n if (!contained) {\n throw new QvdSecurityError('Path traversal detected: Access denied', {\n path: filePath,\n resolvedPath,\n allowedDir: resolvedBaseDir,\n reason: 'outside_allowed_directory',\n // Says which check refused, so a rejection of a path that looks contained is traceable to\n // a symlink or a case difference rather than looking like a bug.\n check: onDisk === null ? 'lexical' : 'filesystem',\n });\n }\n\n return resolvedPath;\n}\n","// @ts-check\n\n/**\n * Largest `BitWidth` a field may declare.\n *\n * A stored index is an offset into the field's symbol table, and it is kept in an `Int32Array`,\n * so it has to fit in a positive 32-bit integer. 31 bits addresses 2,147,483,647 symbols in a\n * single field - orders of magnitude beyond anything the rest of the library will load, since\n * the symbol table for that many values would be terabytes and the memory guard refuses long\n * before. A file declaring more is refused rather than decoded: at 32 bits the top of the range\n * wraps to a negative index, and a negative index means NULL, so the failure would be silently\n * wrong values instead of an error. That is the shape of bug #113 was.\n */\nexport const MAX_BIT_WIDTH = 31;\n\n/**\n * Powers of two up to 2^39, the widest window a field can span: at most 7 bits of byte\n * misalignment plus `MAX_BIT_WIDTH`. Every value here is exactly representable as a double, and\n * so is every intermediate the decoder forms, which is why the arithmetic below can use `/` and\n * `%` on Numbers rather than 32-bit bitwise operators - those would overflow at 32 bits.\n */\nconst POW2 = Array.from({length: 41}, (_, exponent) => 2 ** exponent);\n\n/**\n * Where a field's bits sit inside a record.\n *\n * Both directions need this, and they must not derive it separately. Two copies of\n * `(shift + bitWidth + 7) >> 3` that drift apart write files this library cannot read, and\n * nothing throws - the decode simply starts a byte early and every field after the first\n * straddling one is misaligned. That is #113's failure shape pointed the other way, so the\n * derivation lives here and the encoder, the decoder and their tests all call it.\n *\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits; zero means it occupies no bits at all.\n * @return {{byteStart: number, shift: number, byteCount: number}} The field's byte window:\n * where it starts, how far into that byte it begins, and how many bytes it touches (0 when\n * the width is zero, otherwise 1 to 5).\n */\nexport function fieldGeometry(bitOffset, bitWidth) {\n const shift = bitOffset & 7;\n\n return {\n byteStart: bitOffset >>> 3,\n shift,\n byteCount: bitWidth === 0 ? 0 : (shift + bitWidth + 7) >>> 3,\n };\n}\n\n/**\n * Decodes one bit-packed field out of every record of an index table.\n *\n * ## The layout\n *\n * A record is `recordSize` bytes. Numbering its bits `p = 0, 1, 2, ...`, bit `p` is\n * `(byte[p >> 3] >> (p & 7)) & 1` - little-endian, least significant bit of each byte first. A\n * field occupies `bitWidth` consecutive bits starting at `bitOffset`, least significant bit\n * first, and `Bias` is then added to the value read.\n *\n * This is the same layout the previous implementation produced, by a much longer route: it\n * reversed the record's bytes, concatenated their binary spellings into a string of\n * `recordSize * 8` characters, split that into an array of one number per bit, reversed it, then\n * sliced the array per field and summed `bit * Math.pow(2, index)`. Several arrays the length of\n * the record in *bits*, built and discarded for every row, which is where roughly 98% of a full\n * read went.\n *\n * ## Why the arithmetic is not bitwise\n *\n * JavaScript's `<<`, `>>>` and `&` coerce to 32 bits, and a field can span up to 39 bits once\n * byte misalignment is counted. `Math.floor(acc / 2**shift) % 2**bitWidth` is exact for every\n * value this can form, because the widest accumulator is under 2^40 and doubles are exact to\n * 2^53.\n *\n * @param {Buffer|Uint8Array} buffer The index table, starting at the first record.\n * @param {number} recordSize Bytes per record.\n * @param {number} rowCount Number of records to decode.\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits. Zero means the field holds a single\n * distinct value and occupies no bits at all.\n * @param {number} bias Added to every decoded value. Qlik writes -2 for a field containing\n * NULLs, where stored index 0 means NULL and real symbols start at 2.\n * @param {Int32Array} out Destination, at least `rowCount` long.\n * @return {Int32Array} `out`.\n */\nexport function decodeIndexColumn(buffer, recordSize, rowCount, bitOffset, bitWidth, bias, out) {\n // A single-distinct-value column occupies zero bits, so there is nothing to read: every row\n // holds stored index 0, which is `bias` once the bias is applied.\n if (bitWidth === 0) {\n out.fill(bias, 0, rowCount);\n return out;\n }\n\n const {byteStart, shift, byteCount} = fieldGeometry(bitOffset, bitWidth);\n\n const divisor = POW2[shift];\n const modulus = POW2[bitWidth];\n\n // byteStart + byteCount is at most recordSize - validateFieldBitMetadata has already required\n // bitOffset + bitWidth <= recordSize * 8 - so every read below is inside the record, and the\n // caller has established that `rowCount` whole records are present.\n let base = byteStart;\n\n for (let row = 0; row < rowCount; row++, base += recordSize) {\n let acc = buffer[base];\n\n if (byteCount > 1) acc += buffer[base + 1] * 0x100;\n if (byteCount > 2) acc += buffer[base + 2] * 0x10000;\n if (byteCount > 3) acc += buffer[base + 3] * 0x1000000;\n if (byteCount > 4) acc += buffer[base + 4] * 0x100000000;\n\n out[row] = (Math.floor(acc / divisor) % modulus) + bias;\n }\n\n return out;\n}\n\n/**\n * Writes one bit-packed field into one record. The inverse of `decodeIndexColumn`.\n *\n * Same layout, written the other way: bit `p` of a record is `(byte[p >> 3] >> (p & 7)) & 1`,\n * so a value is shifted left by the field's `shift` and OR-ed across the bytes it touches. The\n * buffer must start zeroed and fields must not overlap, which the caller guarantees by\n * allocating it with `Buffer.alloc` and laying columns out by prefix sum of their widths.\n *\n * Multiplication rather than `<<` for the same reason the decoder divides rather than `>>>`: a\n * field can span 39 bits once misalignment is counted, and JavaScript's bitwise operators stop\n * at 32. Every intermediate here is under 2^40, well inside what a double represents exactly.\n *\n * It takes the geometry rather than a `bitOffset`, so the caller cannot derive the byte window\n * differently from the way `decodeIndexColumn` derives it - see `fieldGeometry`. A zero-width\n * field writes nothing, matching the decoder's zero-width branch, which reads nothing; the\n * first byte used to be written unconditionally, so a `byteCount` of 0 put the value into the\n * next column's bits.\n *\n * @param {Buffer|Uint8Array} buffer The index table being built.\n * @param {number} recordBase Index of the record's first byte.\n * @param {{byteStart: number, shift: number, byteCount: number}} geometry From `fieldGeometry`.\n * @param {number} value The stored index. Must fit in the field's width; the caller checks.\n */\nexport function writeBitField(buffer, recordBase, geometry, value) {\n const {byteStart, shift, byteCount} = geometry;\n\n if (byteCount === 0) {\n return;\n }\n\n const base = recordBase + byteStart;\n const shifted = value * POW2[shift];\n\n buffer[base] |= shifted % 0x100;\n\n if (byteCount > 1) buffer[base + 1] |= Math.floor(shifted / 0x100) % 0x100;\n if (byteCount > 2) buffer[base + 2] |= Math.floor(shifted / 0x10000) % 0x100;\n if (byteCount > 3) buffer[base + 3] |= Math.floor(shifted / 0x1000000) % 0x100;\n if (byteCount > 4) buffer[base + 4] |= Math.floor(shifted / 0x100000000) % 0x100;\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\nimport xml from 'xml2js';\nimport assert from 'assert';\nimport {QvdSymbol} from './QvdSymbol.js';\nimport {QvdValidationError} from './QvdErrors.js';\nimport {validatePath} from './util/validatePath.js';\nimport {fieldGeometry, writeBitField} from './util/bitUtils.js';\n\n/**\n * @typedef {import('./QvdDataFrame.js').QvdDataFrame} QvdDataFrame\n */\n\n/**\n * Persists a QVD file to disk.\n */\nexport class QvdFileWriter {\n /**\n * Constructs a new QVD file writer.\n *\n * @param {string} filePath The path to the QVD file to write.\n * @param {QvdDataFrame} df The data frame to write to the QVD file.\n * @param {Object} [options={}] Options for the writer.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function.\n */\n constructor(filePath, df, options = {}) {\n const {allowedDir, onProgress} = options;\n this._path = validatePath(filePath, allowedDir);\n this._df = df;\n this._onProgress = onProgress;\n this._header = null;\n this._symbolBuffer = null;\n /** @type {Array<Array<import('./QvdSymbol.js').QvdSymbol>>|null} */\n this._symbolTable = null;\n /** @type {Array<any>|null} */\n this._symbolTableMetadata = null;\n this._indexBuffer = null;\n /**\n * Stored index for each distinct value of each column, keyed by the raw value.\n *\n * Built while the symbol table is, because that pass already decides the order symbols are\n * written in and therefore what each index is. The alternative - re-deriving it here from\n * a QvdSymbol and a template-literal key per cell - meant converting every cell twice and\n * allocating 34 million strings on the taxi fixture to look up something already known.\n *\n * @type {Array<Map<any, number>>|null}\n */\n this._symbolIndexByValue = null;\n /** @type {Array<any>|null} */\n this._indexTableMetadata = null;\n /** Rows written, kept because the index table is no longer an array to count. @type {number} */\n this._recordCount = 0;\n this._recordByteSize = null;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * @param {string} stage The current stage of the operation.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n this._onProgress({\n stage,\n current,\n total,\n percent,\n });\n }\n }\n\n /**\n * Writes the data to the QVD file.\n */\n async _writeData() {\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolBuffer, 'The QVD file symbol table has not been parsed.');\n assert(this._indexBuffer, 'The QVD file index table has not been parsed.');\n\n this._emitProgress('write', 0, 1);\n\n // @ts-ignore - Buffer.concat type compatibility\n const headerBuffer = Buffer.concat([Buffer.from(this._header, 'utf-8'), Buffer.from([0])]);\n\n let fd;\n try {\n fd = await fs.promises.open(this._path, 'w');\n await fd.write(headerBuffer, 0, headerBuffer.length, 0);\n await fd.write(this._symbolBuffer, 0, this._symbolBuffer.length, headerBuffer.length);\n await fd.write(this._indexBuffer, 0, this._indexBuffer.length, headerBuffer.length + this._symbolBuffer.length);\n this._emitProgress('write', 1, 1);\n } finally {\n if (fd) {\n await fd.close();\n }\n }\n }\n\n /**\n * Builds the XML header of the QVD file.\n */\n _buildHeader() {\n this._emitProgress('header', 0, 1);\n const creationDate = new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '');\n /** @type {import('./QvdDataFrame.js').QvdMetadata|null} */\n const existingMetadata = this._df.metadata;\n\n // Use existing metadata if available, otherwise create default values\n const baseMetadata = existingMetadata\n ? {\n QvBuildNo: existingMetadata.QvBuildNo || 50667,\n CreatorDoc: existingMetadata.CreatorDoc || crypto.randomUUID(),\n CreateUtcTime: existingMetadata.CreateUtcTime || creationDate,\n SourceCreateUtcTime: existingMetadata.SourceCreateUtcTime || '',\n SourceFileUtcTime: existingMetadata.SourceFileUtcTime || '',\n SourceFileSize: existingMetadata.SourceFileSize || -1,\n StaleUtcTime: existingMetadata.StaleUtcTime || '',\n TableName: existingMetadata.TableName || path.basename(this._path, path.extname(this._path)),\n Compression: existingMetadata.Compression || '',\n Comment: existingMetadata.Comment || '',\n EncryptionInfo: existingMetadata.EncryptionInfo || '',\n TableTags: existingMetadata.TableTags || '',\n ProfilingData: existingMetadata.ProfilingData || '',\n Lineage: existingMetadata.Lineage || {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n }\n : {\n QvBuildNo: 50667,\n CreatorDoc: crypto.randomUUID(),\n CreateUtcTime: creationDate,\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: path.basename(this._path, path.extname(this._path)),\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n };\n\n // Get existing field metadata if available\n /** @type {any[]} */\n let existingFields = [];\n if (existingMetadata && existingMetadata.Fields && existingMetadata.Fields.QvdFieldHeader) {\n existingFields = Array.isArray(existingMetadata.Fields.QvdFieldHeader)\n ? existingMetadata.Fields.QvdFieldHeader\n : [existingMetadata.Fields.QvdFieldHeader];\n }\n\n const xmlObject = {\n QvdTableHeader: {\n ...baseMetadata,\n Fields: {\n QvdFieldHeader: this._df.columns.map((/** @type {any} */ column, /** @type {number} */ index) => {\n // Find existing field metadata for this column\n const existingField = existingFields.find((/** @type {any} */ f) => f.FieldName === column);\n\n return {\n FieldName: column,\n BitOffset: this._indexTableMetadata?.[index][0],\n BitWidth: this._indexTableMetadata?.[index][1],\n Bias: this._indexTableMetadata?.[index][2],\n NoOfSymbols: this._symbolTable?.[index].length,\n Offset: this._symbolTableMetadata?.[index][0],\n Length: this._symbolTableMetadata?.[index][1],\n Comment: existingField?.Comment || '',\n NumberFormat: existingField?.NumberFormat || {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: existingField?.Tags || {},\n };\n }),\n },\n NoOfRecords: this._recordCount,\n RecordByteSize: this._recordByteSize,\n Offset:\n this._symbolTableMetadata && this._symbolTableMetadata.length > 0\n ? this._symbolTableMetadata[this._symbolTableMetadata.length - 1][0] +\n this._symbolTableMetadata[this._symbolTableMetadata.length - 1][1]\n : 0,\n Length: this._indexBuffer?.length,\n },\n };\n\n const builder = new xml.Builder({\n renderOpts: {\n pretty: true,\n newline: '\\r\\n',\n indent: ' ',\n },\n });\n this._header = builder.buildObject(xmlObject) + '\\r\\n';\n this._emitProgress('header', 1, 1);\n }\n\n /**\n * Builds the symbol table of the QVD file.\n *\n * PERFORMANCE OPTIMIZATION: This method uses a single-pass algorithm to build\n * symbol tables for all columns simultaneously. This reduces time complexity from\n * O(n×m×s) to O(n×m) where n=rows, m=columns, s=symbols per column.\n *\n * Algorithm:\n * 1. Initialize a Set for each column to collect unique values\n * 2. Single pass through all data rows, adding values to corresponding Sets\n * 3. Convert Sets to arrays and create QvdSymbol instances\n * 4. Serialize symbols to binary format and update metadata\n *\n * This approach provides:\n * - 80-90% performance improvement for large datasets (100K+ rows)\n * - Better cache locality (process all columns in one data traversal)\n * - Lower memory pressure (no intermediate arrays per column)\n *\n * @private\n */\n _buildSymbolTable() {\n this._symbolTable = [];\n this._symbolTableMetadata = [];\n this._symbolIndexByValue = [];\n\n // A table with no fields is not a QVD. Writing one produced a 741-byte file with an empty\n // `<Fields/>` element that this same library refuses to load, which is the worst of both:\n // the write reports success and the failure surfaces later, somewhere else.\n if (this._df.columns.length === 0) {\n throw new QvdValidationError('A QVD file must have at least one field', {\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numColumns = columns.length;\n const numRows = data.length;\n\n this._emitProgress('symbol-table', 0, numColumns);\n\n // One Map per column, from raw value to the stored index that value will get, built in the\n // single pass over the data that also discovers the distinct values.\n //\n // This used to be a Set per column, then `Array.from` on it, then a Map built from the\n // array - three structures each holding a reference to every distinct value, where one is\n // needed. On a column whose values are all distinct that was roughly 30MB of duplication\n // per million rows, and it bought nothing: a Map preserves insertion order exactly as a Set\n // does, so the indices it hands out are the same ones the array walk produced.\n /** @type {Array<Map<any, number>>} */\n const indexByValue = columns.map(() => new Map());\n /** @type {Array<boolean>} */\n const containsNull = columns.map(() => false);\n\n // A counted loop, not `data.forEach`. forEach skips array holes and the index table's loop\n // does not, so a sparse `data` array made the two passes disagree about how many rows\n // exist: a five-element array with one row set wrote a five-row file in which four rows\n // carried a real value copied from the fifth, and a hole between two rows threw a bare\n // TypeError. A hole reads as `undefined`, which is what this writer already treats as NULL\n // everywhere else, so both passes now see the same rows and a hole becomes a NULL row.\n for (let row = 0; row < numRows; row++) {\n const values = data[row];\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n containsNull[column] = true;\n continue;\n }\n\n const map = indexByValue[column];\n\n if (!map.has(value)) {\n map.set(value, map.size);\n }\n }\n }\n\n // Serialised per column and concatenated once. Concatenating onto an accumulating buffer\n // instead re-copies every byte written so far on each column - O(bytes x columns), which\n // measured 26ms against 14ms on a 67MB symbol table and gets worse linearly with the column\n // count, while transiently holding two copies of everything written so far.\n /** @type {Array<Buffer>} */\n const columnBuffers = [];\n let symbolsOffset = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const symbols = Array.from(indexByValue[column].keys(), (value) => QvdFileWriter._convertRawToSymbol(value));\n\n // @ts-ignore - Symbol byte representation\n const columnBuffer = Buffer.concat(symbols.map((symbol) => symbol.toByteRepresentation()));\n\n columnBuffers.push(columnBuffer);\n this._symbolTableMetadata?.push([symbolsOffset, columnBuffer.length, containsNull[column]]);\n // @ts-ignore - Symbol array type compatibility\n this._symbolTable?.push(symbols);\n this._symbolIndexByValue.push(indexByValue[column]);\n\n symbolsOffset += columnBuffer.length;\n\n this._emitProgress('symbol-table', column + 1, numColumns);\n }\n\n // @ts-ignore - Buffer.concat type compatibility\n this._symbolBuffer = Buffer.concat(columnBuffers);\n }\n\n /**\n * Builds the bit-packed index table of the QVD file.\n *\n * A record is `recordByteSize` bytes. Each column occupies `bitWidth` consecutive bits at\n * `bitOffset`, least significant bit first, where bit `p` of a record is\n * `(byte[p >> 3] >> (p & 7)) & 1`. `Bias` is -2 for a column containing NULLs: stored index 0\n * means NULL, and real symbols start at 2. This is exactly what the reader's\n * `decodeIndexColumn` undoes, and `writeBitField` is its inverse.\n *\n * The previous implementation went the long way round. Per cell it converted the raw value to\n * a QvdSymbol - a second time, the symbol table pass having already done it - to build a\n * template-literal lookup key, then turned the resulting index into a string of bits via\n * `toString(2).split('').map().reverse().concat().slice().reverse()`. Per row it kept an array\n * of those strings, padded each with `padStart`, reversed and joined them, split the result\n * with `/.{1,8}/g`, and allocated a Buffer; then `Buffer.concat` over one Buffer per row. On\n * the 1.7M-row taxi fixture that is 34 million symbols, 34 million key strings, 34 million bit\n * strings and 1.7 million Buffers, and it accounted for 98% of a write.\n *\n * Now: the widths are derived from the symbol counts, the offsets by prefix sum, one Buffer is\n * allocated for the whole table, and each value is OR-ed into place as an integer.\n *\n * @private\n */\n _buildIndexTable() {\n assert(this._symbolTable, 'The QVD file symbol table has not been built.');\n assert(this._symbolTableMetadata, 'The QVD file symbol table metadata has not been built.');\n assert(this._symbolIndexByValue, 'The QVD file symbol index has not been built.');\n\n this._indexTableMetadata = [];\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numRows = data.length;\n const numColumns = columns.length;\n\n this._recordCount = numRows;\n this._emitProgress('index-table', 0, numRows);\n\n // Layout, one entry per column, hoisted out of the row loop so the inner loop does\n // arithmetic into a buffer and nothing else.\n /** @type {Array<{geometry: {byteStart: number, shift: number, byteCount: number}, nullShift: number}>} */\n const layout = [];\n\n let totalBits = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const fieldContainsNull = this._symbolTableMetadata[column][2];\n const symbolCount = this._symbolTable[column].length;\n const nullShift = fieldContainsNull ? 2 : 0;\n\n // The largest stored index is (symbolCount - 1), shifted by 2 when the column contains\n // NULLs (index 0 denotes NULL and indices start at 2, which is what Bias=-2 encodes).\n //\n // Deriving the width this way is O(1) per column instead of O(rows), and it avoids\n // Math.max(...oneArgumentPerRow), which overflows the call stack somewhere around\n // 120k rows and made toQvd() unusable for realistic table sizes.\n const maxStoredIndex = symbolCount === 0 ? 0 : symbolCount - 1 + nullShift;\n\n // A single distinct value needs no bits at all, which matches what Qlik emits.\n const bitWidth = maxStoredIndex === 0 ? 0 : 32 - Math.clz32(maxStoredIndex);\n\n // Every index the row loop can write, checked once per column rather than once per cell.\n //\n // The row loop writes either 0, for NULL, or a value from this map, so validating the\n // map validates every write - 28,512 checks on the taxi fixture instead of 34 million,\n // and it covers the zero-width columns the per-cell check used to skip past. The bound is\n // the symbol count, not the field's capacity: a per-cell `storedIndex >= 2 ** bitWidth`\n // admitted indices in the gap between the two, which address no symbol and read back as\n // NULL with nothing thrown.\n for (const index of this._symbolIndexByValue[column].values()) {\n if (index + nullShift > maxStoredIndex) {\n throw new QvdValidationError('The symbol table and the index table are out of sync', {\n field: columns[column],\n storedIndex: index + nullShift,\n maxStoredIndex,\n symbolCount,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n }\n\n layout.push({geometry: fieldGeometry(totalBits, bitWidth), nullShift});\n\n this._indexTableMetadata.push([totalBits, bitWidth, fieldContainsNull ? -2 : 0]);\n\n totalBits += bitWidth;\n }\n\n // Every column may have a bit width of 0 - each holds a single distinct value, or only\n // NULLs - leaving no bits at all. Qlik still uses a one-byte record in that situation, and\n // a zero-byte record would be rejected on read.\n const recordByteSize = Math.max(1, Math.ceil(totalBits / 8));\n\n this._recordByteSize = recordByteSize;\n this._indexBuffer = Buffer.alloc(numRows * recordByteSize);\n\n const progressInterval = Math.max(1, Math.floor(numRows / 100)); // Report progress every 1%\n\n for (let row = 0, recordBase = 0; row < numRows; row++, recordBase += recordByteSize) {\n const values = data[row];\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n // NULL is stored index 0, which the bias turns back into a negative index on read.\n // Nothing to write: the buffer is already zeroed.\n continue;\n }\n\n const index = this._symbolIndexByValue[column].get(value);\n\n // A value the symbol table never saw. Unreachable while both passes walk the same rows,\n // which is the point of them sharing a counted loop - but the old code absorbed this\n // with `?? 0`, writing the first real symbol in place of the missing value, so a whole\n // column could read back as some other value with nothing thrown.\n if (index === undefined) {\n throw new QvdValidationError('A value is missing from the symbol table', {\n field: columns[column],\n row,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n\n writeBitField(this._indexBuffer, recordBase, layout[column].geometry, index + layout[column].nullShift);\n }\n\n // Report progress periodically\n if ((row + 1) % progressInterval === 0 || row + 1 === numRows) {\n this._emitProgress('index-table', row + 1, numRows);\n }\n }\n\n // The maps are dead once the table is packed, and the writer stays alive through the header\n // build and the file write - the point at which the symbol buffer and the index buffer are\n // both resident.\n this._symbolIndexByValue = null;\n }\n\n /**\n * Converts a raw value/literal to a QVD symbol.\n *\n * @param {any} raw The raw value/literal to convert.\n * @return {QvdSymbol|null} The converted QVD symbol.\n */\n static _convertRawToSymbol(raw) {\n if (raw === null || raw === undefined) {\n return null;\n }\n\n const INT32_MIN = -2147483648;\n const INT32_MAX = 2147483647;\n\n const isInteger = typeof raw === 'number' && Number.isInteger(raw);\n const isFloat = typeof raw === 'number' && !Number.isInteger(raw);\n const isWithinInt32Range = typeof raw === 'number' && raw >= INT32_MIN && raw <= INT32_MAX;\n\n if (isInteger && isWithinInt32Range) {\n return QvdSymbol.fromDualIntValue(raw, raw.toString());\n } else if (isFloat || (isInteger && !isWithinInt32Range)) {\n return QvdSymbol.fromDualDoubleValue(raw, raw.toString());\n } else {\n return QvdSymbol.fromStringValue(raw);\n }\n }\n\n /**\n * Persists the data frame to a QVD file.\n */\n async save() {\n this._buildSymbolTable();\n this._buildIndexTable();\n this._buildHeader();\n await this._writeData();\n }\n}\n","// @ts-check\n\nimport os from 'os';\nimport v8 from 'v8';\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Gets the configured V8 heap size limit for the current Node.js process.\n * This respects the --max-old-space-size flag if set.\n *\n * @returns {number} Heap size limit in bytes\n */\nexport function getHeapLimit() {\n return v8.getHeapStatistics().heap_size_limit;\n}\n\n/**\n * Whether v8.getHeapStatistics().heap_size_limit means what it says on this runtime.\n *\n * Bun reports its *current* heap there rather than a ceiling - 229MB on a machine with 128GB of\n * RAM - so treating it as a limit rejects almost everything. It cannot be detected structurally\n * either: Bun spoofs both process.versions.v8 and process.versions.node, so the runtime's own\n * key is the only reliable signal.\n *\n * @return {boolean} True when the heap limit is a real limit.\n */\nfunction heapLimitIsMeaningful() {\n return !process.versions.bun && !process.versions.deno;\n}\n\n/**\n * Works out how much memory this process may actually use, and which limit decided it.\n *\n * Only two things can bind, and the smaller wins:\n *\n * - The V8 heap ceiling, which is what an allocation actually fails against, fatally and\n * uncatchably. V8 sizes it from physical memory by default, so it already scales down on a\n * small machine.\n * - A container memory limit, from process.constrainedMemory(). This is the case os.freemem()\n * gets dangerously wrong: inside a cgroup it reports the *host's* free memory, so a 2GB\n * container on a large host sails past the check and is then killed by the OOM killer with\n * exit 137 and no JavaScript error to catch.\n *\n * What the OS reports as free or available is deliberately *not* one of them. It is recorded for\n * diagnostics and ignored for the decision, because it does not describe a wall the process can\n * hit - a machine with virtual memory gets slower, not fatal - and because the number itself is\n * not trustworthy. os.freemem() counts only free and speculative pages, excluding the inactive\n * and file-cache pages the OS reclaims on demand. process.availableMemory() is meant to fix that\n * and does on Linux, but on macOS it depends on the libuv version underneath: Node 24 reported\n * 63GB on a 128GB machine here while Node 22 on a macOS CI runner reported 74MB, which refused a\n * 45MB load on a machine that had ample room for it. Letting either bind is what made the same\n * file load or fail from one minute, or one Node version, to the next.\n *\n * @return {{bytes: number, limitedBy: string, candidates: Array<{source: string, bytes: number}>,\n * observed: Array<{source: string, bytes: number}>}} The budget, the name of the limit that\n * bound it, what was allowed to bind, and what was recorded but not used.\n */\nexport function getMemoryBudget() {\n /** @type {Array<{source: string, bytes: number}>} */\n const candidates = [];\n\n if (heapLimitIsMeaningful()) {\n candidates.push({source: 'V8 heap limit', bytes: usableOldSpaceLimit()});\n }\n\n // Node returns 0 when the process is not constrained. Bun returns os.totalmem() instead, which\n // is not a constraint either, so anything at or above total memory is discarded rather than\n // treated as a container limit.\n const constrained = typeof process.constrainedMemory === 'function' ? process.constrainedMemory() : 0;\n if (constrained > 0 && constrained < os.totalmem()) {\n candidates.push({source: 'container memory limit', bytes: constrained});\n }\n\n // Bun outside a container has neither a usable heap limit nor a container limit, so without\n // this there would be no ceiling at all. Total memory is at least a real upper bound.\n if (candidates.length === 0) {\n candidates.push({source: 'total system memory', bytes: os.totalmem()});\n }\n\n /** @type {Array<{source: string, bytes: number}>} */\n const observed = [{source: 'free memory (os.freemem)', bytes: os.freemem()}];\n if (typeof process.availableMemory === 'function') {\n observed.push({source: 'available memory', bytes: process.availableMemory()});\n }\n\n const binding = candidates.reduce((lowest, candidate) => (candidate.bytes < lowest.bytes ? candidate : lowest));\n\n return {bytes: binding.bytes, limitedBy: binding.source, candidates, observed};\n}\n\n/**\n * What `heap_size_limit` overstates the usable old-space limit by, in bytes.\n *\n * `v8.getHeapStatistics().heap_size_limit` counts new space, code space and the trusted spaces\n * as well as old space, and it is old space that a row-materialising load exhausts. Measured on\n * this platform the gap is a flat 192MB at every configured size - `--max-old-space-size=96`\n * reports 288, 512 reports 704, 2048 reports 2240 - so it is an absolute offset, not a\n * proportion, and a safety factor cannot express it. At a 4GB heap it is under 5% and a factor\n * absorbs it; at a heap configured down to a couple of hundred megabytes it is most of the\n * budget, which is where an under-sized estimate turned into a crash.\n *\n * It used to be absorbed into the per-row constants instead, which made those constants\n * describe two unrelated things at once and left them four to six times larger than the memory\n * they were supposed to model. Subtracting it here lets the row model be a row model.\n *\n * V8 exposes no per-space limit - `getHeapSpaceStatistics()` reports current sizes, not\n * ceilings - so this is an observed constant rather than a derived one. If it is wrong on some\n * platform it is wrong in the safe direction on a large heap, and the safety factor still\n * applies underneath.\n */\nconst HEAP_LIMIT_OVERSTATEMENT_BYTES = 192 * 1024 * 1024;\n\n/**\n * Smallest budget worth reporting, in bytes.\n *\n * This is a damage limiter for a platform where the 192MB offset does not hold, not a\n * description of a real ceiling. Subtracting an offset that does not apply would leave a budget\n * near zero and refuse everything, so the floor catches that.\n *\n * It has to leave room for `BASE_BYTES` plus a small load *after* the safety factor, or it\n * achieves the opposite of its purpose. An earlier value of 16MB was exactly `BASE_BYTES`, so at\n * the floor the estimate always exceeded the budget and even `misc/small.qvd` - 606 rows, 29KB -\n * was refused on a runtime where it demonstrably loads. 64MB clears `BASE_BYTES` four times\n * over.\n *\n * It over-claims only where the true old-space limit is under 64MB, which is not a configuration\n * this library can serve: the fixed cost of reading any file at all is 15MB of that.\n */\nconst MINIMUM_BUDGET_BYTES = 64 * 1024 * 1024;\n\n/**\n * The heap limit, less the spaces a row load cannot use.\n *\n * A plain subtraction, because the overstatement is a flat offset at every configured size:\n * `--max-old-space-size=47` reports 239, 96 reports 288, 4096 reports 4288. An earlier version\n * of this only subtracted when the reported limit exceeded twice the offset and otherwise\n * returned half of it, which was meant to avoid a non-positive result. It instead produced the\n * wrong answer across the whole range the correction exists for: at a 47MB heap it returned\n * 119MB, so the guard admitted a load that needed 63MB and the process aborted - the exact\n * failure this function is here to prevent, reintroduced by the fallback rather than by the\n * rule.\n *\n * @return {number} Usable bytes.\n */\nfunction usableOldSpaceLimit() {\n const usable = getHeapLimit() - HEAP_LIMIT_OVERSTATEMENT_BYTES;\n\n return usable > MINIMUM_BUDGET_BYTES ? usable : MINIMUM_BUDGET_BYTES;\n}\n\n/**\n * Estimates the memory usage for loading a QVD file with given parameters.\n * Takes into account Phase 2.5 optimization which skips parsing unused symbols.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Rows the read covers (null = all rows). Decides how much of the\n * symbol table is parsed.\n * @param {number} totalRows Total number of rows in the file\n * @param {number} [columnCount] Columns per row.\n * @param {boolean} [materialisesRows] Whether rows are built at all.\n * @param {number|null} [rowsLive] Rows held at one instant, when that is fewer than `maxRows`.\n * Null means they are the same. Note that this is what the *caller* holds, not its chunk size:\n * `iterateRows` passes two chunks, because `for await` keeps the yielded frame reachable while\n * the generator builds the next one.\n * @returns {number} Estimated memory usage in bytes\n */\n/**\n * What a row-materialising load costs, in bytes.\n *\n * `BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columns)`.\n *\n * Recalibrated 2026-09-11, after the bitwise decode (#134) stopped the reader allocating an\n * array per row and several per cell. The method is the one the original calibration used:\n * generate N rows x C columns where every value is `(i + j) % 100`, so the symbol table stays\n * negligible and only row geometry moves, then binary-search the smallest\n * `--max-old-space-size` at which the load completes.\n *\n * shape cells was (pre-#134) now model\n * 400,000 x 10 4M 118 MB 63 77\n * 800,000 x 5 4M 237 MB 87 106\n * 200,000 x 40 8M 142 MB 79 62\n * 400,000 x 40 16M 307 MB 151 109\n * 800,000 x 20 16M 484 MB 175 202\n * 1,600,000 x 10 16M 520 MB 215 259\n *\n * and against two real files, which the original calibration did not cover:\n *\n * lego/inventory_parts 580,251 x 5 63 MB 81\n * chicago_taxi_rides 2016_01 1,705,805 x 20 367 MB 412\n *\n * The reader needs roughly 2.4x less heap than it did, which is why the old constants - 360 and\n * 34 - over-estimated a taxi read by 4.8x and refused loads that fit comfortably.\n *\n * Two of the model's figures sit *below* the measurement (200,000 x 40 and 400,000 x 40). That\n * is not an under-estimate of the rows: those two shapes are dominated by the fixed cost of\n * reading a file at all, which `BASE_BYTES` covers and which the per-row terms should not be\n * inflated to absorb. Every shape's total prediction is above its measured minimum.\n *\n * The constants are what the geometry implies rather than fitted numbers: a row is a JSArray\n * with a separate backing store, so it costs two object headers plus slack, and a cell is one\n * pointer. Fitting the eight measurements above gives 55-64 and 7.1-7.3; 72 and 8 clear every\n * one of them by 13-26%, which is the margin. Under-estimating means an uncatchable abort,\n * over-estimating means a catchable refusal, so the margin is deliberately one-sided.\n *\n * `BASE_BYTES` is what a load costs before any rows exist - the interpreter, the parsed header,\n * the decoded index columns. Measured as the floor of the binary search: a columnar read of any\n * of these files, which builds no rows at all, completes at 15MB.\n */\nconst BASE_BYTES = 16 * 1024 * 1024;\nconst ROW_BASE_BYTES = 72;\nconst PER_CELL_BYTES = 8;\n\n/**\n * Bytes a read allocates *outside* the V8 heap, in bytes.\n *\n * The decoder builds one `Int32Array` of stored indices per field, and a TypedArray's backing\n * store is external memory: it does not consume old space, so `--max-old-space-size` does not\n * bound it and the V8 heap budget must not be charged for it. A columnar read of the 38MB taxi\n * fixture completes in a 15MB heap for exactly this reason.\n *\n * A cgroup counts it, though, and exceeding a container limit is a SIGKILL - uncatchable, and\n * strictly worse than the heap abort this module exists to prevent. So it is estimated, and\n * checked against the container budget rather than the heap one.\n *\n * Both paths allocate it. A row read builds the codes and then the rows from them, so during\n * the load both are live; a columnar read keeps only the codes. The file buffer is external\n * too, but its size is not known here, and the codes dominate on the shapes that get close to\n * a limit.\n *\n * @param {number} rows Rows that will be decoded.\n * @param {number} columnCount Columns per row.\n * @return {number} Estimated external bytes.\n */\nexport function estimateExternalMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0 || !rows || rows <= 0) {\n return 0;\n }\n\n return rows * columnCount * Int32Array.BYTES_PER_ELEMENT;\n}\n\n/**\n * Estimates the heap a row-materialising load will need, in bytes.\n *\n * @param {number} rows Rows that will be materialised.\n * @param {number} columnCount Columns per row. Zero disables the term, for callers that do not\n * know the geometry yet.\n * @return {number} Estimated bytes.\n */\nfunction estimateRowMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0) {\n return 0;\n }\n return BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columnCount);\n}\n\nexport function estimateMemoryUsage(\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount = 0,\n materialisesRows = true,\n rowsLive = null,\n) {\n // Memory overhead multipliers based on empirical testing\n const FULL_PARSE_OVERHEAD = 6.0; // Baseline: JavaScript objects have 6x overhead\n const MINIMAL_OVERHEAD = 0.01; // Skipped symbols: minimal null placeholder overhead\n\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n\n // Two different row counts, because two different things are being sized.\n //\n // `maxRows` is how many rows the read *covers*, and it is what decides how much of the symbol\n // table gets parsed - chunked iteration parses the symbol table once for the whole window, not\n // once per chunk. `rowsLive` is how many rows are materialised at the same instant, which is\n // what the heap actually has to hold: for a plain read they are the same number, and for\n // `iterate({chunkSize})` the second is *two* chunks of the first - `for await` keeps the\n // yielded frame reachable while the generator builds the next one, so two are alive at the\n // peak. Measured, because charging one chunk admitted a read that then aborted the process;\n // the caller computes the figure and passes it, this function only uses it.\n //\n // Conflating them is the failure this module has made before in the other direction - charging\n // a columnar read for rows it never builds. Charging a 20-million-row iteration for all 20\n // million rows when only `chunkSize` of them exist at once is the same mistake, and it would\n // refuse the one call shape that exists to make such a file readable at all.\n const liveRows = rowsLive === null ? rowsToLoad : Math.min(rowsLive, rowsToLoad);\n\n // The rows themselves. This term used to be missing entirely, which is what made the guard\n // useless for the commonest Qlik shape: many rows over low-cardinality fields. A 150MB file\n // with a 0.43MB symbol table was estimated at 2.6MB and then killed a default heap.\n //\n // A columnar read materialises none of them, and what it does allocate - one Int32Array of\n // codes per field - is a TypedArray backing store, which lives outside the V8 heap this\n // budget describes. That is not a modelling nicety: binary-searching the smallest\n // --max-old-space-size at which a columnar read completes gives 15MB for every file tried,\n // from a 4MB fixture to the 38MB taxi one, because almost nothing it allocates is on the\n // heap. Charging it the row cost refused columnar reads that need a fortieth of the budget.\n const rowMemory = materialisesRows ? estimateRowMemory(liveRows, columnCount) : BASE_BYTES;\n\n if (maxRows === null || maxRows >= totalRows) {\n // Loading all rows - need all symbols, no filtering benefit\n return symbolTableSize * FULL_PARSE_OVERHEAD + rowMemory;\n }\n\n // Estimate what percentage of symbols we'll need\n // Symbol usage grows slower than linear (diminishing returns as you add rows)\n // Use square root scaling as empirical approximation\n const rowPercentage = maxRows / totalRows;\n const symbolPercentage = Math.sqrt(rowPercentage);\n\n // Calculate memory for kept symbols (full overhead) + skipped symbols (minimal overhead)\n const keptSymbolsMemory = symbolTableSize * symbolPercentage * FULL_PARSE_OVERHEAD;\n const skippedSymbolsMemory = symbolTableSize * (1 - symbolPercentage) * MINIMAL_OVERHEAD;\n\n return keptSymbolsMemory + skippedSymbolsMemory + rowMemory;\n}\n\n/**\n * Finds the largest row count whose estimate fits inside a budget.\n *\n * The estimate is monotonic in rows but not invertible in closed form - the symbol term scales\n * with sqrt(rows/totalRows) while the row term scales linearly - so this bisects instead, and\n * the answer is therefore a value the caller can actually use. The previous implementation\n * inverted the square-root term alone and suggested row counts that the same check rejected on\n * the next call.\n *\n * When the limit that refused the read bounds the whole process rather than the V8 heap, the\n * external term has to be counted here too. Without it the suggestion is bisected against a\n * different quantity from the one the refusal used - and for a columnar read, whose heap estimate\n * barely moves with rows, the first test succeeds and it hands back the exact row count it just\n * refused. Recommending the input that produced the error is worse than recommending nothing.\n *\n * @param {number} budget Bytes available.\n * @param {number} symbolTableSize Size of the symbol table in bytes.\n * @param {number} totalRows Rows the file declares.\n * @param {number} columnCount Columns per row.\n * @param {boolean} [materialisesRows=true] Whether rows are built at all.\n * @param {boolean} [includeExternal=false] Count TypedArray backing stores, for a limit that\n * bounds the process rather than old space.\n * @return {number} A row count whose estimate fits the budget, or 0 when none does.\n */\nexport function recommendedRowsFor(\n budget,\n symbolTableSize,\n totalRows,\n columnCount,\n materialisesRows = true,\n includeExternal = false,\n) {\n const costOf = (/** @type {number} */ rows) =>\n estimateMemoryUsage(symbolTableSize, rows, totalRows, columnCount, materialisesRows) +\n (includeExternal ? estimateExternalMemory(Math.min(rows, totalRows), columnCount) : 0);\n\n if (costOf(totalRows) <= budget) {\n return totalRows;\n }\n\n // The bisection below treats `low` as a value known to fit, so that has to be true of its\n // starting point. It is not automatic: the estimate charges 1% of the symbol table even when\n // no rows are requested, so a symbol table two orders of magnitude larger than the budget\n // leaves nothing that fits. Clamping the answer up to 1 in that case produced a suggestion\n // the caller could not use - `maxRows: 1` threw the same error it had just been offered as\n // the fix for.\n if (costOf(0) > budget) {\n return 0;\n }\n\n let low = 0;\n let high = totalRows;\n while (high - low > 1) {\n const mid = Math.floor((low + high) / 2);\n if (costOf(mid) <= budget) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Finds the largest chunk size whose estimate fits inside a budget.\n *\n * The sibling of `recommendedRowsFor`, for the one caller whose knob is not the window. Chunked\n * iteration parses the symbol table once for the whole window however small the chunks are, so\n * the window is held fixed here and only the live-row term moves - bisecting the window instead\n * would recommend a number that does not correspond to anything the caller can set.\n *\n * The answer is in the caller's units, which is why `liveRowsPerChunk` has to be given rather\n * than assumed to be one: the iterator holds two chunks at a time, so bisecting live rows and\n * calling the result a chunk size would recommend a chunk twice as large as fits - and the caller\n * would be refused again on the very next call, which is the loop this function exists to avoid.\n *\n * @param {number} budget Bytes available.\n * @param {number} symbolTableSize Size of the symbol table in bytes.\n * @param {number|null} windowRows Rows the iteration covers, which fixes the symbol term.\n * @param {number} totalRows Rows the file declares.\n * @param {number} columnCount Columns per row.\n * @param {number} [liveRowsPerChunk=1] Rows alive per row of chunk size.\n * @param {boolean} [includeExternal=false] Count TypedArray backing stores, for a limit that\n * bounds the process rather than old space - see `recommendedRowsFor`.\n * @return {number} A chunk size whose estimate fits the budget, or 0 when none does.\n */\nexport function recommendedChunkFor(\n budget,\n symbolTableSize,\n windowRows,\n totalRows,\n columnCount,\n liveRowsPerChunk = 1,\n includeExternal = false,\n) {\n const covered = windowRows === null || windowRows >= totalRows ? totalRows : windowRows;\n\n const fits = (/** @type {number} */ chunk) => {\n const live = Math.min(chunk * liveRowsPerChunk, covered);\n const cost =\n estimateMemoryUsage(symbolTableSize, windowRows, totalRows, columnCount, true, chunk * liveRowsPerChunk) +\n (includeExternal ? estimateExternalMemory(live, columnCount) : 0);\n\n return cost <= budget;\n };\n\n if (fits(covered)) {\n return covered;\n }\n\n // A chunk of one row is the smallest thing a caller can ask for. If even that does not fit,\n // the symbol table alone has exhausted the budget and no chunk size helps - say so rather than\n // returning a number the very next call rejects.\n if (!fits(1)) {\n return 0;\n }\n\n let low = 1;\n let high = covered;\n while (high - low > 1) {\n const mid = Math.floor((low + high) / 2);\n if (fits(mid)) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Validates that there is sufficient memory available to load a QVD file safely.\n * Considers both available system RAM and the configured V8 heap limit.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} [safetyFactor=0.8] Fraction of the memory budget to use (0.0-1.0). Zero\n * disables the check entirely.\n *\n * The default was 0.3 while the estimate counted only the symbol table - a proxy that\n * understated real cost by around a hundredfold for the commonest Qlik shape, so the factor was\n * quietly compensating for it. Now that the estimate models the rows too, 0.3 would double-count\n * that margin and refuse loads with four times the headroom they need. The estimate sits about\n * 1.2-1.6x above the measured requirement, so 0.8 still leaves V8 room to collect.\n * @param {number} [columnCount=0] Columns per row, so the estimate can account for the row\n * arrays. Zero omits that term, which is what the old symbol-table-only estimate did.\n * @param {boolean} [materialisesRows=true] Whether this read builds row arrays at all.\n * @param {{rows: number, perChunk: number}|null} [live=null] For a read that holds fewer rows at\n * once than it covers: `rows` is how many are alive at the peak, and `perChunk` how many of\n * those one row of the caller's chunk size accounts for, so a refusal can name a chunk size.\n * Null means the read holds everything it covers, which is every read but chunked iteration.\n * @throws {QvdValidationError} If insufficient memory is available\n */\nexport function validateMemoryAvailability(\n symbolTableSize,\n maxRows,\n totalRows,\n filePath,\n safetyFactor = 0.8,\n columnCount = 0,\n materialisesRows = true,\n live = null,\n) {\n if (typeof safetyFactor !== 'number' || safetyFactor < 0 || safetyFactor > 1) {\n throw new QvdValidationError('safetyFactor must be a number between 0.0 and 1.0', {safetyFactor});\n }\n\n // Zero disables the check. It used to mean a budget of zero bytes, which refused every file\n // however small - not something any caller can have wanted - so the only reading that makes it\n // useful is \"I will manage memory myself\". This is the documented escape hatch for runtimes\n // whose limits cannot be measured, and for callers who know better than the estimate.\n if (safetyFactor === 0) {\n return;\n }\n\n const budget = getMemoryBudget();\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n\n // `live` describes a read that holds fewer rows at once than it covers - chunked iteration, and\n // nothing else so far. `rows` is how many are alive at the peak; `perChunk` is how many of them\n // one row of the caller's chunk size buys, so that a refusal can recommend a chunk size rather\n // than a live-row count. Both come from the same caller in the same call, so they cannot\n // describe different reads.\n const rowsLive = live === null ? null : live.rows;\n const liveRowsPerChunk = live === null ? 1 : live.perChunk;\n\n // The codes are allocated for whatever is decoded at once, which is one chunk under chunked\n // iteration and the whole window otherwise - the same distinction the heap estimate draws, and\n // it has to be drawn in both places or the two halves of the check describe different reads.\n const liveRows = rowsLive === null ? rowsToLoad : Math.min(rowsLive, rowsToLoad);\n const heapMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows, columnCount, materialisesRows, rowsLive);\n const externalMemory = estimateExternalMemory(liveRows, columnCount);\n\n // Each candidate is measured against the memory it actually bounds. The V8 heap limit bounds\n // old space, which TypedArray backing stores do not occupy; a container limit bounds the\n // process, which they do. Checking one figure against both was wrong in both directions at\n // once: it refused columnar reads that fit the heap forty times over, and - once that was\n // fixed by not charging them for rows - it admitted a columnar read allocating 130MB of codes\n // inside a container with less than that, where the kernel answers with a SIGKILL.\n const bounded = budget.candidates.map((candidate) => {\n const heapOnly = candidate.source === 'V8 heap limit';\n\n return {\n ...candidate,\n heapOnly,\n needs: heapOnly ? heapMemory : heapMemory + externalMemory,\n allowed: candidate.bytes * safetyFactor,\n bounds: heapOnly ? 'the V8 heap' : 'the whole process',\n };\n });\n\n const exceeded = bounded.filter((candidate) => candidate.needs > candidate.allowed);\n const binding = exceeded.reduce(\n (worst, candidate) => (candidate.needs / candidate.allowed > worst.needs / worst.allowed ? candidate : worst),\n exceeded[0],\n );\n\n const heapLimit = getHeapLimit();\n const availableMemory = binding ? binding.bytes : budget.bytes;\n const estimatedMemory = binding ? binding.needs : heapMemory;\n const maxAllowedMemory = binding ? binding.allowed : budget.bytes * safetyFactor;\n\n if (binding) {\n // Bisected against the same estimate this check uses, so the suggestion is one the caller\n // can act on. It used to invert the square-root symbol term alone and could suggest a row\n // count that the very next call rejected.\n // Bisected against the same quantity the refusal compared, which for a process-bounded limit\n // includes the external term. A suggestion measured against a different budget from the\n // refusal is the same mismatch this module exists to avoid, one level up.\n const includeExternal = !binding.heapOnly;\n const recommendedMaxRows = recommendedRowsFor(\n maxAllowedMemory,\n symbolTableSize,\n totalRows,\n columnCount,\n materialisesRows,\n includeExternal,\n );\n\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const availableMB = Math.round(maxAllowedMemory / 1024 / 1024);\n // The usable figure, not the reported one. These differ by the 192MB of non-old-space\n // that heap_size_limit counts, and printing the reported one next to a budget breakdown\n // carrying the corrected one told the reader two different things about the same limit -\n // in the one diagnostic whose job is to say which knob to turn.\n const heapLimitMB = Math.round(usableOldSpaceLimit() / 1024 / 1024);\n const reportedHeapLimitMB = Math.round(heapLimit / 1024 / 1024);\n const availableRamMB = Math.round(availableMemory / 1024 / 1024);\n\n // Naming the limit that bound the decision is the difference between an actionable error and\n // a puzzling one: raising --max-old-space-size fixes a heap-bound refusal and does nothing\n // for a container-bound one, where it makes the OOM kill more likely rather than less.\n // The bare source name, because callers match it against memoryBudget[].source - a test\n // pins that. What the limit bounds goes in its own field and into the prose.\n const limitingFactor = binding.source;\n const limitingScope = binding.bounds;\n const budgetBreakdown = budget.candidates\n .map((candidate) => `${candidate.source} ${Math.round(candidate.bytes / 1024 / 1024)}MB`)\n .join(', ');\n const observedBreakdown = budget.observed\n .map((entry) => `${entry.source} ${Math.round(entry.bytes / 1024 / 1024)}MB`)\n .join(', ');\n\n // Saying \"try maxRows: N\" when no N fits sends the caller round a loop, so that case gets its\n // own advice rather than a number that will be rejected on the next call.\n //\n // A chunked read gets a different knob named, because the one it has is not the window. Its\n // window may be the whole file by design, and shrinking it is not what the caller wants to\n // hear when what actually overflowed is one chunk.\n const containerBound = binding.source === 'container memory limit';\n const chunked = rowsLive !== null;\n const recommendedChunk = chunked\n ? recommendedChunkFor(\n maxAllowedMemory,\n symbolTableSize,\n maxRows,\n totalRows,\n columnCount,\n liveRowsPerChunk,\n includeExternal,\n )\n : 0;\n const knob = chunked ? 'chunkSize' : 'limit';\n const recommendedValue = chunked ? recommendedChunk : recommendedMaxRows;\n const nothingFits = recommendedValue === 0;\n\n let advice;\n if (nothingFits) {\n advice =\n `No row count fits this budget - the symbol table alone exceeds it, so ${knob} cannot help. ` +\n (containerBound\n ? `Raise the container's memory limit.`\n : `Raise the heap with --max-old-space-size, or raise memorySafetyFactor.`);\n } else if (containerBound) {\n advice = `The binding limit is the container's, so raising --max-old-space-size would let V8 grow past it and be killed by the OOM killer instead. Set it below the container limit, raise the limit, or hold fewer rows with ${knob} (recommended: ${recommendedValue.toLocaleString()} rows or less).`;\n } else {\n advice = `Try holding fewer rows using the ${knob} parameter (recommended: ${recommendedValue.toLocaleString()} rows or less), or raise the heap with --max-old-space-size.`;\n }\n\n throw new QvdValidationError(\n `Insufficient memory to load file safely. ` +\n `Symbol table: ${sizeMB}MB, Estimated memory needed: ${estimatedMB}MB, Available: ${availableMB}MB (limited by ${limitingFactor}, which bounds ${limitingScope}; considered: ${budgetBreakdown}; observed but not used: ${observedBreakdown}). ` +\n advice,\n {\n file: filePath,\n symbolTableSize,\n symbolTableSizeMB: sizeMB,\n estimatedMemoryMB: estimatedMB,\n availableMemoryMB: availableMB,\n heapLimitMB,\n reportedHeapLimitMB,\n availableRamMB,\n limitingFactor,\n limitingScope,\n memoryBudget: budget.candidates,\n memoryObserved: budget.observed,\n columnCount,\n totalRows,\n maxRows,\n recommendedMaxRows,\n // Only present when a chunk size is what overflowed, so a caller cannot mistake one\n // recommendation for the other.\n ...(chunked ? {rowsLive, recommendedChunkSize: recommendedChunk} : {}),\n },\n );\n }\n}\n\n/**\n * Emits a warning for large symbol tables when loading all rows.\n * Warning threshold scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {number} [columnCount=0] Columns per row, so the reported figure matches the check\n */\nexport function warnLargeSymbolTable(symbolTableSize, maxRows, totalRows, columnCount = 0, materialisesRows = true) {\n // Dynamic warning threshold: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n // 12.5% of the budget the check uses, not of the figure v8 reports. Thresholding on the\n // reported limit made the warning fire later than the refusal it is meant to precede, and by\n // the widest margin on the small heaps where the 192MB of non-old-space is most of it.\n const LARGE_SYMBOL_TABLE_WARNING = usableOldSpaceLimit() * 0.125;\n\n if (symbolTableSize <= LARGE_SYMBOL_TABLE_WARNING) {\n return;\n }\n\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n // Same estimate the check uses. Without columnCount this printed the symbol table's cost\n // alone - roughly 3.6GB where the check had just computed 5.2GB - and a caller sizing\n // --max-old-space-size from the warning would pick a heap far too small.\n const estimatedMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows, columnCount, materialisesRows);\n\n // The second condition is the cost of *this* read, not whether the caller happened to bound it.\n //\n // It used to be `maxRows === null || maxRows >= totalRows` - \"you asked for everything\". That is\n // a statement about which option was passed, and it came apart when `offset` arrived:\n // `{offset: 1}` on a ten-million-row file materialises 9,999,999 rows and reports a row count\n // one short of the total, so the warning about the memory that costs was silent in exactly the\n // case it exists for. Thresholding the estimate instead is the same answer for every shape that\n // existed before - a full read still warns, a small `maxRows` still does not, because the symbol\n // term is discounted by sqrt(rows/totalRows) - and it is right for the shapes that did not.\n if (estimatedMemory <= LARGE_SYMBOL_TABLE_WARNING) {\n return;\n }\n\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const warnMB = Math.round(LARGE_SYMBOL_TABLE_WARNING / 1024 / 1024);\n\n console.warn(\n `⚠️ Large symbol table detected (${sizeMB}MB > ${warnMB}MB threshold). ` +\n `This read materialises ${rowsToLoad.toLocaleString()} of ${totalRows.toLocaleString()} rows ` +\n `and will use ~${estimatedMB}MB RAM. ` +\n `Reading fewer rows - with limit, maxRows, or a narrower offset window - lowers the row cost, ` +\n `though the symbol table is read in full either way.`,\n );\n}\n","// @ts-check\n\nimport {QvdCorruptedError, QvdValidationError} from '../QvdErrors.js';\nimport {getHeapLimit} from './memoryUtils.js';\nimport {MAX_BIT_WIDTH} from './bitUtils.js';\n\n/**\n * Validates that a parsed XML header actually describes a QVD.\n *\n * `parseStringPromise` succeeds on any well-formed XML, and a QVD whose header has been damaged\n * into a fragment parses into an object rooted at whatever element survived - `{Thou: ''}` for\n * `__tests__/data/misc/damaged.qvd`. The `!headerObj` check beside each call site only covers XML\n * that did not parse at all, so the reader indexed straight into a missing `QvdTableHeader` and\n * raised a bare `TypeError`, reporting an ordinary corrupt file as a bug in this library.\n *\n * `Offset` is range-checked here because nothing downstream checks it: an unusable one makes the\n * index table offset NaN, which `_planIndexTable` reads as falsy and reports as the file having\n * been loaded out of order. `RecordByteSize` and `NoOfRecords` are deliberately left alone -\n * `validateIndexTableMetadata` and `validateRecordCount` already reject both the missing and the\n * malformed cases with a more specific message, and repeating the check here would replace it\n * with a vaguer one.\n *\n * @param {any} headerObj The parsed XML header.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} stage Stage name recorded in the error context.\n * @throws {QvdCorruptedError} If the header is not a usable QVD table header.\n */\nexport function validateHeaderStructure(headerObj, filePath, stage) {\n const tableHeader = headerObj?.['QvdTableHeader'];\n\n // `typeof null` is 'object' and an empty `<QvdTableHeader/>` parses to '' rather than to an\n // object, so neither case is caught by a truthiness or a typeof test on its own.\n if (tableHeader === null || typeof tableHeader !== 'object' || Array.isArray(tableHeader)) {\n throw new QvdCorruptedError('The XML header contains no usable QvdTableHeader element', {\n rootElements: headerObj && typeof headerObj === 'object' ? Object.keys(headerObj) : [],\n file: filePath,\n stage,\n });\n }\n\n const symbolTableLength = parseInt(tableHeader['Offset'], 10);\n\n if (isNaN(symbolTableLength) || !Number.isSafeInteger(symbolTableLength) || symbolTableLength < 0) {\n throw new QvdCorruptedError('Invalid symbol table offset', {\n offset: tableHeader['Offset'],\n file: filePath,\n stage,\n });\n }\n}\n\n/**\n * Validates symbol table size during initial file read (early check).\n * This is the first-pass validation in _readData for lazy loading.\n * Limit scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdValidationError} If symbol table exceeds dynamic limit\n */\nexport function validateSymbolTableSizeEarly(symbolTableLength, filePath) {\n // Dynamic limit: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n const heapLimit = getHeapLimit();\n const MAX_SYMBOL_TABLE_SIZE = heapLimit * 0.125;\n\n if (symbolTableLength > MAX_SYMBOL_TABLE_SIZE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(MAX_SYMBOL_TABLE_SIZE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table too large (${sizeMB}MB exceeds ${maxMB}MB limit for lazy loading). ` +\n `This QVD file contains extremely high-cardinality fields. ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 12.5% = ${maxMB}MB). ` +\n // \"without a row window\" rather than \"without maxRows\": a window can be spelled with\n // maxRows, limit, offset, or an offset and a limit together, and all four reach this\n // check. Naming one of them tells a caller who passed `offset` to remove something they\n // did not pass.\n `Consider: (1) loading the full file without a row window - maxRows, limit or offset - since the symbol table is read in full either way, (2) increasing heap size with --max-old-space-size, or (3) aggregating high-cardinality fields.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: MAX_SYMBOL_TABLE_SIZE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 12.5,\n },\n );\n }\n}\n\n/**\n * Validates symbol table size limits to prevent out-of-memory conditions.\n * This is the comprehensive validation in _parseSymbolTable.\n * Absolute ceiling scales with configured heap size (50% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} totalRows Total number of rows in the file\n * @throws {QvdValidationError} If symbol table exceeds safety limits\n */\nexport function validateSymbolTableSize(symbolTableLength, filePath, totalRows) {\n // Dynamic absolute ceiling: 50% of configured heap size\n // Examples: 4GB heap = 2GB, 8GB heap = 4GB, 16GB heap = 8GB, 32GB heap = 16GB\n const heapLimit = getHeapLimit();\n const ABSOLUTE_MAX_SYMBOL_TABLE = heapLimit * 0.5;\n\n if (symbolTableLength > ABSOLUTE_MAX_SYMBOL_TABLE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(ABSOLUTE_MAX_SYMBOL_TABLE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table exceeds absolute maximum size (${sizeMB}MB > ${maxMB}MB). ` +\n `This QVD file has pathological cardinality (likely a data modeling issue). ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 50% = ${maxMB}MB). ` +\n `Consider: (1) increasing heap size with --max-old-space-size, (2) aggregating high-cardinality fields, (3) splitting the data, or (4) using a different format.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: ABSOLUTE_MAX_SYMBOL_TABLE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 50,\n totalRows,\n },\n );\n }\n}\n\n/**\n * Validates field metadata before processing to prevent buffer overflow attacks.\n *\n * @param {any} field Field metadata object\n * @param {number} symbolBufferLength Length of the symbol buffer\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field metadata is invalid\n */\nexport function validateFieldMetadata(field, symbolBufferLength, filePath) {\n const symbolsOffset = parseInt(field['Offset'], 10);\n const symbolsLength = parseInt(field['Length'], 10);\n\n // Validate offset is a valid number and within bounds\n if (isNaN(symbolsOffset) || !Number.isSafeInteger(symbolsOffset) || symbolsOffset < 0) {\n throw new QvdCorruptedError('Invalid symbol offset', {\n field: field['FieldName'],\n offset: symbolsOffset,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate length is a valid number and non-negative\n if (isNaN(symbolsLength) || !Number.isSafeInteger(symbolsLength) || symbolsLength < 0) {\n throw new QvdCorruptedError('Invalid symbol length', {\n field: field['FieldName'],\n length: symbolsLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate that offset + length doesn't exceed buffer size\n if (symbolsOffset + symbolsLength > symbolBufferLength) {\n throw new QvdCorruptedError('Symbol data extends beyond buffer', {\n field: field['FieldName'],\n offset: symbolsOffset,\n length: symbolsLength,\n bufferSize: symbolBufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n}\n\n/**\n * Validates a header's declared record count.\n *\n * Extracted so the metadata-only read applies exactly the same rule as a load. When they were\n * separate, `readMetadata` coerced an unusable `NoOfRecords` to zero while `fromQvd` refused the\n * same file - so a header with the element deleted reported \"0 rows\" rather than \"this header is\n * broken\", which is indistinguishable from a genuinely empty QVD at the call site.\n *\n * @param {number} totalRows The parsed NoOfRecords.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} [stage='parseIndexTable'] Stage name recorded in the error context.\n * @throws {QvdCorruptedError} If the count is not a non-negative safe integer.\n */\nexport function validateRecordCount(totalRows, filePath, stage = 'parseIndexTable') {\n if (isNaN(totalRows) || !Number.isSafeInteger(totalRows) || totalRows < 0) {\n throw new QvdCorruptedError('Invalid number of records', {\n totalRows,\n file: filePath,\n stage,\n });\n }\n}\n\n/**\n * Validates index table metadata and bounds.\n *\n * @param {number} recordSize Size of a single record in bytes\n * @param {number} totalRows Total number of rows\n * @param {number} indexTableLength Length of the index table\n * @param {number} indexTableOffset Offset to the index table\n * @param {number} bufferLength Length of the buffer\n * @param {number} rowsToLoad Number of rows to load\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number|null} [fileSize] Actual size of the file on disk, when known. Used to detect a\n * header that describes more data than the file contains.\n * @param {number} [windowFirstRow=0] File row the decode starts at. The rows before it still have\n * to exist in the declared table, so the table has to reach `windowFirstRow + rowsToLoad`.\n * @param {number} [bufferFirstRow=0] File row the loaded buffer's index table starts at. A\n * windowed read loads only the records it wants, so this is not always zero, and the two row\n * numbers bound different things: the first bounds the file, the second bounds the buffer.\n * @throws {QvdCorruptedError} If index table metadata is invalid\n */\nexport function validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n indexTableOffset,\n bufferLength,\n rowsToLoad,\n filePath,\n fileSize = null,\n windowFirstRow = 0,\n bufferFirstRow = 0,\n) {\n // Validate recordSize\n if (isNaN(recordSize) || !Number.isSafeInteger(recordSize) || recordSize < 0) {\n throw new QvdCorruptedError('Invalid record byte size', {\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n validateRecordCount(totalRows, filePath);\n\n // Allow recordSize of 0 or 1 only when there are no records (empty QVD)\n // Qlik Sense uses recordSize=1 for empty QVDs\n if (recordSize === 0 && totalRows > 0) {\n throw new QvdCorruptedError('Record byte size cannot be zero when records exist', {\n recordSize,\n totalRows,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate recordSize is reasonable (max 1MB per record)\n if (recordSize > 1048576) {\n throw new QvdCorruptedError('Record byte size exceeds maximum', {\n recordSize,\n maxSize: 1048576,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table length\n if (isNaN(indexTableLength) || !Number.isSafeInteger(indexTableLength) || indexTableLength < 0) {\n throw new QvdCorruptedError('Invalid index table length', {\n length: indexTableLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table start offset doesn't extend beyond buffer\n if (indexTableOffset > bufferLength) {\n throw new QvdCorruptedError('Index table offset beyond buffer', {\n indexTableOffset,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // The index table must be exactly as long as the record count implies. Every QVD produced by\n // Qlik or by this library satisfies this, so a mismatch means the header is inconsistent.\n // Checking it catches corrupt headers that would otherwise decode misaligned rows.\n if (indexTableLength !== totalRows * recordSize) {\n throw new QvdCorruptedError('Index table length inconsistent with record count', {\n indexTableLength,\n expectedLength: totalRows * recordSize,\n totalRows,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate the index table against the actual file when its size is known.\n //\n // Comparing against the in-memory buffer instead is wrong in both directions: during a lazy\n // load the buffer is deliberately truncated, so valid large files were rejected as corrupt,\n // while a truncated file whose header claims more data was accepted and silently returned\n // fewer rows than the header declares.\n if (fileSize !== null) {\n if (indexTableOffset + indexTableLength > fileSize) {\n throw new QvdCorruptedError('Index table extends beyond the end of the file', {\n indexTableOffset,\n indexTableLength,\n fileSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n }\n\n // Ensure the loaded buffer actually holds the rows we were asked to parse.\n //\n // The window's records start `(windowFirstRow - bufferFirstRow)` records into the buffer's index\n // table, which is zero for a read that starts at row 0 and not zero for one that does not.\n const requiredIndexBytes = rowsToLoad * recordSize;\n const bufferRecordStart = (windowFirstRow - bufferFirstRow) * recordSize;\n if (indexTableOffset + bufferRecordStart + requiredIndexBytes > bufferLength) {\n throw new QvdCorruptedError('Index table truncated', {\n indexTableOffset,\n requiredBytes: requiredIndexBytes,\n availableBytes: Math.max(0, bufferLength - indexTableOffset - bufferRecordStart),\n rowsToLoad,\n windowFirstRow,\n bufferFirstRow,\n recordSize,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Ensure the index table reaches the end of the window, not merely as far as its length.\n //\n // Measured against the window's last row rather than its row count: `{offset: 10, limit: 5}`\n // needs fifteen records to exist, and comparing five against the table's length would accept a\n // file that holds only twelve - decoding three real rows and two of whatever follows.\n const requiredTableBytes = (windowFirstRow + rowsToLoad) * recordSize;\n if (indexTableLength < requiredTableBytes) {\n throw new QvdCorruptedError('Index table length smaller than required', {\n indexTableLength,\n requiredBytes: requiredTableBytes,\n rowsToLoad,\n windowFirstRow,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n\n/**\n * Validates field bit offset and bit width for index table parsing.\n *\n * @param {any} field Field metadata object\n * @param {number} recordSize Size of a single record in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field bit metadata is invalid\n */\nexport function validateFieldBitMetadata(field, recordSize, filePath) {\n const bitOffset = parseInt(field['BitOffset'], 10);\n const bitWidth = parseInt(field['BitWidth'], 10);\n\n // Validate bitOffset\n if (isNaN(bitOffset) || !Number.isSafeInteger(bitOffset) || bitOffset < 0) {\n throw new QvdCorruptedError('Invalid bit offset', {\n field: field['FieldName'],\n bitOffset,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth\n if (isNaN(bitWidth) || !Number.isSafeInteger(bitWidth) || bitWidth < 0) {\n throw new QvdCorruptedError('Invalid bit width', {\n field: field['FieldName'],\n bitWidth,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias.\n //\n // It is added to every decoded index inside an Int32Array, and Int32Array coerces NaN to 0 -\n // so an absent or non-numeric Bias made a file read back as plausible wrong values rather\n // than as an error. A blank <Bias> on a nullable column turned every NULL and every symbol\n // above the first into the first symbol, silently. Validated here alongside the other two\n // because the three travel together and are trusted together.\n const bias = parseInt(field['Bias'], 10);\n\n if (isNaN(bias) || !Number.isSafeInteger(bias)) {\n throw new QvdCorruptedError('Invalid bias', {\n field: field['FieldName'],\n bias: field['Bias'],\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth against what a stored index can be.\n //\n // Indices are kept in an Int32Array, so the value has to fit in a positive 32-bit integer.\n // The bound is not a limitation in practice - 31 bits addresses two billion symbols in one\n // field - and refusing is the safe direction: a 32-bit width lets the top of the range wrap\n // to a negative index, and a negative index means NULL, so the file would read back with\n // plausible wrong values rather than an error.\n if (bitWidth > MAX_BIT_WIDTH) {\n throw new QvdCorruptedError('Bit width exceeds maximum', {\n field: field['FieldName'],\n bitWidth,\n maxBitWidth: MAX_BIT_WIDTH,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitOffset + bitWidth doesn't exceed record size in bits\n const recordSizeInBits = recordSize * 8;\n if (bitOffset + bitWidth > recordSizeInBits) {\n throw new QvdCorruptedError('Bit field extends beyond record size', {\n field: field['FieldName'],\n bitOffset,\n bitWidth,\n recordSizeInBits,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n","// @ts-check\n\nimport {QvdSymbol} from '../QvdSymbol.js';\nimport {QvdCorruptedError, QvdParseError} from '../QvdErrors.js';\n\n/**\n * Parses an integer symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for an integer\n if (pointer + 4 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading integer symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const byteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 4));\n const value = Buffer.from(byteData).readIntLE(0, byteData.length);\n return {symbol: QvdSymbol.fromIntValue(value), bytesRead: 4};\n}\n\n/**\n * Parses a double symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for a double\n if (pointer + 8 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading double symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const byteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 8));\n const value = Buffer.from(byteData).readDoubleLE(0);\n return {symbol: QvdSymbol.fromDoubleValue(value), bytesRead: 8};\n}\n\n/**\n * Parses a string symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n const startPointer = pointer;\n const maxStringLength = 1048576; // 1MB max string size to prevent memory exhaustion\n let stringLength = 0;\n\n // Find the null terminator\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('String symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n // Ensure we found the null terminator\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('String symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const value = symbolBuffer.subarray(startPointer, pointer).toString('utf-8');\n return {symbol: QvdSymbol.fromStringValue(value), bytesRead: pointer - startPointer + 1};\n}\n\n/**\n * Skips a string symbol in the buffer without parsing it.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {number} Bytes to skip\n */\nexport function skipStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n const startPointer = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('String symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('String symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return pointer - startPointer + 1;\n}\n\n/**\n * Parses a dual integer symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDualIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for an integer\n if (pointer + 4 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading dual integer symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const intByteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 4));\n const intValue = Buffer.from(intByteData).readIntLE(0, intByteData.length);\n pointer += 4;\n\n // Parse the string portion\n const stringStart = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const stringValue = symbolBuffer.subarray(stringStart, pointer).toString('utf-8');\n return {symbol: QvdSymbol.fromDualIntValue(intValue, stringValue), bytesRead: pointer - (stringStart - 4) + 1};\n}\n\n/**\n * Parses a dual double symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDualDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for a double\n if (pointer + 8 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading dual double symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const doubleByteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 8));\n const doubleValue = Buffer.from(doubleByteData).readDoubleLE(0);\n pointer += 8;\n\n // Parse the string portion\n const stringStart = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const stringValue = symbolBuffer.subarray(stringStart, pointer).toString('utf-8');\n return {\n symbol: QvdSymbol.fromDualDoubleValue(doubleValue, stringValue),\n bytesRead: pointer - (stringStart - 8) + 1,\n };\n}\n\n/**\n * Skips a dual symbol (integer or double) in the buffer without parsing it.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {number} numericBytes Number of bytes for the numeric portion (4 for int, 8 for double)\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {number} Bytes to skip\n */\nexport function skipDualSymbol(symbolBuffer, pointer, bufferLength, numericBytes, fieldName, filePath) {\n if (pointer + numericBytes > bufferLength) {\n throw new QvdCorruptedError(`Buffer overflow reading dual symbol`, {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const startPointer = pointer;\n pointer += numericBytes;\n\n // Skip the string portion\n const maxStringLength = 1048576;\n let stringLength = 0;\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return pointer - startPointer + 1;\n}\n\n/**\n * Parses a symbol based on the type byte.\n *\n * @param {number} typeByte The type byte\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position (after type byte)\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {boolean} shouldParse Whether to parse the symbol (true) or skip it (false)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol (or null if skipped) and bytes read\n */\nexport function parseSymbol(typeByte, symbolBuffer, pointer, bufferLength, fieldName, filePath, shouldParse) {\n switch (typeByte) {\n case 1: {\n // Integer value (4 Bytes)\n if (shouldParse) {\n return parseIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n return {symbol: null, bytesRead: 4};\n }\n case 2: {\n // Double value (8 Bytes)\n if (shouldParse) {\n return parseDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n return {symbol: null, bytesRead: 8};\n }\n case 4: {\n // String value (0 terminated)\n if (shouldParse) {\n return parseStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n case 5: {\n // Dual (Integer format) value (4 bytes), followed by string format\n if (shouldParse) {\n return parseDualIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipDualSymbol(symbolBuffer, pointer, bufferLength, 4, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n case 6: {\n // Dual (Double format) value (8 bytes), followed by string format\n if (shouldParse) {\n return parseDualDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipDualSymbol(symbolBuffer, pointer, bufferLength, 8, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n default: {\n throw new QvdParseError('Unknown symbol type byte', {\n typeByte: typeByte.toString(16),\n offset: pointer - 1,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {readerOptionsFrom, windowFrom} from './util/readOptions.js';\n\n/**\n * One column of a QVD, as the file stores it: a code per row and a dictionary of values.\n *\n * This is the shape the format already has. A QVD does not store a value per cell; it stores a\n * table of distinct symbols per field and an array of indices into it. Keeping that shape is\n * what makes a column cheap - four bytes per row, plus one entry per *distinct* value - and it\n * is why none of the questions that dog a per-row typed array arise here:\n *\n * - A mixed column needs no decision, because nothing per row is typed. On the bundled taxi\n * fixture **no column at all is strictly numeric**: `dropoff_census_tract` is 43% empty\n * strings, and four columns are 100% strings. A `Float64Array` of values would put NaN in\n * 43% of that column and erase Qlik's distinction between a blank and a number.\n * - NULL is a property of the position, not of the value: `codes[row] < 0`. No sentinel is\n * invented, so no sentinel can collide with real data.\n * - An all-null column, a single-valued column and a zero-row column are the same code path.\n */\nexport class QvdColumn {\n /**\n * @param {string} name The field name.\n * @param {Int32Array} codes One stored index per row, bias applied. Negative means NULL.\n * @param {Array<any>} symbols The field's distinct values, indexed by code.\n */\n constructor(name, codes, symbols) {\n this._name = name;\n this._codes = codes;\n this._symbols = symbols;\n\n Object.freeze(this);\n }\n\n /** @return {string} The field name. */\n get name() {\n return this._name;\n }\n\n /** @return {number} Rows in the column. */\n get length() {\n return this._codes.length;\n }\n\n /**\n * The stored index of each row. Negative means NULL.\n *\n * The table's own array, not a copy - it is the thing that makes this cheap, and copying it\n * per call would defeat the point. Treat it as read-only.\n *\n * @return {Int32Array} One code per row.\n */\n get codes() {\n return this._codes;\n }\n\n /**\n * The field's distinct values, indexed by the codes.\n *\n * One entry per distinct value, not per row: a few thousand entries for a column of millions.\n *\n * @return {ReadonlyArray<any>} The dictionary.\n */\n get symbols() {\n return this._symbols;\n }\n\n /**\n * The value of one row.\n *\n * @param {number} row The row index.\n * @return {any} The value, or null where the file stores NULL.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n at(row) {\n if (!Number.isInteger(row) || row < 0 || row >= this._codes.length) {\n throw new QvdValidationError('Row index out of bounds', {\n column: this._name,\n row,\n length: this._codes.length,\n });\n }\n\n const code = this._codes[row];\n\n return code < 0 ? null : this._symbols[code];\n }\n\n /**\n * Iterates the column's values without materialising it.\n *\n * @return {Iterator<any>} An iterator over the values, NULLs included as null.\n */\n [Symbol.iterator]() {\n const codes = this._codes;\n const symbols = this._symbols;\n let row = 0;\n\n return {\n next() {\n if (row >= codes.length) {\n return {done: true, value: undefined};\n }\n\n const code = codes[row++];\n\n return {done: false, value: code < 0 ? null : symbols[code]};\n },\n };\n }\n\n /**\n * The column as a plain array of values, one per row.\n *\n * Lossless, and cell-for-cell what `QvdDataFrame.data[row][column]` would hold. The caller\n * owns the result; the table keeps no reference to it, so two calls return two arrays.\n *\n * @return {Array<any>} One value per row.\n */\n toArray() {\n const out = new Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n out[row] = code < 0 ? null : this._symbols[code];\n }\n\n return out;\n }\n\n /**\n * The dictionary as numbers, for scanning without materialising the column.\n *\n * One entry per *distinct* value, not per row - 17 KB for a column of 1.7 million rows with\n * 2,188 symbols - so this is the cheap conversion, where `toFloat64Array()` is the expensive\n * one. Non-numeric symbols become NaN, which is safe here in a way it is not per row: the\n * codes still distinguish NULL, and a caller that wants the blank back still has `symbols`.\n *\n * Scanning `codes` against this is the fastest way to read a column, because both sides are\n * contiguous typed arrays and the dictionary fits in cache:\n *\n * ```js\n * const codes = column.codes;\n * const values = column.numericSymbols();\n * let total = 0;\n * for (let row = 0; row < codes.length; row++) {\n * const code = codes[row];\n * if (code >= 0) {\n * const value = values[code];\n * if (!Number.isNaN(value)) total += value;\n * }\n * }\n * ```\n *\n * @return {Float64Array} One number per distinct symbol, NaN where the symbol is not a number.\n */\n numericSymbols() {\n const out = new Float64Array(this._symbols.length);\n\n for (let index = 0; index < this._symbols.length; index++) {\n const value = this._symbols[index];\n out[index] = typeof value === 'number' ? value : NaN;\n }\n\n return out;\n }\n\n /**\n * The column as a `Float64Array`.\n *\n * Named for what it costs rather than offered as *the* representation, because it is lossy\n * and on real data it is lossy often: it cannot distinguish a blank from a number, and the\n * bundled taxi fixture has a column that is 43% blank. It therefore refuses by default\n * rather than quietly writing NaN over two fifths of a column.\n *\n * @param {Object} [options] Conversion options.\n * @param {'throw'|'nan'} [options.onNonNumeric='throw'] What to do with a value that is not a\n * number - including NULL. `'throw'` refuses and names the offending row; `'nan'` writes\n * NaN, which is the right choice only when the caller knows the column is numeric.\n * @return {Float64Array} One number per row.\n * @throws {QvdValidationError} If a value is not a number and `onNonNumeric` is `'throw'`.\n */\n toFloat64Array(options = {}) {\n const {onNonNumeric = 'throw'} = options;\n\n if (onNonNumeric !== 'throw' && onNonNumeric !== 'nan') {\n throw new QvdValidationError('onNonNumeric must be \"throw\" or \"nan\"', {\n column: this._name,\n provided: onNonNumeric,\n });\n }\n\n const out = new Float64Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n const value = code < 0 ? null : this._symbols[code];\n\n if (typeof value === 'number') {\n out[row] = value;\n continue;\n }\n\n if (onNonNumeric === 'throw') {\n throw new QvdValidationError('Column holds a value that is not a number', {\n column: this._name,\n row,\n value,\n type: value === null ? 'null' : typeof value,\n hint: 'Pass {onNonNumeric: \"nan\"} to write NaN instead, or use toArray() to keep the value.',\n });\n }\n\n out[row] = NaN;\n }\n\n return out;\n }\n}\n\n/**\n * A QVD read as columns rather than as rows.\n *\n * The same file, the same decoder and the same symbol resolution as `QvdDataFrame.fromQvd` -\n * it simply stops before building rows, and keeps what the decoder already produced. Measured\n * on `__tests__/data/chicago_taxi_rides/chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows x 20\n * columns, as `heapUsed + external` either side of a forced collection:\n *\n * | | retained | bytes/cell |\n * | --- | --- | --- |\n * | `QvdDataFrame.fromQvd()` | 352.8 MiB | 10.84 |\n * | `QvdColumnTable.fromQvd()` | 38.6 MiB | 1.18 |\n *\n * It is not a data frame and does not become one. Offering a conversion would let a caller hold\n * both representations at once, which is the one configuration in which this costs more than it\n * saves. Re-reading a file as rows costs what reading it as rows always cost; there is no\n * saving to protect by avoiding that.\n */\nexport class QvdColumnTable {\n /**\n * @param {Object} decoded What the reader decoded.\n * @param {Array<string>} decoded.columns Field names, in file order.\n * @param {Array<Int32Array>} decoded.codesByField One code array per field.\n * @param {Array<Array<any>>} decoded.symbolsByField One dictionary per field.\n * @param {number} decoded.rowCount Rows decoded.\n * @param {any} decoded.metadata The raw QvdTableHeader.\n * @param {any} decoded.loadStats Statistics about the read.\n */\n constructor({columns, codesByField, symbolsByField, rowCount, metadata, loadStats}) {\n this._columns = columns;\n this._codesByField = codesByField;\n this._symbolsByField = symbolsByField;\n this._rowCount = rowCount;\n this._metadata = metadata;\n this._loadStats = loadStats;\n }\n\n /**\n * Reads a QVD file as columns.\n *\n * Takes the same options as `QvdDataFrame.fromQvd`, with the same meanings - one option\n * vocabulary for both read paths, because they are two answers about the same file rather than\n * two features. `{offset, limit}` is how a caller pages through a file columnwise; there is no\n * columnar `iterate()` because there is nothing for it to bound - a columnar read materialises\n * no rows, which is the memory chunking exists to cap.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Loading options, with the same meanings they have on `fromQvd`.\n * @param {number|null} [options.maxRows] Rows to decode. The older name for `limit`.\n * @param {number|null} [options.limit] Rows to decode, counting from `offset`.\n * @param {number} [options.offset] File row to start at.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear. Unselected fields have their symbols skipped entirely.\n * @param {Function} [options.onProgress] Progress callback, `{stage, current, total, percent}`.\n * @param {AbortSignal} [options.signal] Cancels the read.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor] Fraction of the memory budget a load may use.\n * @param {number} [options.symbolFilteringThreshold] Symbol table size above which a limited\n * read switches to two-pass filtering.\n * @return {Promise<QvdColumnTable>} The file, as columns.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n const reader = new QvdFileReader(path, {\n ...readerOptionsFrom(options),\n\n // This read builds no rows, so the memory guard must not charge it for them. A columnar\n // read of the 38MB taxi fixture completes in a 15MB heap; charged the row cost it was\n // refused below a 2GB one.\n materialisesRows: false,\n });\n\n return await reader.loadColumnar(windowFrom(options));\n }\n\n /** @return {Array<string>} Field names, in file order. */\n get columns() {\n return this._columns;\n }\n\n /** @return {number} Rows decoded. */\n get rowCount() {\n return this._rowCount;\n }\n\n /** @return {Array<number>} `[rows, columns]`, as on a data frame. */\n get shape() {\n return [this._rowCount, this._columns.length];\n }\n\n /** @return {any} The raw `QvdTableHeader`. */\n get metadata() {\n return this._metadata;\n }\n\n /** @return {any} Statistics about the read. */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * One column.\n *\n * @param {string} name The field name.\n * @return {QvdColumn} The column.\n * @throws {QvdValidationError} If the field is not in this file.\n */\n column(name) {\n const index = this._columns.indexOf(name);\n\n if (index === -1) {\n throw new QvdValidationError(`Column '${name}' does not exist`, {\n column: name,\n availableColumns: this._columns,\n });\n }\n\n return new QvdColumn(name, this._codesByField[index], this._symbolsByField[index]);\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport xml from 'xml2js';\nimport assert from 'assert';\nimport {QvdDataFrame} from './QvdDataFrame.js';\nimport {QvdParseError, QvdValidationError, QvdCorruptedError} from './QvdErrors.js';\nimport {validatePath} from './util/validatePath.js';\nimport {decodeIndexColumn} from './util/bitUtils.js';\nimport {validateMemoryAvailability, warnLargeSymbolTable} from './util/memoryUtils.js';\nimport {\n validateHeaderStructure,\n validateSymbolTableSize,\n validateSymbolTableSizeEarly,\n validateFieldMetadata,\n validateIndexTableMetadata,\n validateFieldBitMetadata,\n validateRecordCount,\n} from './util/validationUtils.js';\nimport {parseSymbol} from './util/symbolParser.js';\nimport {normaliseWindow, resolveWindow, selectFields} from './util/readOptions.js';\n\n/**\n * @typedef {import('./util/readOptions.js').QvdRowWindow} QvdRowWindow\n */\n\n/**\n * Maximum number of bytes searched for the XML header delimiter before giving up.\n * Real QVD headers are a few kilobytes; the largest observed is well under 100KB.\n */\nconst MAX_HEADER_SIZE = 16 * 1024 * 1024;\n\n/**\n * Maximum length of a single fs.read call. Node's fs.read binding requires the length to fit\n * in an Int32: a larger value aborts the process via a C++ assertion instead of throwing.\n */\nconst READ_CHUNK_SIZE = 512 * 1024 * 1024;\n\n/**\n * Rows the two-pass symbol analysis decodes at a time.\n *\n * The pass collects the *set* of stored indices a window references, and a set is the same\n * whether it is built in one pass or in slices - so this bounds the scratch column at 256KB\n * instead of four bytes per row of the window. It is a working-set size, not a correctness\n * parameter: any value gives the same answer.\n */\nconst ANALYSIS_SLICE_ROWS = 65536;\n\n/**\n * Parses a QVD file and loads it into memory.\n */\nexport class QvdFileReader {\n /**\n * Constructs a new QVD file parser.\n *\n * @param {string} filePath The path to the QVD file to load.\n * @param {Object} [options={}] Options for the reader.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction (0.0-1.0) of the memory budget a\n * load may use. The budget is the smaller of the V8 heap limit and any container memory limit;\n * what the OS reports as available is recorded for diagnostics and deliberately not allowed to\n * bind - see `getMemoryBudget`. Default is 0.8. **Zero disables the memory\n * check entirely**, which is the escape hatch for runtimes whose limits cannot be measured -\n * Bun reports its current heap as its heap limit - and for callers who would rather manage\n * memory themselves than trust the estimate.\n * @param {boolean} [options.materialisesRows=true] Whether this read will build row arrays.\n * False for a columnar read, whose memory is TypedArray backing stores outside the V8 heap\n * and which must not be charged the row cost.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes,\n * above which a lazy load switches to the two-pass filtering path. The default of 50MB is\n * the point where the extra analysis pass pays for itself; lower it to use filtering on\n * smaller files, raise it to keep the simpler single-pass read for longer.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear. Null reads every field, in file order. An unknown or repeated name is refused.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}` as the\n * read proceeds - the same shape `QvdFileWriter` emits.\n * @param {AbortSignal} [options.signal] Cancels the read. When it is aborted the read throws\n * `signal.reason`, exactly as `signal.throwIfAborted()` does.\n */\n constructor(filePath, options = {}) {\n const {\n allowedDir,\n memorySafetyFactor = 0.8,\n symbolFilteringThreshold = 50 * 1024 * 1024,\n materialisesRows = true,\n fields = null,\n onProgress,\n signal,\n } = options;\n this._materialisesRows = materialisesRows;\n this._path = validatePath(filePath, allowedDir);\n this._memorySafetyFactor = memorySafetyFactor;\n this._symbolFilteringThreshold = symbolFilteringThreshold;\n\n if (onProgress !== undefined && typeof onProgress !== 'function') {\n throw new QvdValidationError('onProgress must be a function', {\n provided: onProgress,\n type: typeof onProgress,\n file: this._path,\n });\n }\n\n // Checked here rather than at the first use, so a caller who passes something signal-shaped\n // finds out before the file is opened instead of discovering that cancellation silently did\n // nothing. `throwIfAborted` is the whole contract this reader needs from it.\n if (\n signal !== undefined &&\n (typeof signal !== 'object' || signal === null || typeof signal.aborted !== 'boolean')\n ) {\n throw new QvdValidationError('signal must be an AbortSignal', {\n provided: signal,\n type: typeof signal,\n file: this._path,\n });\n }\n\n /** @type {Array<string>|null} */\n this._requestedFields = fields === undefined ? null : fields;\n this._onProgress = onProgress;\n this._signal = signal;\n\n this._buffer = null;\n this._headerOffset = null;\n this._symbolTableOffset = null;\n this._indexTableOffset = null;\n this._header = null;\n /**\n * Every field header in the file, in file order, and the caller's selection of them in the\n * order the result should carry. Both are set by `_parseHeader` and null until it has run.\n *\n * One derivation feeds the symbol table, the decoded columns and `columns`, which are three\n * arrays indexed by the same position. Deriving the selection separately at each of those\n * sites - which is what this replaced - meant three answers that had to agree by inspection\n * rather than by construction.\n *\n * @type {Array<any>|null}\n */\n this._allFields = null;\n /** @type {Array<any>|null} */\n this._selectedFields = null;\n /** Whether every field's bit metadata has been validated. Header data; check it once. */\n this._fieldBitMetadataValidated = false;\n /** @type {Array<Array<import('./QvdSymbol.js').QvdSymbol>>|null} */\n this._symbolTable = null;\n /**\n * Stored symbol indices, one Int32Array per field rather than one array per row.\n *\n * Column-major because that is what lets the decoder hoist a field's bit offset, width and\n * bias out of the row loop and write straight into a typed array - no allocation per row or\n * per cell. Renamed from `_indexTable` deliberately: the shape changed, and a reader of this\n * code should not have to discover that from the subscripts.\n *\n * @type {Array<Int32Array>|null}\n */\n this._indexColumns = null;\n\n /** Rows actually decoded into `_indexColumns`. @type {number} */\n this._rowsDecoded = 0;\n /**\n * The file row that the buffer's index table starts at.\n *\n * A windowed read loads only the records it wants, so record 0 of the loaded buffer is not\n * row 0 of the file. Everything that indexes into the index table has to subtract this, and\n * getting it wrong shifts every value by a whole number of rows - which decodes cleanly and\n * returns the wrong data, the #113 failure shape applied to rows instead of symbols.\n *\n * @type {number}\n */\n this._bufferFirstRow = 0;\n /** @type {number|null} */\n this._fileSize = null;\n /** Whether the header's declared extent fits inside the file. False until _readData says so. */\n this._headerMatchesFile = false;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * The same shape `QvdFileWriter._emitProgress` emits, deliberately: a caller who has written a\n * progress bar for a write should not have to write a second one for a read. The stage names\n * differ because the stages differ, but `symbol-table` and `index-table` mean the same thing on\n * both sides.\n *\n * @param {string} stage The current stage of the read.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n * @private\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n\n this._onProgress({stage, current, total, percent});\n }\n }\n\n /**\n * Throws if the caller has cancelled the read.\n *\n * Throws `signal.reason` - a `DOMException` named `AbortError` unless the caller aborted with a\n * reason of their own. That is what `AbortSignal` means everywhere else in Node, and inventing\n * a `QvdAbortError` here would make this library's cancellation the one a caller has to special\n * case.\n *\n * @private\n */\n _throwIfAborted() {\n if (this._signal) {\n this._signal.throwIfAborted();\n }\n }\n\n /**\n * Reads the binary data of the QVD file.\n *\n * LAZY LOADING OPTIMIZATION: When maxRows is specified, this method implements\n * true lazy loading by reading only the necessary portions of the file from disk.\n *\n * For large files (e.g., 5GB), loading only the first 1000 rows can save significant\n * memory and time:\n * - Full load: 5GB in memory, ~30-60s load time\n * - Lazy load (maxRows=1000): ~1.75-2GB in memory, ~2-5s load time\n *\n * Algorithm for Lazy Loading:\n * 1. Stream-read the file until XML header delimiter is found\n * 2. Parse header to determine symbol table and index table locations\n * 3. Calculate bytes needed: header + full symbol table + partial index table\n * 4. Read only those calculated bytes using fs.open/read\n * 5. Rest of parsing proceeds normally with limited data\n *\n * WHY THIS APPROACH:\n * - Symbol table must be fully loaded (contains all unique values)\n * - Index table can be partially loaded (only rows we need)\n * - Streaming for header finding is efficient for unknown header sizes\n * - Direct byte-range reading for remaining data is fastest\n *\n * A window with a non-zero `offset` reads two ranges rather than one: the header and symbol\n * table from the front of the file, and the window's records from wherever they sit. The bytes\n * between are never read, which is what makes `{offset: 1_700_000, limit: 100}` on the taxi\n * fixture a 0.4MB read rather than a 38MB one.\n *\n * @param {QvdRowWindow} window The rows to read.\n * @param {boolean} [headerOnly=false] Stop once the XML header has been read, leaving the\n * symbol and index tables on disk. This is the metadata-only path: the header is a few\n * kilobytes whatever the file's size, so reading a schema costs the same for a 40MB file as\n * for a 40GB one.\n * @param {{rows: number, perChunk: number}|null} [liveRows=null] Rows held at one instant when\n * that is fewer than the window covers - see `_prepare`.\n * @private\n */\n async _readData(window = {offset: 0, limit: null}, headerOnly = false, liveRows = null) {\n this._throwIfAborted();\n this._emitProgress('read', 0, 1);\n // The header is scanned first on both paths, including a full load that is about to read the\n // whole file anyway. It costs a few kilobytes and it is what lets the memory check run\n // *before* the body is read: otherwise a 1.7GB file is loaded into memory in full and only\n // then refused, which is the opposite of what a safety check is for.\n const HEADER_DELIMITER = '\\r\\n\\0';\n const CHUNK_SIZE = 64 * 1024; // 64KB chunks - balance between memory and I/O efficiency\n\n // Use streaming to find the header delimiter dynamically\n // We don't know header size in advance, so we must stream-read\n const stream = fs.createReadStream(this._path, {\n highWaterMark: CHUNK_SIZE,\n });\n\n /** @type {Array<Buffer>} */\n const headerChunks = [];\n let headerBytes = 0;\n /** Last (delimiter length - 1) bytes seen so far, carried across chunk boundaries. */\n let tail = Buffer.alloc(0);\n let headerDelimiterIndex = -1;\n\n try {\n // Read chunks until we find the delimiter.\n //\n // Chunks are collected and concatenated once, and each chunk is searched individually\n // (with a small carry-over so a delimiter straddling a chunk boundary is still found).\n // Concatenating the whole accumulated buffer on every chunk and re-scanning it from the\n // start is quadratic: a 200 MB delimiter-less file cost 43 s and 13 GB of memory.\n for await (const chunk of stream) {\n // Search the new chunk prefixed by the bytes already seen, so a delimiter spanning a\n // chunk boundary is not missed.\n //\n // The carry is kept in `tail` across iterations rather than read back off the previous\n // chunk, because a chunk may be shorter than the delimiter. Taking min(bytesSoFar, 2)\n // bytes from a 1-byte previous chunk yields only 1 byte, which both misses a delimiter\n // spread over three chunks and leaves the reported offset short by the difference.\n const chunkStart = headerBytes;\n const searchBuffer = tail.length > 0 ? Buffer.concat([tail, chunk]) : chunk;\n const foundInSearch = searchBuffer.indexOf(HEADER_DELIMITER);\n\n headerChunks.push(chunk);\n headerBytes += chunk.length;\n\n if (foundInSearch !== -1) {\n // searchBuffer starts tail.length bytes before this chunk does.\n headerDelimiterIndex = chunkStart - tail.length + foundInSearch;\n stream.destroy();\n break;\n }\n\n // Copy the carry instead of keeping a subarray view, which would pin the whole chunk.\n tail = Buffer.from(searchBuffer.subarray(-(HEADER_DELIMITER.length - 1)));\n\n // Real QVD headers are a few kilobytes. Without a cap, a non-QVD or corrupt file is\n // read to its end before the error below is raised, which is a denial-of-service\n // vector for any service that accepts uploaded files.\n if (headerBytes > MAX_HEADER_SIZE) {\n stream.destroy();\n throw new QvdCorruptedError(\n `The XML header delimiter was not found within the first ${MAX_HEADER_SIZE / (1024 * 1024)}MB of the file.`,\n {\n file: this._path,\n bytesSearched: headerBytes,\n maxHeaderSize: MAX_HEADER_SIZE,\n stage: 'readData',\n },\n );\n }\n }\n } catch (error) {\n // Destroying the stream once the delimiter is found surfaces as ERR_STREAM_PREMATURE_CLOSE.\n // That one case is expected and ignored; everything else must propagate.\n //\n // The previous condition also required a 'code' property, so any error without one — a\n // TypeError or RangeError raised in the loop body, or a stream error from a source that\n // does not set a code — was swallowed. Execution then fell through to the generic\n // 'header not properly delimited' error below, reporting file corruption for what was\n // actually a bug or an I/O failure.\n const isExpectedEarlyClose =\n headerDelimiterIndex !== -1 &&\n error !== null &&\n typeof error === 'object' &&\n /** @type {{code?: unknown}} */ (error).code === 'ERR_STREAM_PREMATURE_CLOSE';\n\n if (!isExpectedEarlyClose) {\n throw error;\n }\n }\n\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'readData',\n },\n );\n }\n\n const headerBuffer = Buffer.concat(headerChunks);\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n\n // Parse header to get metadata about symbol and index table locations\n const headerXml = headerBuffer.subarray(0, headerEndIndex).toString();\n const headerObj = await xml.parseStringPromise(headerXml, {explicitArray: false});\n\n if (!headerObj) {\n throw new QvdParseError('The XML header could not be parsed.', {\n file: this._path,\n stage: 'readData',\n });\n }\n\n validateHeaderStructure(headerObj, this._path, 'readData');\n\n const symbolTableOffset = headerEndIndex;\n const symbolTableLength = parseInt(headerObj['QvdTableHeader']['Offset'], 10);\n const indexTableOffset = symbolTableOffset + symbolTableLength;\n const recordSize = parseInt(headerObj['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(headerObj['QvdTableHeader']['NoOfRecords'], 10);\n\n if (headerOnly) {\n // The header, and not one byte more. `headerChunks` holds whole 64KB chunks, so the tail\n // of the last one is whatever followed the delimiter; trimming it is what keeps this\n // constant-cost rather than \"the header plus up to 64KB of symbol table\".\n //\n // This returns before the memory check below on purpose. That check sizes the rows a call\n // will materialise, and this call materialises none - running it would let a file too\n // large to load refuse to report its own schema, which is the opposite of the point.\n //\n // _parseHeader runs next and re-derives the offsets from this buffer, exactly as it does\n // on the full path. Nothing downstream of it is reached, because there are no rows.\n this._buffer = headerBuffer.subarray(0, headerEndIndex);\n this._emitProgress('read', 1, 1);\n return;\n }\n\n // Column count drives the largest term in the memory estimate, because what actually\n // exhausts the heap on a many-row file is one array per row plus one slot per cell - not the\n // symbol table, which for the commonest Qlik shape is tiny.\n let headerFields = headerObj['QvdTableHeader']?.['Fields']?.['QvdFieldHeader'];\n if (headerFields && !Array.isArray(headerFields)) {\n headerFields = [headerFields];\n }\n\n // A field selection is checked here, before anything large is read, and the count it produces\n // is what the memory guard is charged for. Both halves matter: an unknown field name costs\n // nothing to discover at this point, and charging a two-column projection for twenty columns\n // would refuse reads that fit ten times over.\n const columnCount = Array.isArray(headerFields)\n ? selectFields(headerFields, this._requestedFields, this._path).length\n : 0;\n\n // SAFETY CHECK: enough memory to materialise the rows this call will produce. Runs here,\n // before any large read, so a file too big to hold is refused rather than read and refused.\n //\n // Two conditions gate it, and both exist so that a corrupt file keeps its accurate diagnosis\n // instead of being reported as an out-of-memory problem.\n //\n // The numbers have to be usable at all - a NaN or negative Offset would produce a nonsense\n // estimate - and they have to be consistent with the file on disk. The estimate is computed\n // from NoOfRecords, so a header that overstates it produces an enormous figure: a truncated\n // 3KB file claiming 900 million rows was refused for needing 530GB of RAM, when what it\n // actually needs is to be re-downloaded. Where the file contradicts its own header, this\n // declines to make a memory claim and lets the structural checks downstream say what is\n // really wrong.\n const headerNumbersUsable = [symbolTableLength, recordSize, totalRows].every(\n (value) => Number.isSafeInteger(value) && value >= 0,\n );\n\n if (headerNumbersUsable) {\n const {size: fileSize} = await fs.promises.stat(this._path);\n this._fileSize = fileSize;\n this._headerMatchesFile = headerEndIndex + symbolTableLength + totalRows * recordSize <= fileSize;\n }\n\n // Where the window really lands in this file, clamped to the rows it has.\n const resolved = headerNumbersUsable ? resolveWindow(window, totalRows) : {offset: 0, limit: 0};\n const windowRows = resolved.limit;\n\n if (headerNumbersUsable && this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolTableLength,\n windowRows,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n columnCount,\n this._materialisesRows,\n liveRows,\n );\n }\n\n if (window.offset === 0 && window.limit === null) {\n // Load entire file into memory (original behavior)\n // This is simple and fast for small to medium files\n this._buffer = await fs.promises.readFile(this._path);\n this._fileSize = this._buffer.length;\n this._bufferFirstRow = 0;\n this._emitProgress('read', 1, 1);\n return;\n }\n\n const rowsToLoad = windowRows;\n\n // SAFETY CHECK: Very large symbol tables are still blocked to prevent OOM. Every read that is\n // not a whole-file read reaches here, which is the point at which it still costs nothing to\n // refuse: the buffer below is allocated a few lines later and it always spans the entire\n // symbol table, whatever the window, because a stored index in any row can address any symbol.\n //\n // This deliberately does NOT distinguish `{offset: n, limit: m}` from `{offset: n}`. An\n // earlier revision of this work exempted the second, on the reasoning that a window bounded\n // only by an offset runs to the end of the file and so should be gated like a full read.\n // Measured on a 16,000-row fixture with a 153MB symbol table at a 288MB heap, that was wrong\n // in the uncatchable direction: `{offset: 15990, limit: 10}` was refused having allocated\n // nothing, at 53MB of RSS, while `{offset: 15990}` - the same ten rows - skipped this check,\n // passed the memory guard (whose symbol term is discounted by sqrt(windowRows/totalRows), so\n // it collapses for a small window), allocated and filled the whole 153MB buffer, and was only\n // then refused by the 50% ceiling in `_parseSymbolTable`. 207MB of RSS to read ten rows, and\n // inside a container sized below that it is a SIGKILL rather than an error.\n //\n // The exemption was also solving almost nothing. The band of symbol-table sizes where this\n // check refuses a read that a full load would have completed is bounded above by the memory\n // guard's own 6x symbol term: it is empty for any heap of 2GB or less, and 7MB wide at 4GB.\n validateSymbolTableSizeEarly(symbolTableLength, this._path);\n\n // Validate the header numbers before they are used to size an allocation. Without this,\n // a NaN or negative value reaches Buffer.alloc and surfaces as a raw Node RangeError.\n for (const [name, value] of [\n ['Offset', symbolTableLength],\n ['RecordByteSize', recordSize],\n ['NoOfRecords', totalRows],\n ]) {\n if (!Number.isSafeInteger(value) || Number(value) < 0) {\n throw new QvdCorruptedError(`Invalid header value: ${name}`, {\n name,\n value,\n file: this._path,\n stage: 'readData',\n });\n }\n }\n\n // Bytes of the index table the window skips, and bytes it covers.\n const skippedIndexBytes = resolved.offset * recordSize;\n const indexTableBytesToRead = rowsToLoad * recordSize;\n\n // The buffer holds the header, the symbol table, and the window's records - not the records\n // before them. A window deep in a large file therefore costs what the window costs: the taxi\n // fixture's last hundred rows are a 0.4MB read rather than a 38MB one.\n const totalBytesToRead = indexTableOffset + indexTableBytesToRead;\n\n // What the file has to contain for the window to exist in it, which is a different number as\n // soon as the offset is non-zero. Checking the buffer's size against the file would accept a\n // window that runs off the end.\n const fileBytesRequired = indexTableOffset + skippedIndexBytes + indexTableBytesToRead;\n\n // Now read the exact portion we need from the file\n const fd = await fs.promises.open(this._path, 'r');\n try {\n const {size: fileSize} = await fd.stat();\n this._fileSize = fileSize;\n\n // The buffer size is derived entirely from header values, which may not describe the\n // file on disk (truncated download, interrupted copy, file still being written, or a\n // deliberately crafted header). Reading past the end would otherwise leave the tail of\n // the buffer holding whatever memory the allocator handed out, and that memory is then\n // parsed as symbol and index data.\n if (fileBytesRequired > fileSize) {\n throw new QvdCorruptedError('The file is shorter than its header claims.', {\n file: this._path,\n fileSize,\n requiredBytes: fileBytesRequired,\n stage: 'readData',\n });\n }\n\n // Zero-filled rather than allocUnsafe: if any path ever fails to overwrite part of this\n // buffer, the result is zeros instead of leaked process memory.\n this._buffer = Buffer.alloc(totalBytesToRead);\n\n // The header and symbol table, from the front of the file.\n await this._readRange(fd, 0, indexTableOffset, 0, fileSize, totalBytesToRead);\n\n // The window's records, from wherever they are, into the buffer straight after the symbol\n // table. The two positions differ by exactly the bytes that were skipped.\n if (indexTableBytesToRead > 0) {\n await this._readRange(\n fd,\n indexTableOffset,\n indexTableBytesToRead,\n indexTableOffset + skippedIndexBytes,\n fileSize,\n fileBytesRequired,\n );\n }\n\n this._bufferFirstRow = resolved.offset;\n } finally {\n await fd.close();\n }\n\n this._emitProgress('read', 1, 1);\n }\n\n /**\n * Reads one byte range of the file into the buffer.\n *\n * Read in bounded chunks, checking bytesRead each time. A single fs.read call with a length of\n * 2^31 or more does not throw - it trips a C++ assertion and aborts the whole process, which no\n * try/catch can intercept.\n *\n * @param {import('fs/promises').FileHandle} fd The open file.\n * @param {number} bufferOffset Where in the buffer to write.\n * @param {number} byteCount How many bytes to read.\n * @param {number} filePosition Where in the file to read from.\n * @param {number} fileSize The file's size, for the error.\n * @param {number} requiredBytes Bytes the whole read needs, for the error.\n * @private\n */\n async _readRange(fd, bufferOffset, byteCount, filePosition, fileSize, requiredBytes) {\n assert(this._buffer, 'The read buffer has not been allocated.');\n\n let done = 0;\n\n while (done < byteCount) {\n const length = Math.min(READ_CHUNK_SIZE, byteCount - done);\n // @ts-ignore - Buffer type compatibility\n const {bytesRead} = await fd.read(this._buffer, bufferOffset + done, length, filePosition + done);\n\n if (bytesRead === 0) {\n throw new QvdCorruptedError('Unexpected end of file while reading QVD data.', {\n file: this._path,\n fileSize,\n // Two numbers, because they stopped being the same one when a window began reading two\n // ranges: `bytesRead` is how much of this range arrived, `filePosition` is where in the\n // file it gave up. Reporting the position under the name of the count made a windowed\n // read of a truncated file claim tens of megabytes had been read when a few hundred\n // bytes had.\n bytesRead: done,\n filePosition: filePosition + done,\n requiredBytes,\n stage: 'readData',\n });\n }\n\n done += bytesRead;\n }\n }\n\n /**\n * Parses the XML header of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n */\n async _parseHeader() {\n if (!this._buffer) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const HEADER_DELIMITER = '\\r\\n\\0';\n\n const headerBeginIndex = 0;\n const headerDelimiterIndex = this._buffer.indexOf(HEADER_DELIMITER, headerBeginIndex);\n\n // Check explicitly for -1 (not found) rather than using falsy check (!headerDelimiterIndex)\n // because indexOf() returns 0 when the delimiter is at position 0, which is a valid buffer index.\n // Using !0 would incorrectly treat position 0 as an error.\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n const headerBuffer = this._buffer.subarray(headerBeginIndex, headerEndIndex);\n\n /*\n * The following instruction parses the XML header into a JSON object. It is important to\n * note that the object is a plain JavaScript object and not an instance of representative\n * class. Hence, types are not casted, therefore all raw values are strings, and child nodes\n * that contain an array of objects are not represented directly as an array but as an object\n * with a property, named like the array item tag, that is an array of the actual objects. The\n * same applies to child nodes that contain a single object and the root node.\n *\n * The following XML representation of the QVD header for example...\n *\n * <QvdTableHeader>\n * ...\n * <Fields>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * </Fields>\n * </QvdTableHeader>\n *\n * ...is parsed into the following object:\n *\n * {\n * QvdTableHeader: {\n * ...,\n * Fields: {\n * QvdFieldHeader: [\n * { FieldName: 'Field1', ...},\n * { FieldName: 'Field2', ...}\n * ]\n * }\n * }\n * }\n */\n\n // Note: xml2js (via sax-js) does not support external entity resolution\n // by default, providing inherent protection against XXE attacks.\n this._header = await xml.parseStringPromise(headerBuffer.toString(), {explicitArray: false});\n\n if (!this._header) {\n throw new QvdParseError('The XML header could not be parsed.', {\n file: this._path,\n stage: 'parseHeader',\n });\n }\n\n validateHeaderStructure(this._header, this._path, 'parseHeader');\n\n /*\n * Because the three parts of the QVD file, header, symbol and index table, are seamlessly concatenated,\n * the end of the respective previous part is the beginning of the next part.\n */\n\n // A header with no field elements, validated here rather than at each use.\n //\n // Three places downstream normalise the field list with\n // `if (!Array.isArray(fields)) fields = [fields]`, which turns an absent `<Fields/>` into\n // `[undefined]` and then dereferences it - a bare TypeError from the middle of the reader\n // where readMetadata, which checks, reports the file as corrupt. Checking once, at the\n // point the header becomes available, means every path downstream can assume a field list.\n const fields = this._header['QvdTableHeader']?.['Fields']?.['QvdFieldHeader'];\n const fieldList = fields === undefined || fields === null ? [] : Array.isArray(fields) ? fields : [fields];\n\n if (fieldList.length === 0) {\n throw new QvdCorruptedError('The QVD file header declares no fields', {\n file: this._path,\n stage: 'parseHeader',\n });\n }\n\n // Counting the entries is not enough, because a `<QvdFieldHeader>` that is empty or holds\n // text instead of child elements parses to a string, and the normalisation above counts a\n // string as one perfectly good field. Nothing then reads it as anything but an object:\n // readMetadata reported `columns: [null], columnCount: 1` for an eight-column file, which is\n // indistinguishable from a real one-column QVD, while fromQvd refused the same file as\n // corrupt several steps later and blamed a symbol offset. That divergence is the thing the\n // metadata path is designed not to produce, so the entries are checked where they are counted.\n const malformedIndex = fieldList.findIndex(\n (field) => field === null || typeof field !== 'object' || Array.isArray(field),\n );\n\n if (malformedIndex !== -1) {\n throw new QvdCorruptedError('The QVD file header declares a field with no properties', {\n fieldIndex: malformedIndex,\n fieldCount: fieldList.length,\n file: this._path,\n stage: 'parseHeader',\n });\n }\n\n this._headerOffset = headerBeginIndex;\n this._symbolTableOffset = headerEndIndex;\n this._indexTableOffset = this._symbolTableOffset + parseInt(this._header['QvdTableHeader']['Offset'], 10);\n\n // The file's fields, and the caller's selection of them, resolved once and here.\n //\n // Everything downstream is positionally aligned by the order `selectFields` returns - the\n // symbol table, the decoded columns and `columns` are three arrays indexed by the same\n // position - so they have to come from one derivation rather than from three that happen to\n // agree. That is the same rule `fieldGeometry` exists to enforce for the bit layout, and the\n // consequence of breaking it is the same: a misalignment decodes cleanly and returns another\n // column's values with nothing thrown.\n // `fieldList` rather than re-normalising `fields`: the check above has already turned it into\n // an array and rejected the entries that are not field elements, so recomputing it here would\n // be a second derivation that happens to agree - which is the thing this caching exists to\n // stop, one scope up.\n this._allFields = fieldList;\n this._selectedFields = selectFields(this._allFields, this._requestedFields, this._path);\n }\n\n /**\n * Establishes the geometry of the index table, and validates it.\n *\n * Both passes over the index table - the symbol-usage analysis and the decode itself - need\n * exactly this, and they used to derive it separately with two copies of the same bit\n * unpacking. The copies are the reason the bias comment in the analysis pass warns so loudly\n * about keeping the sign in step with the other one: the two could drift, and #113 is what\n * that looks like when they do. There is one copy now.\n *\n * @param {QvdRowWindow} window The rows of interest, as file row indices.\n * @param {string} stage Stage name for any error raised here.\n * @return {{fields: Array<any>, recordSize: number, totalRows: number, rowsToLoad: number,\n * indexBuffer: Buffer}} The record geometry. `indexBuffer` starts at the window's first\n * record, so the decoder always counts from zero.\n * @private\n */\n _planIndexTable(window, stage) {\n if (!this._buffer || !this._header || !this._indexTableOffset || !this._selectedFields || !this._allFields) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage,\n },\n );\n }\n\n const allFields = this._allFields;\n const fields = this._selectedFields;\n\n // Size of a single row of the index table in bytes\n const recordSize = parseInt(this._header['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n const indexTableLength = parseInt(this._header['QvdTableHeader']['Length'], 10);\n\n // Resolved again rather than trusted. Callers already pass a window resolved against this\n // file, and resolving a resolved window returns it unchanged - but this is the function that\n // decides which bytes get decoded, and it should not be possible to reach it with a window\n // that runs off the end of the file.\n const {offset: firstRow, limit: rowsToLoad} = resolveWindow(window, totalRows);\n\n // Validate all index table metadata\n validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n this._indexTableOffset,\n this._buffer.length,\n rowsToLoad,\n this._path,\n this._fileSize,\n firstRow,\n this._bufferFirstRow,\n );\n\n // Where the window's first record sits in the buffer. The buffer's index table starts at file\n // row `_bufferFirstRow`, which is not row 0 whenever the read was windowed, so the two have to\n // be subtracted rather than assumed equal - getting this wrong returns whole rows of the wrong\n // data with nothing thrown.\n const bufferRecordStart = (firstRow - this._bufferFirstRow) * recordSize;\n const indexBuffer = this._buffer.subarray(\n this._indexTableOffset + bufferRecordStart,\n this._indexTableOffset + bufferRecordStart + rowsToLoad * recordSize,\n );\n\n // Validate BitOffset and BitWidth for every field in the file, selected or not, once.\n //\n // A projection must not make a corrupt file readable: if a field's bit metadata is nonsense,\n // `{fields: [...]}` that happens to leave it out should not quietly succeed where a full read\n // refuses. The check costs nothing - it reads header numbers - and keeping it whole means one\n // answer to \"does this file decode\".\n //\n // Once per reader, not once per window: the metadata is the header's and does not change\n // between chunks, so a 200-chunk iteration over 20 fields was re-parsing the same 4,000\n // strings. It stays *here*, after validateIndexTableMetadata, rather than moving up into\n // `_prepare` - that call is what establishes `recordSize` is usable, and validating bit\n // offsets against an unusable record size reports the wrong fault for the same file.\n if (!this._fieldBitMetadataValidated) {\n for (const field of allFields) {\n validateFieldBitMetadata(field, recordSize, this._path);\n }\n\n this._fieldBitMetadataValidated = true;\n }\n\n // The decoder indexes into the buffer without per-row bounds checks, which is only sound\n // because validateIndexTableMetadata has already established that the buffer holds the\n // window's `rowsToLoad` whole records: it requires the declared table to reach the end of the\n // window and the loaded buffer to hold it, and `indexBuffer` is exactly that span. The row\n // loop this replaced re-checked per record, which was dead code for the same reason.\n //\n // Stated as an assertion rather than dropped, because relaxing any of those checks later\n // would make the decode read past the end - where an out-of-range byte is undefined, the\n // arithmetic yields NaN, and the stored index silently becomes 0. Better to fail here.\n assert(\n rowsToLoad === 0 || recordSize === 0 || Math.floor(indexBuffer.length / recordSize) >= rowsToLoad,\n `The index table holds ${Math.floor(indexBuffer.length / (recordSize || 1))} whole records ` +\n `but ${rowsToLoad} were validated as present.`,\n );\n\n return {fields, recordSize, totalRows, rowsToLoad, indexBuffer};\n }\n\n /**\n * Analyzes the index table to determine which symbols are actually needed.\n * This is used for two-pass symbol filtering optimization.\n *\n * Only the selected fields are analysed. An unselected field's symbols are never parsed, so\n * there is nothing for a usage set to filter and decoding its column would be a pass over the\n * whole window for an answer nobody reads.\n *\n * @param {QvdRowWindow} window The rows to analyse.\n * @return {Promise<Array<Set<number>>>} One set of needed symbol indices per selected field, in\n * the same order `_parseSymbolTable` walks them.\n * @private\n */\n async _analyzeIndexTableSymbolUsage(window) {\n const {fields, recordSize, rowsToLoad, indexBuffer} = this._planIndexTable(window, 'analyzeIndexTableSymbolUsage');\n\n // One set per field, indexed by position rather than keyed by field name.\n //\n // By position because every other per-field array in this reader is - the symbol table, the\n // decoded columns and `columns` are all indexed the same way - and a name-keyed map is not\n // the same thing when a header declares two fields with one name. Qlik does not produce such\n // a file, but nothing here rejects one, and keying by name made the second field's set\n // overwrite the first's: the first field was then filtered against the wrong set, every\n // symbol it needed and the other did not read back as `undefined`, and nothing threw.\n // Measured on a copy of `lego/colors.qvd` with a field renamed to collide: a plain read gives\n // `'Black'` where a filtered read gives `undefined`. It only bites above\n // `symbolFilteringThreshold`, which is to say only on the large files where it is hardest to\n // notice - the #113 failure shape exactly.\n /** @type {Array<Set<number>>} */\n const symbolUsage = [];\n\n // One slice of one column at a time, reused across every slice and every field.\n //\n // Bounded rather than sized to the window, because the answer this pass produces is a *set*\n // of distinct indices: the union over slices is the same set the whole window would give, so\n // there is no reason to hold the window. Sizing it to the window made the pass allocate four\n // bytes per row of a read whose entire purpose might be to hold only a chunk at a time -\n // `iterate({limit: 20_000_000, chunkSize: 1000})` allocated 80MB here while the memory guard\n // had been told the read holds 2,000 rows. A cgroup counts that 80MB and answers with a\n // SIGKILL, which is the uncatchable direction.\n //\n // Capping it is the fix rather than telling the guard about it: an allocation the guard has\n // to be told about is one more figure that can drift from what the code does, and this one\n // did not need to exist.\n const sliceRows = Math.min(rowsToLoad, ANALYSIS_SLICE_ROWS);\n const column = new Int32Array(sliceRows);\n\n fields.forEach((/** @type {any} */ field, /** @type {number} */ position) => {\n this._throwIfAborted();\n\n const needed = new Set();\n symbolUsage[position] = needed;\n\n // The bias is applied inside the decoder, which is the same call the parse pass makes.\n // When these were two separate unpackings, a sign difference here would have recorded the\n // wrong symbols as needed and every affected cell would have read back as undefined -\n // silently, because nothing throws on an index that addresses no symbol.\n const bitOffset = parseInt(field['BitOffset'], 10);\n const bitWidth = parseInt(field['BitWidth'], 10);\n const bias = parseInt(field['Bias'], 10);\n\n for (let first = 0; first < rowsToLoad; first += sliceRows) {\n const count = Math.min(sliceRows, rowsToLoad - first);\n\n // The decoder always counts records from the start of the buffer it is given, so a slice\n // is a matter of where that buffer starts - the same property that makes a row window\n // cheap in `_parseIndexTable`.\n decodeIndexColumn(\n first === 0 ? indexBuffer : indexBuffer.subarray(first * recordSize),\n recordSize,\n count,\n bitOffset,\n bitWidth,\n bias,\n column,\n );\n\n for (let row = 0; row < count; row++) {\n // Negative indices denote NULL and reference no symbol, so they never need to be kept.\n if (column[row] >= 0) {\n needed.add(column[row]);\n }\n }\n }\n\n this._emitProgress('symbol-analysis', position + 1, fields.length);\n });\n\n return symbolUsage;\n }\n\n /**\n * Parses the symbol table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * A field the caller did not select is skipped whole. Its symbol area is neither scanned nor\n * parsed - the per-field `Offset` and `Length` say exactly where it is, so there is nothing to\n * walk past - and that is where field selection earns its keep. The index decode is cheap by\n * comparison; parsing symbols is not.\n *\n * @param {Array<Set<number>>|null} symbolsToKeep Optional set of symbol indices to keep per\n * selected field, indexed by position. If provided, only these symbols will be parsed\n * (two-pass filtering optimization).\n * @param {number} rowsToLoad Rows the read covers, for memory estimation.\n * @param {{rows: number, perChunk: number}|null} [liveRows=null] Rows held at one instant when\n * that is fewer than the window covers - see `_prepare`.\n */\n async _parseSymbolTable(symbolsToKeep = null, rowsToLoad = 0, liveRows = null) {\n if (\n !this._buffer ||\n !this._header ||\n !this._symbolTableOffset ||\n !this._indexTableOffset ||\n !this._selectedFields ||\n !this._allFields\n ) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseSymbolTable',\n },\n );\n }\n\n const allFields = this._allFields;\n const fields = this._selectedFields;\n const symbolBuffer = this._buffer.subarray(this._symbolTableOffset, this._indexTableOffset);\n const symbolTableSize = symbolBuffer.length;\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n\n // SAFETY CHECK 1: Absolute ceiling to prevent pathological cases\n // Phase 2.5 optimization allows much larger symbol tables when using maxRows,\n // but we still need an absolute maximum to prevent truly extreme cases\n validateSymbolTableSize(symbolTableSize, this._path, totalRows);\n\n // SAFETY CHECK 2: Dynamic memory validation, now against the symbol table's real size rather\n // than the size its header declared. _readData already ran this check before reading\n // anything; this is the more accurate second look, and the two agree on a well-formed file.\n //\n // Skipped on the same condition as the early one. This is the call that mattered: the\n // structural checks that identify a truncated file run in _parseIndexTable, after this, so\n // an estimate built on an inflated NoOfRecords would report a memory problem for a file\n // whose real problem is that it is short.\n if (this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolTableSize,\n rowsToLoad,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n fields.length,\n this._materialisesRows,\n liveRows,\n );\n }\n\n // WARNING ZONE: Large files without maxRows parameter\n // Educate users about best practices but don't block\n warnLargeSymbolTable(symbolTableSize, rowsToLoad, totalRows, fields.length, this._materialisesRows);\n\n /*\n * The symbol table is a contiguous byte array that contains all possible symbols/values of all fields/columns.\n * The symbols/values of one field are stored consecutively in the same order as the fields/columns are defined\n * in the header. The length of the symbol area as well as it's offset, relativ to the begin of the symbol\n * table, are also defined in the header.\n */\n\n // Validate every field's metadata, selected or not, to prevent buffer overflow attacks.\n //\n // Whole-file rather than whole-selection for the same reason the bit metadata is: a\n // projection must not turn a file a full read refuses into one it accepts. Reading header\n // numbers costs nothing next to parsing the symbols they describe.\n for (const field of allFields) {\n validateFieldMetadata(field, symbolBuffer.length, this._path);\n }\n\n // Parse all possible symbols of each *selected* field/column\n // Phase 2.5 optimization: Skip parsing entirely for symbols we don't need\n this._symbolTable = fields.map((/** @type {any} */ field, /** @type {number} */ position) => {\n this._throwIfAborted();\n\n const symbolsOffset = parseInt(field['Offset'], 10); // Offset of the column's symbol area in the symbol table\n const symbolsLength = parseInt(field['Length'], 10); // Length of the column's symbol area in the symbol table\n\n const fieldName = field['FieldName'];\n // By position, matching how `_analyzeIndexTableSymbolUsage` built it. Both walk\n // `this._selectedFields`, so position is the one key that cannot collide.\n const neededSymbols = symbolsToKeep ? symbolsToKeep[position] : null;\n const filteringEnabled = neededSymbols !== null;\n\n const symbols = [];\n let symbolIndex = 0; // Track current symbol index as we parse\n\n // Parse all possible values of the current field/column\n for (let pointer = symbolsOffset; pointer < symbolsOffset + symbolsLength; pointer++) {\n // Each stored symbol consists of a type byte and the actual value, which length depends on the type\n const typeByte = symbolBuffer[pointer++];\n\n // Check if we should keep this symbol (filtering mode)\n const shouldKeepSymbol = !filteringEnabled || !!(neededSymbols && neededSymbols.has(symbolIndex));\n\n // Use utility function to parse or skip symbol\n const {symbol, bytesRead} = parseSymbol(\n typeByte,\n symbolBuffer,\n pointer,\n symbolBuffer.length,\n fieldName,\n this._path,\n shouldKeepSymbol,\n );\n\n symbols.push(symbol);\n pointer += bytesRead - 1; // -1 because the loop will increment\n symbolIndex++;\n }\n\n this._emitProgress('symbol-table', position + 1, fields.length);\n\n return symbols;\n // @ts-ignore - Symbol table type assignment\n });\n }\n\n /**\n * Parses the bit stuffed index table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * One `Int32Array` per field, filled by `decodeIndexColumn`, replacing an array per row filled\n * a bit at a time. The old route, per row, built an `Int32Array` of the record's bytes,\n * concatenated a binary string of `recordSize * 8` characters, split it into a character\n * array, reversed that, and mapped it to one number per *bit*; then per cell it sliced the\n * result again and summed `bit * Math.pow(2, index)`. Several arrays the length of the record\n * in bits, built and discarded for every row.\n *\n * Column-major is what makes the decode tight: a field's bit offset, width and bias are the\n * same for every row, so they are hoisted out of the loop and the inner loop does arithmetic\n * into a typed array and nothing else. Rows are assembled later, once, in `load()`.\n *\n * The window is what makes chunked iteration cheap: `decodeIndexColumn` walks records by\n * `base += recordSize`, so decoding rows k to k+n is a question of where the buffer slice starts\n * and how many iterations run. Nothing about the decoder changed to support it.\n *\n * @param {QvdRowWindow} window The rows to decode.\n */\n async _parseIndexTable(window) {\n const {fields, recordSize, rowsToLoad, indexBuffer} = this._planIndexTable(window, 'parseIndexTable');\n\n this._rowsDecoded = rowsToLoad;\n this._indexColumns = fields.map((/** @type {any} */ field, /** @type {number} */ position) => {\n this._throwIfAborted();\n\n const column = decodeIndexColumn(\n indexBuffer,\n recordSize,\n rowsToLoad,\n parseInt(field['BitOffset'], 10),\n parseInt(field['BitWidth'], 10),\n parseInt(field['Bias'], 10),\n new Int32Array(rowsToLoad),\n );\n\n this._emitProgress('index-table', position + 1, fields.length);\n\n return column;\n });\n }\n\n /**\n * Reads the file's schema and header metadata, without touching the symbol or index tables.\n *\n * Constant cost in the size of the file. `fromQvd(path, {maxRows: 0})` is not the same thing\n * and never was: the lazy path reads `headerEnd + symbolTableLength + rowsToLoad * recordSize`\n * bytes, so it still pulls the entire symbol table - 0.4MB on the taxi fixture, but hundreds\n * of megabytes on a high-cardinality file, and it has to be parsed as well as read.\n *\n * The memory check is deliberately not run for this. It sizes the rows a call will\n * materialise, and this materialises none; applying it would let a file too large to load\n * refuse to say what is in it.\n *\n * @return {Promise<import('./QvdDataFrame.js').QvdFileMetadata>} The file's schema and header.\n */\n async loadMetadata() {\n await this._readData({offset: 0, limit: null}, true);\n\n this._emitProgress('header', 0, 1);\n await this._parseHeader();\n this._emitProgress('header', 1, 1);\n this._throwIfAborted();\n\n assert(this._header, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n\n let fields = header['Fields']?.['QvdFieldHeader'] ?? [];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n // A header that declares no fields is a broken header, not a table with no columns, and\n // reporting `columnCount: 0` for it would be the same kind of plausible-but-wrong answer\n // this library keeps having to design against. Loading such a file throws too.\n if (fields.length === 0) {\n throw new QvdCorruptedError('The QVD file header declares no fields', {\n file: this._path,\n stage: 'readMetadata',\n });\n }\n\n const columns = fields.map((/** @type {any} */ field) => field['FieldName']);\n const rowCount = parseInt(header['NoOfRecords'], 10);\n\n // The same rule a load applies, through the same function. Coercing an unusable value to\n // zero here instead would report a damaged 606-row file as empty, and `rowCount` is exactly\n // what a caller is expected to branch on.\n validateRecordCount(rowCount, this._path, 'readMetadata');\n\n // An empty frame carrying the same header, so the camelCase mappings live in one place\n // rather than being spelled out a second time here and drifting from the ones a loaded\n // frame reports.\n const shape = new QvdDataFrame([], columns, header, {\n symbolTableBytes: parseInt(header['Offset'], 10),\n totalRows: rowCount,\n rowsLoaded: 0,\n symbolFiltering: false,\n symbolsKept: null,\n });\n\n return {\n columns,\n rowCount,\n columnCount: columns.length,\n fields: columns.map((/** @type {string} */ name) => shape.getFieldMetadata(name)),\n fileMetadata: shape.fileMetadata,\n metadata: header,\n };\n }\n\n /**\n * Loads the QVD file into memory and parses it.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} [window]\n * The rows to load. A number or null means what it always meant - the first N rows, or all of\n * them - and `{offset, limit}` is the same thing said more precisely, so `5` and\n * `{offset: 0, limit: 5}` are one read. `maxRows` is accepted as a second name for `limit`.\n * @throws {QvdValidationError} If the window is not a non-negative integer, null, or a valid\n * `{offset, limit}` object.\n * @return {Promise<QvdDataFrame>} The loaded QVD file.\n */\n async load(window = null) {\n const rows = normaliseWindow(window, this._path);\n const prepared = await this._prepare(rows);\n\n await this._parseIndexTable({offset: prepared.offset, limit: prepared.rowsAvailable});\n\n const data = this._buildRows(prepared.resolvedByField, 0, prepared.rowsAvailable);\n\n return new QvdDataFrame(data, prepared.columns, prepared.metadata, {\n ...prepared.loadStats,\n rowsLoaded: data.length,\n });\n }\n\n /**\n * Reads the file as columns, without ever materialising rows.\n *\n * Shares every step with `load()` up to the point where rows would be built - see `_prepare`.\n * What it keeps instead is what the decoder already produced: one `Int32Array` of stored\n * indices per field, and one resolved value per distinct symbol. On the 1.7M x 20 taxi\n * fixture that is 38.6 MiB against the 352.8 MiB `data` retains, because a column costs four\n * bytes per row rather than a boxed value per cell, and the symbols are a few thousand\n * entries shared across every row that uses them.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} [window]\n * The rows to decode, in the same spellings `load()` accepts.\n * @return {Promise<import('./QvdColumnTable.js').QvdColumnTable>} The decoded columns.\n */\n async loadColumnar(window = null) {\n const rows = normaliseWindow(window, this._path);\n const prepared = await this._prepare(rows);\n\n await this._parseIndexTable({offset: prepared.offset, limit: prepared.rowsAvailable});\n\n const {QvdColumnTable} = await import('./QvdColumnTable.js');\n\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n return new QvdColumnTable({\n columns: prepared.columns,\n codesByField: this._indexColumns,\n symbolsByField: prepared.resolvedByField,\n rowCount: this._rowsDecoded,\n metadata: prepared.metadata,\n loadStats: {...prepared.loadStats, rowsLoaded: this._rowsDecoded},\n });\n }\n\n /**\n * Yields the window as data frames of at most `chunkSize` rows.\n *\n * The file is opened, read and parsed **once**; only the index decode and the row building\n * happen per chunk. That is the whole reason this exists as a method rather than as a loop of\n * `load({offset, limit})` calls at the call site: the symbol table has to be parsed in full\n * whatever the chunk size - a stored index in the last chunk can address the first symbol -\n * and re-parsing it per chunk is what makes the obvious implementation cost more than a plain\n * load rather than less. PyQvd's chunked read does re-read it, and the comment on #140 records\n * that as a limitation rather than a design.\n *\n * What it bounds is row materialisation, which is what actually dominates a large read's heap.\n * Two chunks of rows are alive at a time, not one - `for await` keeps the yielded frame\n * reachable while this generator builds the next - which is why `liveRows` below is\n * `chunkSize * 2`, and why the heap it needs is twice what one chunk suggests.\n *\n * A window covering no rows yields nothing at all, rather than one empty frame - so\n * `for await` over an exhausted offset does nothing, which is what a paging loop wants.\n *\n * @param {number|null|{offset?: number, limit?: number|null, maxRows?: number|null}} window\n * The rows to cover, in the same spellings `load()` accepts.\n * @param {number} chunkSize Rows per frame. Must be a positive integer.\n * @return {AsyncGenerator<QvdDataFrame>} The chunks, in order.\n */\n async *iterateRows(window, chunkSize) {\n if (typeof chunkSize !== 'number' || !Number.isInteger(chunkSize) || chunkSize <= 0) {\n throw new QvdValidationError('chunkSize must be a positive integer', {\n provided: chunkSize,\n type: typeof chunkSize,\n file: this._path,\n });\n }\n\n // The memory guard sizes what is live at once, and from here that is *two* chunks rather than\n // the whole window. Passed into `_prepare` rather than stored on the reader, so it cannot\n // outlive this call: while it was an instance field, a reader used for `load()` after an\n // iteration would have the guard size two chunks for a read that materialises every row -\n // failing open, which is the uncatchable direction. No caller could reach that today, but\n // nothing said the reader was single-use either, and `QvdFileReader` is a documented export.\n // It is paired with the chunk size it came from so a refusal can recommend a chunk size rather\n // than a live-row count the caller has no knob for.\n //\n // Two, not one, because `for await (const chunk of ...)` keeps the yielded frame reachable\n // while the generator computes the next one - that is the async-iteration protocol, not\n // something this code can arrange away. Charging one chunk was measured and it was wrong in\n // the dangerous direction: on the 1.7M x 20 taxi fixture with `chunkSize: 500_000`, a read\n // that needs a 214MB heap was admitted at 170MB and the process aborted with a V8 heap-limit\n // abort - uncatchable, which is the exact failure the guard exists to prevent. Against the\n // measured minimum heap at four chunk sizes the two-chunk figure sits at 1.00 to 1.14x, never\n // below; the one-chunk figure sat at 0.53 to 0.61x.\n //\n // `estimateMemoryUsage` caps this at the window, so a window smaller than two chunks is still\n // charged only for itself.\n const liveRows = {rows: chunkSize * 2, perChunk: 2};\n\n const rows = normaliseWindow(window, this._path);\n const prepared = await this._prepare(rows, liveRows);\n\n for (let done = 0; done < prepared.rowsAvailable; done += chunkSize) {\n this._throwIfAborted();\n\n const count = Math.min(chunkSize, prepared.rowsAvailable - done);\n const offset = prepared.offset + done;\n\n await this._parseIndexTable({offset, limit: count});\n\n const data = this._buildRows(prepared.resolvedByField, done, prepared.rowsAvailable);\n\n yield new QvdDataFrame(data, prepared.columns, prepared.metadata, {\n ...prepared.loadStats,\n offset,\n rowsLoaded: data.length,\n });\n }\n }\n\n /**\n * Reads the file and resolves its symbols, stopping short of decoding any rows.\n *\n * Everything `load()`, `loadColumnar()` and `iterateRows()` have in common, which is everything\n * that depends on the file rather than on the window. Two read paths for one binary format is\n * the drift risk #113 is the standing example of - a stored index resolved one way here and\n * another way there returns plausible wrong values and throws nothing - so there is one path,\n * and the entry points differ only in what they do with what it returns and how many rows they\n * ask for at a time.\n *\n * @param {QvdRowWindow} window The rows the read covers.\n * @param {{rows: number, perChunk: number}|null} [liveRows] Rows held at one instant when that\n * is fewer than the window covers, and how many of them one row of the caller's chunk size\n * accounts for. Only `iterateRows` passes it; every other read holds what it covers.\n * @return {Promise<{columns: Array<string>, metadata: any, loadStats: any,\n * resolvedByField: Array<Array<any>>, rowsAvailable: number, offset: number}>} The parsed\n * file, with the window as it resolved against it.\n * @private\n */\n async _prepare(window, liveRows = null) {\n this._throwIfAborted();\n\n await this._readData(window, false, liveRows);\n\n this._emitProgress('header', 0, 1);\n await this._parseHeader();\n this._emitProgress('header', 1, 1);\n this._throwIfAborted();\n\n assert(this._header, 'The QVD file header has not been parsed.');\n\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n const symbolTableLength = parseInt(this._header['QvdTableHeader']['Offset'], 10);\n\n // Where this window lands in this file. Resolved through the same function `_readData` used,\n // so the rows that were read and the rows that will be decoded cannot disagree.\n const resolved = resolveWindow(window, totalRows);\n const rowsAvailable = resolved.limit;\n\n // Determine if we should use two-pass symbol filtering\n // This optimization is beneficial for large symbol tables with limited row access\n let symbolsToKeep = null;\n let symbolsKept = null;\n\n // Any window that does not cover the whole file is a candidate, which now includes one that\n // is bounded by its offset rather than by its limit.\n if (window.limit !== null || window.offset > 0) {\n // Use two-pass filtering for symbol tables above the threshold when loading limited rows.\n // The threshold is an option rather than a constant so this path can be exercised with a\n // small fixture: it is the most intricate code in the reader, and the only files large\n // enough to reach the 50MB default are ones no repository should be carrying around.\n if (symbolTableLength > this._symbolFilteringThreshold) {\n // Pass 1: Analyze which symbols are actually needed\n symbolsToKeep = await this._analyzeIndexTableSymbolUsage({offset: resolved.offset, limit: rowsAvailable});\n\n // Recorded rather than logged. This used to be a console.log, which a library has no\n // business emitting: callers could not silence it, and it was the only way to find out\n // whether filtering had happened. It is now reported through QvdDataFrame.loadStats,\n // which callers can inspect - and tests can assert on deterministically, where the\n // previous test measured a heapUsed delta and failed on GC timing instead.\n symbolsKept = symbolsToKeep.reduce((sum, set) => sum + set.size, 0);\n }\n }\n\n // Pass 2: Parse symbol table (with filtering if enabled)\n await this._parseSymbolTable(symbolsToKeep, rowsAvailable, liveRows);\n\n assert(this._symbolTable, 'The QVD file symbol table has not been parsed.');\n this._throwIfAborted();\n\n // Resolve each field's symbols once rather than once per cell.\n //\n // A stored index addresses the same symbol in every row, so the work below - the symbol\n // lookup, toPrimaryValue(), and the numeric-string coercion - depends only on the index.\n // Doing it inside the row loop repeated it 34 million times on the taxi fixture for a\n // symbol table of a few thousand entries.\n //\n // A filtered-out symbol is stored as null by the two-pass path, and an index past the end\n // of the array reads as undefined. Both resolve to undefined here, which is what the\n // per-cell version produced through optional chaining.\n const resolvedByField = this._symbolTable.map((symbols) => {\n const resolved = new Array(symbols.length);\n\n for (let index = 0; index < symbols.length; index++) {\n const value = symbols[index]?.toPrimaryValue();\n\n // Number('') and Number(' ') are 0, which silently turned every blank cell Qlik\n // stored into the number zero - indistinguishable from a real zero, and persisted as\n // one on the next write. Blank strings are never numeric, so exclude them.\n resolved[index] =\n typeof value === 'string' && value.trim() !== '' && !isNaN(Number(value)) ? Number(value) : value;\n }\n\n return resolved;\n });\n\n assert(this._selectedFields, 'The QVD file fields have not been resolved.');\n\n const columns = this._selectedFields.map((/** @type {any} */ field) => field['FieldName']);\n\n // The complete header metadata, describing the *file* rather than this read of it.\n //\n // Not narrowed to the selected fields, and not adjusted for the window. `NoOfRecords` has\n // always been the file's row count rather than the number loaded - that is what `loadStats`\n // is for - and `select()` has always passed the whole header through to the frame it returns,\n // so narrowing here would give one answer for a projection made at load time and another for\n // the same projection made afterwards.\n const metadata = this._header['QvdTableHeader'];\n\n /** @type {import('./QvdDataFrame.js').QvdLoadStats} */\n const loadStats = {\n symbolTableBytes: symbolTableLength,\n totalRows,\n rowsLoaded: 0,\n offset: resolved.offset,\n symbolFiltering: symbolsToKeep !== null,\n symbolsKept,\n };\n\n return {columns, metadata, loadStats, resolvedByField, rowsAvailable, offset: resolved.offset};\n }\n\n /**\n * Builds rows from the columns currently decoded.\n *\n * `data` stays eager: of the four ways this library is used - a full read, a preview already\n * bounded by a limit, writing an array out, and reading metadata - not one is helped by\n * materialising a row only when it is touched, and a lazy accessor would cost a proxy, a cache\n * and mutation semantics to serve none of them. A caller who wants columns without paying for\n * rows uses `QvdColumnTable`, which stops before this loop.\n *\n * @param {Array<Array<any>>} resolvedByField One resolved value per distinct symbol, per field.\n * @param {number} progressBase Rows already delivered before this call, so that progress over a\n * chunked iteration counts the whole window rather than restarting at every chunk.\n * @param {number} progressTotal Rows the whole window covers.\n * @return {Array<Array<any>>} The rows.\n * @private\n */\n _buildRows(resolvedByField, progressBase, progressTotal) {\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n const indexColumns = this._indexColumns;\n const fieldCount = indexColumns.length;\n const rowCount = this._rowsDecoded;\n const data = new Array(rowCount);\n\n // Report about once per percent of the window, as the writer does, and at least once at the\n // end. Checking the abort signal on the same tick keeps a cancelled 20-million-row load from\n // running to completion before it notices.\n const reportInterval = Math.max(1, Math.floor(progressTotal / 100));\n\n for (let row = 0; row < rowCount; row++) {\n const values = new Array(fieldCount);\n\n for (let field = 0; field < fieldCount; field++) {\n const symbolIndex = indexColumns[field][row];\n\n // A negative index is how a bias of -2 encodes NULL: stored index 0 means NULL, and\n // real symbols start at 2. It addresses no symbol.\n values[field] = symbolIndex < 0 ? null : resolvedByField[field][symbolIndex];\n }\n\n data[row] = values;\n\n if ((progressBase + row + 1) % reportInterval === 0 || row + 1 === rowCount) {\n this._throwIfAborted();\n this._emitProgress('rows', progressBase + row + 1, progressTotal);\n }\n }\n\n return data;\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {metadataOptionsFrom, readerOptionsFrom, windowFrom} from './util/readOptions.js';\n\n/**\n * @typedef {Object} QvdNumberFormat\n * @property {string} Type - Number format type\n * @property {string} nDec - Number of decimals\n * @property {string} UseThou - Use thousands separator\n * @property {string} Fmt - Format string\n * @property {string} Dec - Decimal separator\n * @property {string} Thou - Thousands separator\n */\n\n/**\n * @typedef {Object} QvdFieldHeader\n * @property {string} FieldName - The name of the field\n * @property {string|number} [BitOffset] - The bit offset\n * @property {string|number} [BitWidth] - The bit width\n * @property {string|number} [Bias] - The bias value\n * @property {string|number} [NoOfSymbols] - Number of symbols\n * @property {string|number} [Offset] - The offset\n * @property {string|number} [Length] - The length\n * @property {string} [Comment] - Field comment\n * @property {QvdNumberFormat|string} [NumberFormat] - Number format\n * @property {Object|string} [Tags] - Field tags\n */\n\n/**\n * @typedef {Object} QvdFields\n * @property {QvdFieldHeader|QvdFieldHeader[]} QvdFieldHeader - Field header(s)\n */\n\n/**\n * @typedef {Object} QvdMetadata\n * @property {string|number} [QvBuildNo] - QlikView build number\n * @property {string} [CreatorDoc] - Creator document\n * @property {string} [CreateUtcTime] - Creation UTC time\n * @property {string} [SourceCreateUtcTime] - Source creation UTC time\n * @property {string} [SourceFileUtcTime] - Source file UTC time\n * @property {string|number} [SourceFileSize] - Source file size\n * @property {string} [StaleUtcTime] - Stale UTC time\n * @property {string} [TableName] - Table name\n * @property {string|number} [NoOfRecords] - Number of records\n * @property {string|number} [RecordByteSize] - Record byte size\n * @property {string|number} [Offset] - Offset\n * @property {string|number} [Length] - Length\n * @property {string} [Compression] - Compression type\n * @property {string} [Comment] - Comment\n * @property {string} [EncryptionInfo] - Encryption info\n * @property {string} [TableTags] - Table tags\n * @property {string} [ProfilingData] - Profiling data\n * @property {Object|string} [Lineage] - Lineage\n * @property {QvdFields} [Fields] - Fields information\n */\n\n/**\n * A QVD file's schema and header, read without its data.\n *\n * @typedef {Object} QvdFileMetadata\n * @property {Array<string>} columns Field names, in file order.\n * @property {number} rowCount Rows the file declares in its header. Note that this is the\n * file's row count, not a number of rows loaded - nothing was loaded.\n * @property {number} columnCount Number of fields.\n * @property {Array<Object|null>} fields Per-field metadata, in the same shape and order that\n * `getFieldMetadata()` returns for a loaded frame.\n * @property {Object} fileMetadata File-level metadata, in the same shape as the `fileMetadata`\n * accessor on a loaded frame.\n * @property {QvdMetadata} metadata The raw `QvdTableHeader`, as `metadata` gives it.\n */\n\n/**\n * Statistics describing the read that produced a data frame.\n *\n * @typedef {Object} QvdLoadStats\n * @property {number} symbolTableBytes Size of the file's symbol table, in bytes.\n * @property {number} totalRows Rows the file declares in its header.\n * @property {number} rowsLoaded Rows actually materialised.\n * @property {number} [offset] File row the first materialised row came from: zero unless the read\n * asked for a window, the window's start when it did, and under `iterate()` the chunk's own\n * position - which is the only way a chunk can say where in the file it sits. An offset past the\n * end of the file reports the clamped value, so it equals `totalRows` for a window that caught\n * no rows.\n * @property {boolean} symbolFiltering Whether the two-pass symbol-filtering path was used.\n * @property {number|null} symbolsKept Symbols retained by that path, or null when it did not run.\n */\n\n/**\n * Represents a loaded QVD file.\n */\nexport class QvdDataFrame {\n /**\n * Represents the data frame stored inside a QVD file.\n * @param {Array<Array<any>>} data The data of the data frame.\n * @param {Array<string>} columns The columns of the data frame.\n * @param {QvdMetadata|null} metadata The metadata from the QVD file header (optional).\n * @param {QvdLoadStats|null} loadStats Statistics about the read (optional).\n */\n constructor(data, columns, metadata = null, loadStats = null) {\n this._data = data;\n this._columns = columns;\n this._metadata = metadata;\n this._loadStats = loadStats;\n }\n\n /**\n * Returns the data of the data frame.\n */\n get data() {\n return this._data;\n }\n\n /**\n * Returns the columns of the data frame.\n */\n get columns() {\n return this._columns;\n }\n\n /**\n * Returns the shape of the data frame.\n */\n get shape() {\n return [this._data.length, this._columns.length];\n }\n\n /**\n * Returns the complete metadata object from the QVD file header.\n * @return {Object|null} The complete metadata object or null if not available.\n */\n get metadata() {\n return this._metadata;\n }\n\n /**\n * Returns statistics about the read that produced this data frame.\n *\n * Carried by every frame that came from a file - `fromQvd()`, and each chunk `iterate()` yields,\n * which is how a chunk reports its `offset`. `fromDict()`, `head()`, `tail()`, `rows()` and\n * `select()` describe no particular read and report null rather than a stale figure.\n *\n * The main use is confirming that a lazy load actually filtered the symbol table:\n * `symbolFiltering` says whether the two-pass path ran, and `symbolsKept` how many symbols\n * survived it. Note that a bounded read does not filter on its own - the two-pass path engages\n * only above `symbolFilteringThreshold`, so on a file below it this reports false and every\n * symbol was parsed however few rows were asked for.\n *\n * @return {QvdLoadStats|null} Load statistics, or null if this frame did not come from a file.\n */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * Returns file-level metadata from the QVD header.\n * @return {Object} File-level metadata properties.\n */\n get fileMetadata() {\n if (!this._metadata) {\n return {};\n }\n\n const header = this._metadata;\n return {\n qvBuildNo: header.QvBuildNo,\n creatorDoc: header.CreatorDoc,\n createUtcTime: header.CreateUtcTime,\n sourceCreateUtcTime: header.SourceCreateUtcTime,\n sourceFileUtcTime: header.SourceFileUtcTime,\n sourceFileSize: header.SourceFileSize,\n staleUtcTime: header.StaleUtcTime,\n tableName: header.TableName,\n noOfRecords: header.NoOfRecords,\n recordByteSize: header.RecordByteSize,\n offset: header.Offset,\n length: header.Length,\n compression: header.Compression,\n comment: header.Comment,\n encryptionInfo: header.EncryptionInfo,\n tableTags: header.TableTags,\n profilingData: header.ProfilingData,\n lineage: header.Lineage,\n };\n }\n\n /**\n * Returns field-level metadata for a specific field/column.\n * @param {string} fieldName The name of the field.\n * @return {Object|null} Field metadata or null if field not found.\n */\n getFieldMetadata(fieldName) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return null;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const field = fields.find((f) => f.FieldName === fieldName);\n if (!field) {\n return null;\n }\n\n return {\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n };\n }\n\n /**\n * Returns field-level metadata for all fields.\n * @return {Array<Object>} Array of field metadata objects.\n */\n getAllFieldMetadata() {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return [];\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n return fields.map((field) => ({\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n }));\n }\n\n /**\n * @typedef {Object} FileMetadataUpdate\n * @property {string|number} [qvBuildNo] - QlikView build number\n * @property {string} [creatorDoc] - Creator document\n * @property {string} [createUtcTime] - Creation UTC time\n * @property {string} [sourceCreateUtcTime] - Source creation UTC time\n * @property {string} [sourceFileUtcTime] - Source file UTC time\n * @property {string|number} [sourceFileSize] - Source file size\n * @property {string} [staleUtcTime] - Stale UTC time\n * @property {string} [tableName] - Table name\n * @property {string} [compression] - Compression type\n * @property {string} [comment] - Comment\n * @property {string} [encryptionInfo] - Encryption info\n * @property {string} [tableTags] - Table tags\n * @property {string} [profilingData] - Profiling data\n * @property {Object|string} [lineage] - Lineage\n */\n\n /**\n * Sets modifiable file-level metadata. Immutable properties related to data storage are ignored.\n * @param {FileMetadataUpdate} metadata Object containing metadata properties to update.\n */\n setFileMetadata(metadata) {\n if (!this._metadata) {\n // Initialize metadata structure if it doesn't exist\n this._metadata = {\n QvBuildNo: 50667,\n CreatorDoc: '',\n CreateUtcTime: '',\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: '',\n Fields: {\n QvdFieldHeader: this._columns.map((column) => ({\n FieldName: column,\n BitOffset: 0,\n BitWidth: 0,\n Bias: 0,\n NoOfSymbols: 0,\n Offset: 0,\n Length: 0,\n Comment: '',\n NumberFormat: {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: {},\n })),\n },\n NoOfRecords: 0,\n RecordByteSize: 0,\n Offset: 0,\n Length: 0,\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {},\n };\n }\n\n // Only allow modification of certain fields (not Offset, Length, NoOfRecords, RecordByteSize)\n const modifiableFields = [\n 'qvBuildNo',\n 'creatorDoc',\n 'createUtcTime',\n 'sourceCreateUtcTime',\n 'sourceFileUtcTime',\n 'sourceFileSize',\n 'staleUtcTime',\n 'tableName',\n 'compression',\n 'comment',\n 'encryptionInfo',\n 'tableTags',\n 'profilingData',\n 'lineage',\n ];\n\n // Map camelCase to XML property names\n const fieldMapping = {\n qvBuildNo: 'QvBuildNo',\n creatorDoc: 'CreatorDoc',\n createUtcTime: 'CreateUtcTime',\n sourceCreateUtcTime: 'SourceCreateUtcTime',\n sourceFileUtcTime: 'SourceFileUtcTime',\n sourceFileSize: 'SourceFileSize',\n staleUtcTime: 'StaleUtcTime',\n tableName: 'TableName',\n compression: 'Compression',\n comment: 'Comment',\n encryptionInfo: 'EncryptionInfo',\n tableTags: 'TableTags',\n profilingData: 'ProfilingData',\n lineage: 'Lineage',\n };\n\n modifiableFields.forEach((field) => {\n // @ts-ignore - Dynamic property access for metadata mapping\n if (metadata[field] !== undefined) {\n // @ts-ignore - Dynamic property access for metadata mapping\n this._metadata[fieldMapping[field]] = metadata[field];\n }\n });\n }\n\n /**\n * @typedef {Object} FieldMetadataUpdate\n * @property {string} [comment] - Field comment\n * @property {QvdNumberFormat|string} [numberFormat] - Number format\n * @property {Object|string} [tags] - Field tags\n */\n\n /**\n * Sets modifiable field-level metadata for a specific field.\n * Immutable properties related to data storage (Offset, Length, BitOffset, etc.) are ignored.\n * @param {string} fieldName The name of the field.\n * @param {FieldMetadataUpdate} metadata Object containing field metadata properties to update.\n */\n setFieldMetadata(fieldName, metadata) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n this._metadata.Fields.QvdFieldHeader = fields;\n }\n\n const fieldIndex = fields.findIndex((f) => f.FieldName === fieldName);\n if (fieldIndex === -1) {\n return;\n }\n\n // Only allow modification of Comment, NumberFormat, and Tags (not Offset, Length, BitOffset, etc.)\n if (metadata.comment !== undefined) {\n fields[fieldIndex].Comment = metadata.comment;\n }\n if (metadata.numberFormat !== undefined) {\n fields[fieldIndex].NumberFormat = metadata.numberFormat;\n }\n if (metadata.tags !== undefined) {\n fields[fieldIndex].Tags = metadata.tags;\n }\n }\n\n /**\n * Returns the first n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n head(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('head() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(this._data.slice(0, n), this._columns, this._metadata);\n }\n\n /**\n * Returns the last n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n tail(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('tail() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(n === 0 ? [] : this._data.slice(-n), this._columns, this._metadata);\n }\n\n /**\n * Returns the selected rows of the data frame.\n *\n * @param {...number} args The indices of the rows to return.\n * @return {QvdDataFrame} The selected rows of the data frame.\n * @throws {QvdValidationError} If any index is not an integer or is out of bounds.\n */\n rows(...args) {\n for (const index of args) {\n if (typeof index !== 'number' || !Number.isInteger(index)) {\n throw new QvdValidationError('rows() requires integer indices', {\n provided: index,\n type: typeof index,\n });\n }\n if (index < 0 || index >= this._data.length) {\n throw new QvdValidationError(`Row index ${index} out of bounds`, {\n index,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n }\n return new QvdDataFrame(\n args.map((index) => this._data[index]),\n this._columns,\n this._metadata,\n );\n }\n\n /**\n * Returns the value at the specified row and column.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {any} The value at the specified row and column.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n at(row, column) {\n if (typeof row !== 'number' || !Number.isInteger(row)) {\n throw new QvdValidationError('Row index must be an integer', {\n provided: row,\n type: typeof row,\n });\n }\n if (row < 0 || row >= this._data.length) {\n throw new QvdValidationError(`Row index ${row} out of bounds`, {\n index: row,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n return this._data[row][this._columns.indexOf(column)];\n }\n\n /**\n * Selects the specified columns from the data frame.\n *\n * @param {...string} args The names of the columns to select.\n * @return {QvdDataFrame} The selected columns of the data frame.\n * @throws {QvdValidationError} If any column name does not exist.\n */\n select(...args) {\n for (const column of args) {\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n }\n const indices = args.map((arg) => this._columns.indexOf(arg));\n const data = this._data.map((row) => indices.map((index) => row[index]));\n const columns = indices.map((index) => this._columns[index]);\n return new QvdDataFrame(data, columns, this._metadata);\n }\n\n /**\n * Returns the data frame as a dictionary.\n *\n * @return {Promise<{columns: Array<string>, data: Array<Array<any>>}>} The data frame as a dictionary.\n */\n async toDict() {\n return {columns: this._columns, data: this._data};\n }\n\n /**\n * Persists the data frame to a QVD file.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional writing options.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function that receives progress updates during write operations.\n */\n async toQvd(path, options = {}) {\n const {QvdFileWriter} = await import('./QvdFileWriter.js');\n const writerOptions = {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n };\n await new QvdFileWriter(path, this, writerOptions).save();\n }\n\n /**\n * Loads a QVD file and returns its data frame.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional loading options.\n * @param {number|null} [options.maxRows] The maximum number of rows to load. Must be a non-negative\n * integer; if not specified or null, all rows are loaded. Anything else throws a QvdValidationError.\n * This is the older name for `limit`; the two are the same option and passing both throws.\n * @param {number|null} [options.limit] Rows to read, counting from `offset`. The same number as\n * `maxRows`, spelled so that it reads correctly beside an offset.\n * @param {number} [options.offset=0] File row to start at. An offset past the end of the file\n * returns no rows rather than throwing, so a paging loop terminates on its own.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should\n * appear in the result. Unselected fields have their symbols skipped entirely rather than\n * parsed and discarded. An unknown or repeated name throws.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}` as the\n * read proceeds - the same shape `toQvd`'s callback receives.\n * @param {AbortSignal} [options.signal] Cancels the read. The rejection is `signal.reason`,\n * which is a `DOMException` named `AbortError` unless you aborted with a reason of your own.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction (0.0-1.0) of the memory budget a load\n * may use. The budget is the smaller of the V8 heap limit and any container memory limit. Default\n * is 0.8; the estimate it scales accounts for the rows and columns being materialised, so this is\n * headroom for garbage collection rather than compensation for an inaccurate figure.\n * **Zero disables the memory check entirely.**\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes, above which\n * a lazy load switches to the two-pass filtering path. Defaults to 50MB.\n * @throws {QvdValidationError} If a window option is not a non-negative integer, if both\n * `maxRows` and `limit` are given, or if `fields` names a column the file does not have.\n * @return {Promise<QvdDataFrame>} The data frame of the QVD file.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n return await new QvdFileReader(path, readerOptionsFrom(options)).load(windowFrom(options));\n }\n\n /**\n * Reads a QVD file in chunks, as an async generator of data frames.\n *\n * The file is opened, read and parsed once; only the index decode and the row building happen\n * per chunk, so what this bounds is row materialisation - the part that actually dominates a\n * large read's heap. It is **not** constant-memory reading of an arbitrarily large file: the\n * symbol table is parsed in full whatever the chunk size, because a stored index in the last\n * chunk can address the first symbol. On a high-cardinality file that table is the bulk of the\n * cost, and `readMetadata` is the only read that avoids it.\n *\n * ```js\n * for await (const chunk of QvdDataFrame.iterate('big.qvd', {chunkSize: 50_000})) {\n * process(chunk.data);\n * }\n * ```\n *\n * A window covering no rows yields nothing, so a loop over an exhausted offset simply does not\n * run its body.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] The same options `fromQvd` takes, plus:\n * @param {number} [options.chunkSize=100000] Rows per frame. Must be a positive integer.\n * @return {AsyncGenerator<QvdDataFrame>} The chunks, in file order.\n */\n static async *iterate(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n const reader = new QvdFileReader(path, readerOptionsFrom(options));\n\n yield* reader.iterateRows(windowFrom(options), options.chunkSize === undefined ? 100000 : options.chunkSize);\n }\n\n /**\n * Reads a QVD file's schema and header metadata, without reading its data.\n *\n * Costs the same whatever the file's size, because it stops at the XML header - a few\n * kilobytes - and never touches the symbol or index tables.\n *\n * This is what `{maxRows: 0}` looks like but is not. That still reads and parses the whole\n * symbol table, which is 0.4MB on a 38MB taxi fixture but hundreds of megabytes on a\n * high-cardinality file. Use this when you want to know what is in a file rather than to\n * read any of it.\n *\n * No data frame comes back, deliberately: one with `data: []` would be indistinguishable\n * from an empty file at the call site.\n *\n * ```js\n * const {columns, rowCount, fields} = await QvdDataFrame.readMetadata('sales.qvd');\n * ```\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional reading options.\n * @param {string} [options.allowedDir] Optional allowed directory path, applied exactly as it\n * is for `fromQvd`.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}`, as on\n * the reads that return data. Only the `read` and `header` stages occur here; there are no\n * symbols to parse and no rows to build.\n * @param {AbortSignal} [options.signal] Cancels the read, rejecting with `signal.reason`.\n * @return {Promise<QvdFileMetadata>} The file's schema and header metadata.\n */\n static async readMetadata(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n return await new QvdFileReader(path, metadataOptionsFrom(options)).loadMetadata();\n }\n\n /**\n * Constructs a data frame from a dictionary.\n *\n * @param {{columns: Array<string>, data: Array<Array<any>>}} data The dictionary to construct the data frame from.\n * @return {Promise<QvdDataFrame>} The constructed data frame.\n */\n static async fromDict(data) {\n if (!data.columns) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any columns.', {\n data,\n });\n }\n if (!data.data) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any data.', {\n data,\n });\n }\n\n return new QvdDataFrame(data.data, data.columns);\n }\n}\n","// @ts-check\n\nexport {QvdSymbol} from './QvdSymbol.js';\nexport {QvdDataFrame} from './QvdDataFrame.js';\nexport {QvdColumnTable, QvdColumn} from './QvdColumnTable.js';\nexport {QvdFileReader} from './QvdFileReader.js';\nexport {QvdFileWriter} from './QvdFileWriter.js';\nexport {\n QvdError,\n QvdParseError,\n QvdValidationError,\n QvdIOError,\n QvdCorruptedError,\n QvdSecurityError,\n} from './QvdErrors.js';\n"]}