qvdjs 1.0.0 → 2.0.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.
- package/LICENSE +2 -1
- package/README.md +102 -32
- package/dist/index.cjs +639 -176
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +635 -172
- package/dist/index.js.map +1 -1
- package/package.json +10 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/QvdErrors.js","../src/util/cellRules.js","../src/util/symbolBytes.js","../src/QvdDual.js","../src/util/readOptions.js","../src/util/storedSymbols.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/util/resolveSymbols.js","../src/QvdColumnTable.js","../src/QvdFileReader.js","../src/QvdDataFrame.js","../src/QvdSymbol.js","../src/index.js","../src/util/qlikDate.js"],"names":["assert","fs","path","xml","QvdFileReader","QvdColumnTable","QvdFileWriter"],"mappings":"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","file":"index.js","sourcesContent":["// @ts-check\n\n/**\n * The name each of this module's classes reports, written out rather than read from the class.\n *\n * A class's own `name` is whatever the build left it: the CommonJS bundle of every release checked from\n * 0.6.2 to 0.11.0 gave these classes no name at all, so `error.name` was `''` for a `require`d qvdjs,\n * and a bundler minifying the source renames them. `error.name` is what callers match on, so it must\n * not depend on either.\n *\n * @type {Map<Function, string>}\n */\nconst ERROR_NAMES = new Map();\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 // A caller's own subclass keeps its own name.\n this.name = ERROR_NAMES.get(new.target) ?? new.target.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\nERROR_NAMES.set(QvdError, 'QvdError');\nERROR_NAMES.set(QvdParseError, 'QvdParseError');\nERROR_NAMES.set(QvdValidationError, 'QvdValidationError');\nERROR_NAMES.set(QvdIOError, 'QvdIOError');\nERROR_NAMES.set(QvdCorruptedError, 'QvdCorruptedError');\nERROR_NAMES.set(QvdSecurityError, 'QvdSecurityError');\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * What a QVD symbol can hold, said once.\n *\n * Only the writer used to apply these rules. It defined the int32 range, to choose between an int\n * and a double, and refused NaN, the infinities and a string containing NUL. `QvdSymbol` checked\n * nothing: the RangeError from Node's `writeInt32LE` was its only range check, and it wrote a NUL\n * whole - so the same value could be refused by one and written by the other. Everything that\n * decides whether a number or a text can be stored now reads it from here, and throws from here.\n */\n\n/** Lower bound of the integer a type 1 or type 5 symbol holds. */\nexport const INT32_MIN = -2147483648;\n\n/** Upper bound of the integer a type 1 or type 5 symbol holds. */\nexport const INT32_MAX = 2147483647;\n\n/** Terminates a text in the symbol table, so a stored text cannot contain one. */\nexport const NUL = String.fromCharCode(0);\n\n/**\n * Marks a `QvdDual`, from whichever copy of this library built it.\n *\n * `Symbol.for` rather than `Symbol()`, and a brand rather than `instanceof`, because a cell can come\n * from a different copy of the class than the one checking it: the CommonJS and ESM builds loaded in\n * one process, two installed copies of the package, a Jest module registry that has been reset, or a\n * vm realm. Each has its own `QvdDual`, and `instanceof` answers false across all of them.\n */\nexport const DUAL_BRAND = Symbol.for('qvdjs.QvdDual');\n\n/**\n * The dual value a cell holds, or null when it is not one.\n *\n * A dual is either a `QvdDual` - recognised by its brand, so one built by another copy of this\n * library counts - or a plain object whose own enumerable keys are exactly `number` and `text`. The\n * second form is what every clone of a `QvdDual` produces: `structuredClone`, `postMessage`,\n * `v8.serialize` and `JSON` all keep own enumerable data properties and drop the class, so a frame\n * sent to a worker and back writes the same duals it was read with.\n *\n * The shape is exact because a looser one writes the wrong file silently. An object that merely\n * *has* `number` and `text` - a record `{number, text, date}`, an array given the two properties, an\n * object that inherits them - is somebody's own data, and storing it as a dual would discard the rest\n * of it without a word. It is refused instead, and so is anything that is not a plain object - see\n * `isPlainObject` - so an object literal from a vm realm is accepted where `instanceof Object` would\n * refuse it.\n *\n * The halves are not type-checked here. The caller validates them, so that a refusal can say which\n * half is wrong rather than that the object is not a dual.\n *\n * @param {any} value Any value.\n * @return {{number: any, text: any}|null} The value itself when it is a dual, or null.\n */\nexport function asDual(value) {\n if (value === null || typeof value !== 'object') {\n return null;\n }\n\n try {\n if (value[DUAL_BRAND] === true) {\n return value;\n }\n\n if (!isPlainObject(value)) {\n return null;\n }\n\n const keys = Object.keys(value);\n\n return keys.length === 2 &&\n ((keys[0] === 'number' && keys[1] === 'text') || (keys[0] === 'text' && keys[1] === 'number'))\n ? value\n : null;\n } catch {\n // A revoked Proxy throws from every one of those operations. It is not a dual, and the refusal\n // that follows describes it without touching it again.\n return null;\n }\n}\n\n/**\n * Whether a value is a plain object: an object literal from any realm, or one with a null prototype.\n *\n * Tested as \"a prototype that is null, or whose own prototype is null\", which is what a realm's\n * `Object.prototype` is. An array, a class instance and an object made with `Object.create(other)` are\n * not plain, although an instance of an anonymous class and the last read their constructor name as\n * `Object` through the chain.\n *\n * @param {any} value The value.\n * @return {boolean} True for a plain object.\n * @throws {TypeError} For a revoked Proxy, from `Array.isArray` and `Object.getPrototypeOf`.\n */\nexport function isPlainObject(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || Object.getPrototypeOf(prototype) === null;\n}\n\n/**\n * Whether a text reads as a finite number.\n *\n * This is the rule `{coerceNumericStrings: true}` applies, and the one every read applied from #212 until\n * coercion became opt-in. The reader started from `!isNaN(Number(text))` and was narrowed twice.\n * `Number('')` and `Number(' ')` are 0, which turned every blank cell Qlik stored into a real zero, so\n * blank text is never numeric. And `Number.isFinite` rather than `!isNaN`, because JavaScript reads `E` as\n * an exponent: `Number('8E5597')` is Infinity, and that string is a LEGO colour code in this repository's\n * own `lego/colors.qvd`. A text whose numeric reading is not finite stays text.\n *\n * @param {string} text The text.\n * @return {boolean} True when the text reads as a finite number.\n */\nexport function isNumericText(text) {\n return text.trim() !== '' && Number.isFinite(Number(text));\n}\n\n/**\n * Whether a number is stored as a 32-bit integer rather than as a double.\n *\n * This is the rule Qlik follows, read off the files it wrote rather than chosen here: every numeric\n * symbol in the bundled Qlik files is an int exactly when its value is an integer inside the int32\n * range, whether it is a pure number or a dual. The kind follows the value, never the text.\n *\n * -0 is stored as the integer 0, because `Number.isInteger(-0)` is true and -0 is inside the range.\n * That is the cause, and not a Map folding the two together: a Map only merges 0 and -0 when both\n * occur in one column, and a column holding -0 alone is stored as 0 all the same. Qlik's engine\n * compares -0 equal to 0 and `Num()` shows it as 0.\n *\n * @param {number} value A finite number.\n * @return {boolean} True when the value is stored as an int symbol.\n */\nexport function isStoredAsInt(value) {\n return Number.isInteger(value) && value >= INT32_MIN && value <= INT32_MAX;\n}\n\n/**\n * Why a value cannot be stored as a number, or null when it can.\n *\n * @param {any} value The value.\n * @return {string|null} `'is a string, not a number'` and the like, `'is NaN'`, `'is Infinity'`,\n * `'is -Infinity'`, or null.\n */\nexport function numberProblem(value) {\n if (typeof value !== 'number') {\n return `is ${describeType(value)}, not a number`;\n }\n\n return Number.isFinite(value) ? null : `is ${String(value)}`;\n}\n\n/**\n * Why a value cannot be stored as a text, or null when it can.\n *\n * NUL is refused because it is what ends a text in the symbol table: a text containing one was\n * written whole, and the reader then took the character after it for the next symbol's type byte.\n *\n * An unpaired surrogate is refused because UTF-8 has no encoding for one. A JavaScript string is a\n * sequence of UTF-16 code units, and a code unit from U+D800 to U+DFFF is half of a character unless\n * a high one is followed by a low one. Node writes each half on its own as U+FFFD, the replacement\n * character, so `'\\uD800'` and `'\\uDFFF'` were written as the same three bytes: two different strings\n * became two symbols with one stored value, and neither read back as what was written.\n *\n * A string with both problems reports the NUL.\n *\n * @param {any} value The value.\n * @return {{reason: 'type'|'nul'|'surrogate', position?: number}|null} The problem, with the index of\n * the offending code unit where there is one, or null.\n */\nexport function textProblem(value) {\n if (typeof value !== 'string') {\n return {reason: 'type'};\n }\n\n // indexOf rather than includes: this runs once per distinct value on a table that may have\n // millions of them, and indexOf on a string primitive is the cheaper of the two.\n const position = value.indexOf(NUL);\n\n if (position !== -1) {\n return {reason: 'nul', position};\n }\n\n // isWellFormed is one native call for the whole string, so the scan for where the problem is runs\n // only for a string that is about to be refused.\n return value.isWellFormed() ? null : {reason: 'surrogate', position: unpairedSurrogateIndex(value)};\n}\n\n/**\n * The index of the first code unit in a string that is half of a surrogate pair without the other\n * half.\n *\n * @param {string} value A string that is not well formed.\n * @return {number} The index, or -1 when every surrogate is paired.\n */\nfunction unpairedSurrogateIndex(value) {\n for (let index = 0; index < value.length; index++) {\n const unit = value.charCodeAt(index);\n\n if (unit < 0xd800 || unit > 0xdfff) {\n continue;\n }\n\n // A high surrogate followed by a low one is one character: step over both. charCodeAt past the\n // end is NaN, which fails the comparison, so a high surrogate at the end is unpaired.\n const next = value.charCodeAt(index + 1);\n\n if (unit <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) {\n index++;\n continue;\n }\n\n return index;\n }\n\n return -1;\n}\n\n/**\n * Throws unless a value can be stored as a number.\n *\n * `subject` names the half being checked, as the message starts: `'The double of a symbol'` gives\n * \"The double of a symbol must be a finite number; got a string\". A cell is the exception, and is\n * checked with a null subject: it is already known to be a number, so all that can be wrong with it\n * is NaN or an infinity, and the message for that has been quoted to callers since the writer first\n * refused it.\n *\n * @param {any} value The value.\n * @param {string|null} subject What the value is, capitalised; null for a cell.\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If the value is not a finite number.\n */\nexport function checkNumber(value, subject, context) {\n if (numberProblem(value) === null) {\n return;\n }\n\n if (subject === null && typeof value === 'number') {\n throw new QvdValidationError('NaN and Infinity cannot be stored in a QVD field', {\n ...context,\n provided: String(value),\n });\n }\n\n throw new QvdValidationError(`${subject ?? 'A number'} must be a finite number; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n}\n\n/**\n * Throws unless a value can be stored as a text.\n *\n * @param {any} value The value.\n * @param {string} subject What the value is, capitalised, as the message starts: `'A string value'`\n * gives \"A string value cannot contain a NUL character\".\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If the value is not a string, or holds a NUL or an unpaired surrogate,\n * which no stored text can; `context.position` is that code unit's index.\n */\nexport function checkText(value, subject, context) {\n const problem = textProblem(value);\n\n if (problem === null) {\n return;\n }\n\n if (problem.reason === 'type') {\n throw new QvdValidationError(`${subject} must be a string; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n }\n\n if (problem.reason === 'surrogate') {\n throw new QvdValidationError(`${subject} cannot contain an unpaired surrogate`, {\n ...context,\n position: problem.position,\n });\n }\n\n throw new QvdValidationError(`${subject} cannot contain a NUL character`, {...context, position: problem.position});\n}\n\n/**\n * The name of a value's constructor, read without letting the read throw.\n *\n * A getter, or a revoked Proxy, can throw from `value.constructor`, and an error message is the\n * wrong place to find that out: the caller would get that error instead of the one being built.\n *\n * @param {any} value An object.\n * @return {string|null} The name, or null when there is none to read.\n */\nexport function constructorName(value) {\n try {\n const name = value.constructor?.name;\n\n return typeof name === 'string' && name !== '' ? name : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Names a value's type the way a caller reading an error would.\n *\n * `typeof` alone says \"object\" for a Date, an array and a Map alike, which is the least useful thing\n * it could say in a message whose job is to tell somebody what to convert. The value is never\n * converted to a string along the way: an object's own conversion can throw, or say nothing about\n * what the object is.\n *\n * @param {any} value The value.\n * @return {string} `'a Date'`, `'an array'`, `'a plain object with keys a, b'`, `'a boolean'`,\n * `'NaN'`, and so on.\n */\nexport function describeType(value) {\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'number') {\n // A number that fails a number check is NaN or an infinity, and \"got a number\" would say nothing.\n return Number.isFinite(value) ? 'a number' : String(value);\n }\n\n if (typeof value === 'undefined') {\n return 'undefined';\n }\n\n if (typeof value !== 'object') {\n return `a ${typeof value}`;\n }\n\n let name;\n\n try {\n if (Array.isArray(value)) {\n return 'an array';\n }\n\n // '[object Date]' when there is no constructor name to read: a null prototype, a replaced\n // constructor property.\n name = constructorName(value) ?? Object.prototype.toString.call(value).slice(8, -1);\n\n if (name === 'Object') {\n // The name an object inheriting from another reads through its chain, too - from\n // `Object.create({number: 1, text: 'x'})`, or an instance of an anonymous class - and calling that\n // plain would contradict a message asking for one: \"metadata must be a plain object; got a plain\n // object\".\n if (!isPlainObject(value)) {\n return 'an object whose prototype is not Object.prototype';\n }\n\n const keys = Object.keys(value);\n\n if (keys.length === 0) {\n return 'a plain object';\n }\n\n // Capped, because the message is for a person and an object can have any number of keys.\n return `a plain object with keys ${keys.slice(0, 5).join(', ')}${keys.length > 5 ? ', ...' : ''}`;\n }\n } catch {\n // A revoked Proxy throws from Array.isArray itself.\n return 'an object';\n }\n\n // 'an Error', 'an Int32Array', but 'a Uint8Array': a leading U is read \"you\".\n return `${/^[aeio]/i.test(name) ? 'an' : 'a'} ${name}`;\n}\n","// @ts-check\n\nimport {isStoredAsInt} from './cellRules.js';\n\n/**\n * How one symbol is laid out in the symbol table, said once.\n *\n * | Kind | Bytes after the type byte |\n * | --- | --- |\n * | 1, int | int32, little-endian |\n * | 2, double | float64, little-endian |\n * | 4, string | UTF-8 text, then a NUL |\n * | 5, dual int | int32, then UTF-8 text and a NUL |\n * | 6, dual double | float64, then UTF-8 text and a NUL |\n *\n * Nothing here validates. A caller checks its values through `cellRules` first, and these\n * functions encode what they are given.\n */\n\n/**\n * The kind a value is stored as.\n *\n * The number decides between int and double - through `isStoredAsInt`, which is Qlik's rule - and\n * the presence of a text decides between pure and dual. Nothing else does: a text is never parsed\n * to choose a kind.\n *\n * @param {number|null} number The numeric half, or null for a string.\n * @param {string|null} text The text, or null for a pure number.\n * @return {1|2|4|5|6} The type byte.\n */\nexport function kindOf(number, text) {\n if (number === null) {\n return 4;\n }\n\n if (isStoredAsInt(number)) {\n return text === null ? 1 : 5;\n }\n\n return text === null ? 2 : 6;\n}\n\n/**\n * The bytes one symbol takes, type byte and terminator included.\n *\n * @param {number} kind The type byte.\n * @param {number|null} number The numeric half, unused for kind 4.\n * @param {string|null} text The text, unused for kinds 1 and 2.\n * @return {number} The length in bytes.\n */\nexport function symbolByteLength(kind, number, text) {\n const numberBytes = kind === 1 || kind === 5 ? 4 : kind === 2 || kind === 6 ? 8 : 0;\n // @ts-ignore - a kind of 4, 5 or 6 carries a text\n const textBytes = kind >= 4 ? Buffer.byteLength(text, 'utf8') + 1 : 0;\n\n return 1 + numberBytes + textBytes;\n}\n\n/**\n * Encodes one symbol into a buffer.\n *\n * The buffer is expected to be sized with `symbolByteLength`, so every byte in the range is written:\n * a buffer from `Buffer.allocUnsafe` holds whatever memory it was given, and a byte skipped here\n * would put that memory into the file.\n *\n * @param {Buffer} buffer The buffer.\n * @param {number} offset Where the type byte goes.\n * @param {number} kind The type byte.\n * @param {number|null} number The numeric half, unused for kind 4.\n * @param {string|null} text The text, unused for kinds 1 and 2.\n * @return {number} The offset after the symbol.\n */\nexport function writeSymbol(buffer, offset, kind, number, text) {\n buffer[offset++] = kind;\n\n if (kind === 1 || kind === 5) {\n // @ts-ignore - kinds 1 and 5 carry a number\n offset = buffer.writeInt32LE(number, offset);\n } else if (kind === 2 || kind === 6) {\n // @ts-ignore - kinds 2 and 6 carry a number\n offset = buffer.writeDoubleLE(number, offset);\n }\n\n if (kind >= 4) {\n // @ts-ignore - kinds 4, 5 and 6 carry a text\n offset += buffer.write(text, offset, 'utf8');\n buffer[offset++] = 0;\n }\n\n return offset;\n}\n","// @ts-check\n\nimport {DUAL_BRAND, asDual, checkNumber, checkText} from './util/cellRules.js';\n\n/**\n * A Qlik dual value, holding both of its halves: a number, and the text Qlik displays for it.\n *\n * Qlik stores dates, timestamps and formatted numbers this way - the date `1756-01-01` is the number\n * -52593 with that text, and a fare of `4.50` is the number 4.5 with that text. To Qlik the value\n * *is* the number: it sums, sorts and compares by it, and the text belongs to how the field shows it.\n * That is why a read returns a dual as its number by default, and keeps the text with the frame so a\n * write puts it back. Read with `{duals: 'both'}` to get this object instead, for a cell that has to\n * carry both halves on its own - through a worker, or into another frame.\n *\n * It has no `valueOf` and no `toString`, and every implicit conversion throws a `TypeError`: `+`,\n * `-`, `<`, `==` against a primitive, a template literal, `String()`, `Number()`, `new Date()`,\n * `join()` and a default `sort()`. Each of those has to pick one half, and whichever it picked would\n * be wrong somewhere - `new Date(dual)` of a date's serial is a moment in January 1970, and a string\n * comparison of a fare's number is not a comparison of its text. Read `.number` or `.text` instead:\n *\n * ```js\n * const fare = new QvdDual(4.5, '4.50');\n * fare.number + 1; // 5.5\n * fare.text; // '4.50'\n * `${fare}`; // TypeError\n * ```\n *\n * It is plain data: `number` and `text` are own, enumerable, read-only properties, and the object is\n * frozen. So `structuredClone`, `postMessage`, `v8.serialize` and `JSON` all turn it into\n * `{number, text}`, and the writer accepts exactly that shape as a dual, from any copy of this\n * library. `===` compares identity, as for any object.\n */\nexport class QvdDual {\n /**\n * Constructs a dual value.\n *\n * The storage kind is not chosen here. The writer derives it from the number, as Qlik does: an\n * integer inside the int32 range is stored as a dual int, anything else as a dual double.\n *\n * @param {number} number The numeric half. Must be a finite number.\n * @param {string} text The text half. Must be a string with no NUL and no unpaired surrogate.\n * @throws {QvdValidationError} If either half cannot be stored in a QVD. The message names the half.\n */\n constructor(number, text) {\n checkNumber(number, 'The number of a dual value', {half: 'number'});\n checkText(text, 'The text of a dual value', {half: 'text'});\n\n defineHalves(this, number, text);\n }\n\n /**\n * Refuses every implicit conversion. See the class comment for why neither half is a safe answer.\n *\n * The hint JavaScript passes is not used: `'number'`, `'string'` and `'default'` say which\n * conversion ran, not which half the caller meant, and the fix is the same for all three.\n *\n * @return {never}\n * @throws {TypeError} Always.\n */\n [Symbol.toPrimitive]() {\n throw new TypeError(\n `A QvdDual holds two values, ${this.number} and ${JSON.stringify(this.text)}; use .number or .text`,\n );\n }\n\n /**\n * Both halves, so `JSON.stringify` loses neither - and produces the shape the writer accepts back.\n *\n * @return {{number: number, text: string}} The dual as a plain object.\n */\n toJSON() {\n return {number: this.number, text: this.text};\n }\n\n /**\n * How Node's `util.inspect` and `console.log` show a dual.\n *\n * @return {string} For example `QvdDual(4.5, \"4.50\")`.\n */\n [Symbol.for('nodejs.util.inspect.custom')]() {\n return `QvdDual(${this.number}, ${JSON.stringify(this.text)})`;\n }\n\n /** @return {string} `'QvdDual'`, for `Object.prototype.toString`. */\n get [Symbol.toStringTag]() {\n return 'QvdDual';\n }\n\n /**\n * Whether a value is a dual cell: a `QvdDual` from any copy of this library, or a plain object whose\n * own enumerable keys are exactly `number` and `text`, which is what a clone of one becomes.\n *\n * Recognition only. The halves are checked when the value is written.\n *\n * @param {any} value Any value.\n * @return {boolean} True for a dual cell.\n */\n static isDual(value) {\n return asDual(value) !== null;\n }\n}\n\n// On the prototype and not enumerable, so it is never copied: a clone is recognised by its shape,\n// and a copy of this class loaded elsewhere by the same key.\nObject.defineProperty(QvdDual.prototype, DUAL_BRAND, {value: true});\n\n/**\n * Defines a dual's halves as own, enumerable, read-only properties and freezes it.\n *\n * Own and enumerable is the point: those are the properties every clone keeps. A getter on the\n * prototype would clone to `{}`.\n *\n * @param {object} target The object being built.\n * @param {number} number The numeric half.\n * @param {string} text The text half.\n */\nfunction defineHalves(target, number, text) {\n Object.defineProperties(target, {\n number: {value: number, enumerable: true},\n text: {value: text, enumerable: true},\n });\n\n Object.freeze(target);\n}\n\n/**\n * A `QvdDual` for a symbol read from a file, taken as stored.\n *\n * Not validated, because a read reports what the file holds: a damaged file's NaN double reads as\n * NaN, and the writer refuses it if anyone stores it again. Built without calling the constructor\n * rather than by setting a flag the constructor reads, so no state outlives the call - a flag left\n * set by a call that threw would have switched validation off for the next `new QvdDual`.\n *\n * @param {number} number The stored int or double.\n * @param {string} text The stored text.\n * @return {QvdDual} A frozen dual.\n */\nexport function dualFromSymbol(number, text) {\n const dual = Object.create(QvdDual.prototype);\n\n defineHalves(dual, number, text);\n\n return dual;\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/** What a dual symbol can read back as. The first is the default. */\nconst DUAL_MODES = Object.freeze(['number', 'text', 'both']);\n\n/**\n * Checks the `duals` option.\n *\n * A dual is a number with the text Qlik displays for it: the date -52593 shown as `1756-01-01`, the\n * fare 4.5 shown as `4.50`. Qlik treats the value as its number - it sums, sorts and compares by it -\n * so `'number'` is the default, and the text is kept with the frame so a write puts it back.\n * `'text'` returns the text instead, and `'both'` a frozen `QvdDual` holding both halves.\n *\n * Refused rather than defaulted when unrecognised: a typo such as `'numbers'` falling back to the\n * default would look like it worked, and the first sign of the mistake would be somewhere else.\n *\n * @param {any} value The option as passed. `undefined` and null mean the default.\n * @param {string} filePath The file being read, for the error.\n * @return {'number'|'text'|'both'} The mode.\n * @throws {QvdValidationError} If the value is not one of the modes.\n */\nexport function normaliseDuals(value, filePath) {\n if (value === undefined || value === null) {\n return 'number';\n }\n\n if (!DUAL_MODES.includes(value)) {\n throw new QvdValidationError(`duals must be one of ${DUAL_MODES.map((mode) => `'${mode}'`).join(', ')}`, {\n option: 'duals',\n provided: value,\n file: filePath,\n });\n }\n\n return value;\n}\n\n/**\n * Checks the `coerceNumericStrings` option.\n *\n * Off by default. A string symbol is a value stored with no number, and a read that turned the ones\n * spelled like numbers into numbers returned values the file does not hold: `Number()` accepts\n * leading zeros, exponents, hex prefixes and surrounding whitespace, so `'007'` read as 7 and `'0x10'`\n * as 16. On, it is that rule - see `isNumericText` - for callers who relied on it, and the original\n * text is kept in the frame's `storedSymbols`, so a write stores the string again.\n *\n * It applies to every cell a read would return as a string: a string symbol in every `duals` mode, and\n * a dual's text under `{duals: 'text'}`, which reads as the number the dual stores rather than as\n * `Number(text)`.\n *\n * A boolean and nothing else. A truthy string such as `'false'` switching it on would be the opposite\n * of what was asked, with no error to say so.\n *\n * @param {any} value The option as passed. `undefined` and null mean off.\n * @param {string} filePath The file being read, for the error.\n * @return {boolean} Whether to coerce.\n * @throws {QvdValidationError} If the value is not a boolean.\n */\nexport function normaliseCoerceNumericStrings(value, filePath) {\n if (value === undefined || value === null) {\n return false;\n }\n\n if (typeof value !== 'boolean') {\n throw new QvdValidationError('coerceNumericStrings must be true or false', {\n option: 'coerceNumericStrings',\n provided: value,\n type: typeof value,\n file: filePath,\n });\n }\n\n return value;\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 duals: options.duals,\n coerceNumericStrings: options.coerceNumericStrings,\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`, `fields`, `duals` and `coerceNumericStrings` are absent because they mean\n * nothing here, not because they were forgotten: a read that stops at the XML header has no rows to\n * window and parses no field's symbols to skip or resolve. They are ignored rather than refused, so that\n * one options object can be passed to `readMetadata` and to a data read without the caller having to\n * 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 {QvdValidationError} from '../QvdErrors.js';\nimport {checkNumber, checkText, describeType} from './cellRules.js';\n\n/**\n * The stored-symbol record: what a frame keeps so that the cells it shows write back as the symbols\n * they were read from.\n *\n * A cell shows one value. Usually that value is the whole symbol - a pure number, a pure string - but\n * not always: a dual read as its number has a text the cell does not show, a dual read as its text has\n * a number, and a string read as a number has the text it was spelled with. For each field that holds\n * such a symbol the record keeps one entry, and entry `i` says that a cell holding `values[i]` stands\n * for the stored symbol (`numbers[i]`, `texts[i]`):\n *\n * | `numbers[i]` | `texts[i]` | The stored symbol |\n * | --- | --- | --- |\n * | a number | a string | a dual |\n * | null | a string | a pure string - one read as a number |\n * | a number | null | a pure number, recorded because another symbol reads as the same value |\n *\n * The last row is what lets the writer see a collision: when two different symbols read as one value,\n * both are recorded, and the writer refuses that value rather than guess which symbol a cell meant.\n *\n * It is plain data - arrays of numbers, strings and nulls - so it survives `JSON`, `structuredClone`,\n * `postMessage` and `v8.serialize` whole, and a frame sent elsewhere can be rebuilt with `fromDict`.\n * It is frozen, because every frame derived from a read shares it: a change through one would change\n * what all of them write.\n *\n * @typedef {Object} StoredSymbolsEntry\n * @property {string} field The field the entry describes.\n * @property {ReadonlyArray<number|string>} values What a cell holds for each recorded symbol.\n * @property {ReadonlyArray<number|null>} numbers Each symbol's number, or null for a pure string.\n * @property {ReadonlyArray<string|null>} texts Each symbol's text, or null for a pure number.\n */\n\n/**\n * @typedef {ReadonlyArray<StoredSymbolsEntry>} StoredSymbols\n */\n\n/**\n * Where a reader leaves the record on the header object it returns.\n *\n * `Symbol.for`, so any copy of this library finds it. The property is not enumerable, so the header\n * still deep-equals the one `readMetadata` returns for the same file, and a caller who builds a frame\n * the way the architecture notes show - `new QvdDataFrame(data, columns, df.metadata)` - keeps the\n * record without knowing it exists.\n */\nexport const STORED_SYMBOLS = Symbol.for('qvdjs.storedSymbols');\n\n/**\n * Records this copy of the module has built or validated, so passing one on - to `head()`, `select()`,\n * a chunk of `iterate()` - costs nothing. A WeakSet, so it holds no record alive.\n *\n * @type {WeakSet<object>}\n */\nconst trusted = new WeakSet();\n\n/**\n * Freezes a record the reader built and marks it as needing no validation.\n *\n * A reader's record is taken as the file stores it. A damaged file's NaN double is recorded as NaN,\n * which validation would refuse: a read reports what is there, and the writer refuses the value if\n * anyone stores it again.\n *\n * @param {Array<StoredSymbolsEntry>} entries Entries whose arrays are already frozen.\n * @return {StoredSymbols} The record.\n */\nexport function trustStoredSymbols(entries) {\n const record = Object.freeze(entries);\n\n trusted.add(record);\n\n return record;\n}\n\n/**\n * Leaves a record on a header object, without making it part of what the header enumerates.\n *\n * @param {any} metadata The header object a read returns.\n * @param {StoredSymbols} record The record.\n */\nexport function attachStoredSymbols(metadata, record) {\n if (metadata !== null && typeof metadata === 'object' && Object.isExtensible(metadata)) {\n Object.defineProperty(metadata, STORED_SYMBOLS, {value: record, enumerable: false, configurable: true});\n }\n}\n\n/**\n * Throws a validation error about a record.\n *\n * @param {string} message The message.\n * @param {Object} context The context.\n * @return {never}\n * @throws {QvdValidationError} Always.\n */\nfunction refuse(message, context) {\n throw new QvdValidationError(message, context);\n}\n\n/**\n * A record checked, frozen and safe to write from, or null for none.\n *\n * Every check a writer relies on is made here, once, so a record typed by hand or rebuilt from JSON\n * can be refused with a message rather than producing a file. What it does *not* check is whether two\n * entries make a value ambiguous; the writer works that out for the values a column actually holds,\n * so a record merged from two reads is checked against the cells it is used with.\n *\n * @param {any} record The record, null or undefined.\n * @return {StoredSymbols|null} A frozen record - the same one when it was already trusted, otherwise\n * a frozen copy - or null.\n * @throws {QvdValidationError} If the record is not an array of well-formed entries.\n */\nexport function normaliseStoredSymbols(record) {\n if (record === null || record === undefined) {\n return null;\n }\n\n if (typeof record === 'object' && trusted.has(record)) {\n return record;\n }\n\n if (!Array.isArray(record)) {\n refuse(`storedSymbols must be an array of field entries; got ${describeType(record)}`, {\n option: 'storedSymbols',\n type: typeof record,\n });\n }\n\n /** @type {Set<string>} */\n const fields = new Set();\n\n const entries = record.map((entry, index) => {\n if (entry === null || typeof entry !== 'object' || Array.isArray(entry) || typeof entry.field !== 'string') {\n refuse('Each storedSymbols entry must be an object with a string field name', {entry: index});\n }\n\n const {field, values, numbers, texts} = entry;\n\n if (fields.has(field)) {\n refuse(`storedSymbols lists field '${field}' twice`, {field, entry: index});\n }\n\n fields.add(field);\n\n if (\n !Array.isArray(values) ||\n !Array.isArray(numbers) ||\n !Array.isArray(texts) ||\n values.length !== numbers.length ||\n values.length !== texts.length\n ) {\n refuse(`The values, numbers and texts of the storedSymbols entry for '${field}' must be arrays of one length`, {\n field,\n entry: index,\n });\n }\n\n for (let symbol = 0; symbol < values.length; symbol++) {\n const value = values[symbol];\n const number = numbers[symbol];\n const text = texts[symbol];\n const context = {field, symbol};\n\n if (typeof value !== 'number' && typeof value !== 'string') {\n refuse(`A stored symbol's value must be a number or a string; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n }\n\n if (number !== null) {\n checkNumber(number, \"A stored symbol's number\", context);\n }\n\n if (text !== null) {\n checkText(text, \"A stored symbol's text\", context);\n }\n\n // What each kind of symbol can be read as. A dual reads as one of its halves; a pure string as\n // itself or, coerced, as a number; a pure number only as itself. An entry that says otherwise\n // would write a symbol no read of it could have produced.\n const consistent =\n number !== null && text !== null\n ? sameValueZero(value, number) || value === text\n : number === null && text !== null\n ? value === text || (typeof value === 'number' && Number.isFinite(value))\n : number !== null && sameValueZero(value, number);\n\n if (!consistent) {\n refuse(\n number === null && text === null\n ? 'A stored symbol needs a number or a text'\n : \"A stored symbol's value must be its number or its text\",\n {...context, value, number, text},\n );\n }\n }\n\n return Object.freeze({\n field,\n values: Object.freeze(values.slice()),\n numbers: Object.freeze(numbers.slice()),\n texts: Object.freeze(texts.slice()),\n });\n });\n\n return trustStoredSymbols(entries);\n}\n\n/**\n * The entries of a record for some of its fields, sharing them rather than copying.\n *\n * @param {StoredSymbols|null} record The record.\n * @param {ReadonlyArray<string>} columns The fields to keep.\n * @return {StoredSymbols|null} The narrowed record: the same one when nothing is dropped, an empty one\n * when nothing is kept, and null only when there was none. Never null for a record, because a frame\n * given null takes the one a read left on its header, with entries for every field of the read.\n */\nexport function narrowStoredSymbols(record, columns) {\n if (record === null) {\n return null;\n }\n\n const kept = record.filter((entry) => columns.includes(entry.field));\n\n return kept.length === record.length ? record : trustStoredSymbols(kept);\n}\n\n/**\n * The entry for one field, or null.\n *\n * @param {StoredSymbols|null} record The record.\n * @param {string} field The field.\n * @return {StoredSymbolsEntry|null} The entry.\n */\nexport function storedSymbolsEntry(record, field) {\n if (record === null) {\n return null;\n }\n\n return record.find((entry) => entry.field === field) ?? null;\n}\n\n/**\n * Value-to-text maps for `textAt`, built on first use per entry. Weak, so an entry that is no longer\n * referenced takes its map with it.\n *\n * @type {WeakMap<StoredSymbolsEntry, Map<number|string, string>>}\n */\nconst firstTexts = new WeakMap();\n\n/**\n * Each value of a record entry, mapped to the text a cell holding it stands for.\n *\n * The text of the first symbol holding the value that has one. Symbols are in the order they appear\n * in the file, and a pure number recorded for a collision has no text, so a dual's text wins over it\n * whichever of the two the file stores first. A value no symbol gives a text is not in the map.\n *\n * Built from the last symbol to the first, so an earlier text overwrites a later one and each symbol\n * costs one write rather than a lookup and a write.\n *\n * @param {StoredSymbolsEntry} entry The field's entry.\n * @return {Map<number|string, string>} Value to text.\n */\nexport function firstTextByValue(entry) {\n /** @type {Map<number|string, string>} */\n const byValue = new Map();\n\n for (let index = entry.values.length - 1; index >= 0; index--) {\n const text = entry.texts[index];\n\n if (text !== null) {\n byValue.set(entry.values[index], text);\n }\n }\n\n return byValue;\n}\n\n/**\n * The text a cell stands for, according to a record entry - see `firstTextByValue`.\n *\n * @param {StoredSymbolsEntry} entry The field's entry.\n * @param {number|string} value The cell.\n * @return {string|null} The text, or null when the entry gives the value none.\n */\nexport function storedTextOf(entry, value) {\n let byValue = firstTexts.get(entry);\n\n if (byValue === undefined) {\n byValue = firstTextByValue(entry);\n firstTexts.set(entry, byValue);\n }\n\n return byValue.get(value) ?? null;\n}\n\n/**\n * `SameValueZero`, the equality a Map uses for its keys: `===`, except that NaN equals NaN.\n *\n * @param {any} a One value.\n * @param {any} b The other.\n * @return {boolean} Whether they are the same value.\n */\nexport function sameValueZero(a, b) {\n return a === b || (a !== a && b !== b);\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';\n// Node's assert, used only for invariants a bug in this library would violate - \"this private\n// method ran after the one that fills the field it reads\". Never for input: everything a caller\n// can get wrong throws a QvdError with a context object instead.\n//\n// #143 read the old Copilot instruction \"use assertions for validation\" as an explanation for\n// these calls. It is not: every one sits after a method that either assigns the field\n// unconditionally or throws, and 3,570 corruption cases across every bundled fixture and every\n// entry point produced no AssertionError. They are checked, and they stay.\nimport assert from 'assert';\nimport {QvdValidationError} from './QvdErrors.js';\nimport {validatePath} from './util/validatePath.js';\nimport {fieldGeometry, writeBitField} from './util/bitUtils.js';\nimport {\n asDual,\n checkNumber,\n checkText,\n constructorName,\n describeType,\n isNumericText,\n numberProblem,\n textProblem,\n} from './util/cellRules.js';\nimport {kindOf, symbolByteLength, writeSymbol} from './util/symbolBytes.js';\nimport {firstTextByValue, normaliseStoredSymbols, sameValueZero} from './util/storedSymbols.js';\n\n/**\n * @typedef {import('./QvdDataFrame.js').QvdDataFrame} QvdDataFrame\n */\n\n/**\n * Persists a QVD file to disk.\n */\n/**\n * The index of the first character in a text that XML 1.0 cannot hold, even written as a character\n * reference: a C0 control other than tab, line feed and carriage return, or U+FFFE or U+FFFF. NUL is one\n * of them; a surrogate without its pair, the other thing XML cannot hold, is `textProblem`'s to report.\n *\n * @param {string} value The text.\n * @return {number} The index, or -1 when there is none.\n */\nfunction notXmlIndex(value) {\n for (let index = 0; index < value.length; index++) {\n const unit = value.charCodeAt(index);\n\n if ((unit < 0x20 && unit !== 0x09 && unit !== 0x0a && unit !== 0x0d) || unit === 0xfffe || unit === 0xffff) {\n return index;\n }\n }\n\n return -1;\n}\n\n/**\n * Throws unless a text can be written into the XML header.\n *\n * The header is XML, which has no way to write a NUL, a surrogate without its pair or a control\n * character such as U+0001. The builder refused each with a bare `Error: Invalid character in string`,\n * naming neither the field nor the property. A read can produce such a text: the parser accepts a raw\n * control character in the header it reads, so a file carrying one in its table name read without\n * complaint and could not be written back.\n *\n * @param {string} value The text.\n * @param {string} subject What the text is, capitalised, as the message starts.\n * @param {Object} context Where the text came from, merged into the error's context.\n * @throws {QvdValidationError} If the text holds a character the header cannot; `context.position` is\n * its index.\n */\nfunction checkHeaderText(value, subject, context) {\n checkText(value, subject, context);\n\n const position = notXmlIndex(value);\n\n if (position !== -1) {\n const code = value.charCodeAt(position).toString(16).toUpperCase().padStart(4, '0');\n\n throw new QvdValidationError(`${subject} cannot contain U+${code}, which XML cannot hold`, {...context, position});\n }\n}\n\n/**\n * Checks every text in a part of the header: a string, or the strings inside an object or an array, as\n * the XML builder would write them.\n *\n * @param {any} value The value.\n * @param {string} property Its path in the header, such as `Lineage.LineageInfo.Statement`.\n * @param {string} owner What the property belongs to, for the message: `the table`, or a field.\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If a text holds a character the header cannot.\n */\nfunction checkHeaderTexts(value, property, owner, context) {\n if (typeof value === 'string') {\n checkHeaderText(value, `The ${property} of ${owner}`, {...context, property});\n } else if (Array.isArray(value)) {\n value.forEach((item, index) => checkHeaderTexts(item, `${property}[${index}]`, owner, context));\n } else if (value !== null && typeof value === 'object') {\n for (const [key, item] of Object.entries(value)) {\n checkHeaderTexts(item, `${property}.${key}`, owner, context);\n }\n }\n}\n\n/**\n * Checks the field names before a single row is walked.\n *\n * All three of these produced a file rather than an error. A non-string name was written as\n * whatever it stringified to; a duplicate produced two fields of one name, which makes\n * `at(row, name)` and `select(name)` answer about the first and ignore the second - and which\n * broke two-pass symbol filtering, because the usage sets were keyed by name (#181); and an empty\n * name produced a field nothing can address. A name the header cannot hold - see `checkHeaderText` -\n * is refused here too, before the rows rather than after them.\n *\n * @param {Array<any>} columns The field names.\n * @param {string} filePath The file being written, for the error.\n * @throws {QvdValidationError} If a name is not a usable, unique string.\n */\nfunction validateColumnNames(columns, filePath) {\n /** @type {Set<string>} */\n const seen = new Set();\n\n columns.forEach((name, index) => {\n if (typeof name !== 'string' || name.length === 0) {\n throw new QvdValidationError('Field names must be non-empty strings', {\n column: index,\n provided: name,\n type: typeof name,\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n checkHeaderText(name, 'A field name', {column: index, provided: name, file: filePath, stage: 'buildSymbolTable'});\n\n if (seen.has(name)) {\n throw new QvdValidationError(`Field '${name}' appears twice`, {\n column: name,\n columnIndex: index,\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n seen.add(name);\n });\n}\n\n/**\n * Refuses a cell that is neither a number, a string, a dual value nor NULL.\n *\n * Everything refused here previously produced either a raw `TypeError` from deep inside\n * `Buffer.from`, naming neither the field nor the row, or a file. The file cases are the reason\n * this is not merely a nicer error message: `[1, 2]` became `Buffer.from([1, 2])`, so the array was\n * written as the two *bytes* 1 and 2 and read back as two control characters; and a `Date` was\n * written as its full `toString()`, which carries the writing machine's timezone and locale into the\n * data.\n *\n * A `QvdSymbol` is refused too. It carries a storage kind, which the writer derives from the value\n * instead, and a dual symbol built through its factories was never a dual cell anyone could read back.\n * So is an object that only resembles a dual - `{number, text, date}`, or one that inherits the two\n * properties - because storing it as one would discard the rest of it without a word.\n *\n * Numbers and strings are checked in `cellRules`, which is where the other things that used to\n * produce a file are refused: a string containing a NUL, which ends a string symbol early and made\n * `toQvd` produce a file this same library refuses to read; a string containing an unpaired\n * surrogate, which UTF-8 cannot encode, so it was written as U+FFFD and two different strings could\n * become one stored value; and `NaN` or an infinity, which came back as the string `'NaN'` or as the\n * infinity itself.\n *\n * @param {any} value The value.\n * @param {string} column The field it belongs to, for the error.\n * @param {number} row The row it was first seen on, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {never}\n * @throws {QvdValidationError} Always.\n */\nfunction refuseCell(value, column, row, filePath) {\n let resemblesDual = false;\n\n try {\n resemblesDual =\n value !== null &&\n typeof value === 'object' &&\n ('number' in value || 'text' in value || ('intValue' in value && 'stringValue' in value));\n } catch {\n // A revoked Proxy throws from `in`. It resembles nothing.\n }\n\n throw new QvdValidationError(\n `A QVD field holds numbers, strings, dual values and NULL; ${describeType(value)} cannot be written. ` +\n `Convert it first - a Date to new QvdDual(dateToQlikSerial(date), text), the serial and the text Qlik shows, ` +\n `which is how Qlik stores a date; a boolean to -1 and 0, as a Qlik comparison stores it.` +\n (resemblesDual ? ' A dual value is a QvdDual, or an object whose only keys are number and text.' : ''),\n {\n column,\n row,\n type: typeof value,\n constructor: constructorName(value) ?? undefined,\n file: filePath,\n stage: 'buildSymbolTable',\n },\n );\n}\n\n/**\n * How many dual objects a column remembers by identity before it stops adding them: this many, plus\n * two for every symbol the column holds.\n *\n * A read shares one `QvdDual` per symbol between every row that holds it, so remembering each object\n * makes a repeat cost one lookup, as a repeated number does. A caller who builds a fresh object per\n * row would add one entry per row instead - two million rows, two million entries - so past the bound\n * an object is resolved by its number on every row, which costs a validation and a lookup and holds\n * nothing.\n */\nconst OBJECT_MEMO_BASE = 64;\n\n/**\n * One column's symbols while they are collected.\n *\n * `keys` and `texts` are the slots, in first-appearance order: a slot's key is its number or its\n * string, and its text is the text of a dual, or null. `byKey` maps a key to its slot, so one number is\n * one symbol however it arrived - a plain number, a dual object, a cell resolved through the record.\n * `byCell` maps a primitive cell to its slot, and is `byKey` itself unless the field has a record\n * entry that can map a cell to a different key. `byObject` remembers dual objects by identity, up to\n * a bound.\n *\n * A record entry is looked up one of two ways. When every value in it is its own number - as in every\n * entry a `{duals: 'number'}` read builds without `coerceNumericStrings` - a cell is still its own key,\n * and the entry only gives it a text: `textByNumber`. Any other entry can make a cell stand for another\n * key, or for more than one, and `byValue` lists every symbol holding each value, so all of them can be\n * weighed.\n *\n * @typedef {Object} ColumnSymbols\n * @property {string} name The field name.\n * @property {Array<number|string>} keys Each slot's number or string.\n * @property {Array<string|null>} texts Each slot's text, or null.\n * @property {Map<number|string, number>} byKey Key to slot.\n * @property {Map<number|string, number>} byCell Primitive cell to slot.\n * @property {Map<object, number>} byObject Dual object to slot, bounded.\n * @property {import('./util/storedSymbols.js').StoredSymbolsEntry|null} entry The field's record entry.\n * @property {Map<number|string, string>|null} textByNumber For an entry whose every value is its own\n * number, each number's first text.\n * @property {Map<number|string, number|Array<number>>|null} byValue For any other entry, each value's\n * index or indices in it.\n * @property {SlotFacts} facts What kinds of value the slots hold, for the header.\n */\n\n/**\n * What kinds of value a column's written symbols hold - what decides which of its tags and number\n * format still describe it.\n *\n * @typedef {Object} SlotFacts\n * @property {boolean} hasNumber Some symbol has a number: a pure number or a dual.\n * @property {boolean} hasNonNumber Some symbol is a pure string.\n * @property {boolean} hasFraction Some number is not a whole number.\n */\n\n/**\n * Whether every symbol in a record entry is keyed by the value its cell holds - the symbol's own number,\n * as it is for a dual read as its number and for a pure number recorded beside one.\n *\n * Such an entry cannot make a value ambiguous - each value stands for one number, and no symbol in it\n * is a string - and never maps a cell to a key other than itself. So the cell needs no map of its own\n * and no weighing of entries, only the text the first symbol holding it has.\n *\n * @param {import('./util/storedSymbols.js').StoredSymbolsEntry} entry The entry.\n * @return {boolean} True when every value is its symbol's number.\n */\nfunction valuesAreNumbers(entry) {\n const {values, numbers} = entry;\n\n // A pure string's number is null, which no value is the same as.\n for (let index = 0; index < values.length; index++) {\n if (!sameValueZero(values[index], numbers[index])) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * A slot added after the column's others, for a key it does not have. The caller puts the key in\n * `byKey`.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} key The number or string.\n * @param {string|null} text The text supplied with it, or null.\n * @return {number} The slot.\n */\nfunction newSlot(column, key, text) {\n const slot = column.keys.length;\n\n column.keys.push(key);\n column.texts.push(text);\n\n // Every slot is created here, so the facts cost nothing extra: no pass over the symbols afterwards.\n if (typeof key === 'number') {\n column.facts.hasNumber = true;\n if (!Number.isInteger(key)) column.facts.hasFraction = true;\n } else {\n column.facts.hasNonNumber = true;\n }\n\n return slot;\n}\n\n/**\n * The slot for a key, created at its first appearance.\n *\n * A text is attached to a number slot that has none, in place, whatever order the cells came in: a\n * plain number carries no text, so a dual with the same number supplies it rather than losing it. A\n * slot that already has a text keeps it, which is Qlik's rule - values sharing a number share the first\n * text encountered.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} key The number or string.\n * @param {string|null} text The text supplied with it, or null.\n * @return {number} The slot.\n */\nfunction slotFor(column, key, text) {\n let slot = column.byKey.get(key);\n\n if (slot === undefined) {\n slot = newSlot(column, key, text);\n column.byKey.set(key, slot);\n } else if (text !== null && column.texts[slot] === null && typeof key === 'number') {\n column.texts[slot] = text;\n }\n\n return slot;\n}\n\n/**\n * Whether some of a record entry's symbols say different things about the value they share: two\n * numbers, two texts of pure strings, or a number and a pure string. Those are the symbols one cell\n * could stand for, and the writer refuses to pick one.\n *\n * @param {ReadonlyArray<number>} indices Indices into the entry of symbols that read as one value.\n * @param {ReadonlyArray<number|null>} numbers The entry's numbers.\n * @param {ReadonlyArray<string|null>} texts The entry's texts.\n * @return {boolean} True when they stand for more than one stored value.\n */\nfunction standsForSeveral(indices, numbers, texts) {\n /** @type {number|null} */\n let number = null;\n /** @type {string|null} */\n let string = null;\n\n for (const index of indices) {\n if (numbers[index] !== null) {\n if (number === null) {\n number = numbers[index];\n } else if (!sameValueZero(number, numbers[index])) {\n return true;\n }\n } else if (string === null) {\n string = texts[index];\n } else if (string !== texts[index]) {\n return true;\n }\n }\n\n return number !== null && string !== null;\n}\n\n/**\n * Whether a field whose record entry this is could have been read with `{duals: 'text'}` and, read that\n * way without `coerceNumericStrings`, would still have a value that stands for more than one stored value.\n *\n * Without coercion such a read shows every symbol with a text as that text, and a pure number as itself,\n * so the entry's symbols are grouped that way and weighed as the writer weighs a cell. Every symbol that\n * could end up in such a group is in the entry already: a `'text'` read records every dual, and a string\n * with a dual's text is either numeric, so coercion read it as a number and recorded it, or not, so the\n * dual reads as that text with coercion too and the string is recorded beside it.\n *\n * A dual shown as its number whose text is not numeric proves the entry came from a `'number'` read,\n * because a `'text'` read shows that text. Without coercion a `'number'` read maps no value to two stored\n * values: every value it records is a number, and every symbol under one number has that number.\n *\n * @param {import('./util/storedSymbols.js').StoredSymbolsEntry} entry The entry.\n * @return {boolean} True when a `'text'` read without coercion could still be refused.\n */\nfunction ambiguousAsUncoercedText(entry) {\n const {values, numbers, texts} = entry;\n\n for (let index = 0; index < values.length; index++) {\n if (typeof values[index] === 'number' && numbers[index] !== null && texts[index] !== null) {\n // @ts-ignore - the text was just checked for null\n if (!isNumericText(texts[index])) {\n return false;\n }\n }\n }\n\n /** @type {Map<number|string|null, Array<number>>} */\n const byShown = new Map();\n\n for (let index = 0; index < values.length; index++) {\n const shown = texts[index] ?? numbers[index];\n const indices = byShown.get(shown);\n\n if (indices === undefined) {\n byShown.set(shown, [index]);\n } else {\n indices.push(index);\n }\n }\n\n for (const indices of byShown.values()) {\n if (indices.length > 1 && standsForSeveral(indices, numbers, texts)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether reading the field with `{duals: 'both'}`, coercion left as it was, would leave no value standing\n * for more than one stored value.\n *\n * `'both'` records no dual - each is a `QvdDual` cell of its own - so under a value such a read records the\n * entry's symbols less its duals: strings coercion read as that number, and pure symbols beside them. Every\n * one of those is in the entry already, whichever mode built it, because coercion and the pure symbols\n * beside what it records do not depend on the mode.\n *\n * @param {ColumnSymbols} column The column, whose entry has a value that stands for several stored values.\n * @return {boolean} True when `'both'` is enough.\n */\nfunction unambiguousWithoutDuals(column) {\n // @ts-ignore - only a column with a byValue map refuses a value, and it has an entry\n const {numbers, texts} = column.entry;\n\n // @ts-ignore - see above\n for (const found of column.byValue.values()) {\n if (typeof found !== 'number') {\n const kept = found.filter((/** @type {number} */ index) => numbers[index] === null || texts[index] === null);\n\n if (kept.length > 1 && standsForSeveral(kept, numbers, texts)) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * What to do about a field in which a value stands for more than one stored value - the end of that\n * refusal.\n *\n * It names the least change to the read after which no value of the field does, so it is worked out from\n * every value in the field's entry and not only the one refused: advice fitted to that one could lead to a\n * second refusal for another. The entry does not say which duals mode built it, only sometimes shows it: a\n * dual shown as its text comes from a `'text'` read, and one shown as its number whose text is not a\n * number from a `'number'` read. Where the least change depends on the mode, the sentence says how.\n *\n * - **No value stands for a string read as a number beside another stored value:** `{duals: 'both'}`, or\n * `QvdDual` cells. Coercion can stay on, because a string it reads as a number reads as that number in\n * every mode: had it made a value ambiguous, that value would be among the ones weighed.\n * - **One does, and dropping coercion is enough for any read:** without `coerceNumericStrings`. A string\n * then reads as itself, and under `'number'` and `'both'` nothing is left to record two stored values\n * under one value; see `ambiguousAsUncoercedText` for `'text'`.\n * - **Dropping coercion is not enough for a `'text'` read, and `{duals: 'both'}` is:** that, for any read.\n * A string `'4'` beside a dual 4 with the text `4` is the example: a `'text'` read without coercion shows\n * both as `'4'`, and `'both'` shows the dual as a `QvdDual`.\n * - **Neither is enough on its own for a `'text'` read:** both, when the entry shows a `'text'` read. When\n * it does not, the read may have been `'number'`, for which dropping coercion is enough, so the sentence\n * asks for `'both'` as well only if the field was read with `'text'`. Switching to `'number'` is not\n * enough either: it records every dual `'both'` leaves out, and what is ambiguous without them stays so.\n *\n * `'007'` and `'7'` read as 7 in every mode, so a refusal that named only `'both'` for them would send\n * the caller to a read that is refused again.\n *\n * @param {ColumnSymbols} column The column, whose entry has a value that stands for several stored values.\n * @return {string} The sentence.\n */\nfunction ambiguityRemedy(column) {\n // @ts-ignore - only a column with a byValue map refuses a value, and it has an entry\n const {values, numbers, texts} = column.entry;\n let coerced = false;\n let other = false;\n\n // @ts-ignore - see above\n for (const [value, found] of column.byValue) {\n if (typeof found !== 'number' && standsForSeveral(found, numbers, texts)) {\n // Under a value that is a number, every symbol with a number has that number, so what disagrees with\n // them is a pure string - and only coercion reads a pure string as a number.\n if (typeof value === 'number') {\n coerced = true;\n } else {\n other = true;\n }\n }\n }\n\n if (!coerced) {\n return \"Read the field with {duals: 'both'}, or write QvdDual cells.\";\n }\n\n // A value that is a string, and stands for several stored values, is a dual's text a 'text' read\n // showed, and dropping coercion leaves it as ambiguous as it was.\n // @ts-ignore - see above\n if (!other && !ambiguousAsUncoercedText(column.entry)) {\n return 'Read the field without {coerceNumericStrings: true}.';\n }\n\n if (unambiguousWithoutDuals(column)) {\n return \"Read the field with {duals: 'both'}.\";\n }\n\n // A dual shown as its text shows a 'text' read, and every value `other` counted is one.\n return values.some((value, index) => typeof value === 'string' && numbers[index] !== null)\n ? \"Read the field with {duals: 'both'} and without {coerceNumericStrings: true}.\"\n : \"Read the field without {coerceNumericStrings: true}, and with {duals: 'both'} as well if it was read \" +\n \"with {duals: 'text'}.\";\n}\n\n/**\n * The slot for a number or a string cell the column has not seen, through the frame's record.\n *\n * With no record entry for the value, the cell is its own key. Otherwise the entries holding it say\n * what it stands for: one pure string's text, or one number with the first text any of them has. When\n * they say more than one thing - two numbers, two texts, or a number and a string - the cell could be\n * either, and it is refused rather than written as one of them.\n *\n * The ambiguity is worked out here, from the entries themselves, rather than trusted to a read: a\n * record merged from two frames, or built by hand, is checked the same way. An entry whose every value\n * is its own number - see `valuesAreNumbers` - has no ambiguity to find, so the cell only takes its text.\n *\n * Called only for a cell the row loop has just looked for in `byCell` and not found, and whose slot the\n * row loop then puts there.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} value The cell.\n * @param {number} row The row, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {number} The slot.\n * @throws {QvdValidationError} If the record maps the value to more than one stored value.\n */\nfunction slotForCell(column, value, row, filePath) {\n // A cell that is its own key. `byCell` is `byKey` here, so the lookup that missed was for the key: the\n // slot is new, and the row loop's write of it is the write to `byKey`. Asking again, and writing twice,\n // cost two map operations per distinct value.\n if (column.byCell === column.byKey) {\n return newSlot(column, value, column.textByNumber === null ? null : (column.textByNumber.get(value) ?? null));\n }\n\n // @ts-ignore - a column whose cells have a map of their own has an entry that is not keyed by numbers\n const found = column.byValue.get(value);\n\n if (found === undefined) {\n return slotFor(column, value, null);\n }\n\n // @ts-ignore - byValue is only set together with entry\n const {numbers, texts} = column.entry;\n const indices = typeof found === 'number' ? [found] : found;\n\n if (standsForSeveral(indices, numbers, texts)) {\n /** @type {Array<{number: number|null, text: string|null}>} */\n const stored = [];\n\n for (const index of indices) {\n if (!stored.some((pair) => sameValueZero(pair.number, numbers[index]) && pair.text === texts[index])) {\n stored.push({number: numbers[index], text: texts[index]});\n }\n }\n\n throw new QvdValidationError(\n `The value ${JSON.stringify(value)} in field '${column.name}' (row ${row}) was read from ${stored.length} ` +\n `different stored values, so writing it back would have to guess which one. ${ambiguityRemedy(column)}`,\n {column: column.name, row, value, stored, file: filePath, stage: 'buildSymbolTable'},\n );\n }\n\n /** @type {number|null} */\n let number = null;\n /** @type {string|null} */\n let numberText = null;\n\n for (const index of indices) {\n // One stored value: a pure string here means every symbol holding the value is that string.\n if (numbers[index] === null) {\n // @ts-ignore - a symbol with no number has a text\n return slotFor(column, texts[index], null);\n }\n\n number ??= numbers[index];\n numberText ??= texts[index];\n }\n\n // @ts-ignore - every index came from an entry that holds a number or a text, and none was a string\n return slotFor(column, number, numberText);\n}\n\n/**\n * The slot for a dual object the column has not remembered.\n *\n * Keyed by its number, so a fresh object per row costs a validation and a lookup, and never a map\n * entry past the bound. Anything that is not a dual - see `asDual` - is refused.\n *\n * @param {ColumnSymbols} column The column.\n * @param {object} value The cell.\n * @param {number} row The row, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {number} The slot.\n * @throws {QvdValidationError} If the value is not a dual, or a half of it cannot be stored.\n */\nfunction slotForObject(column, value, row, filePath) {\n const dual = asDual(value);\n\n if (dual === null) {\n refuseCell(value, column.name, row, filePath);\n }\n\n const {number, text} = dual;\n\n // The problem functions allocate nothing for a good half, so the context is only built for a bad one.\n if (numberProblem(number) !== null) {\n checkNumber(number, 'The number of a dual value', {\n column: column.name,\n row,\n half: 'number',\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n if (textProblem(text) !== null) {\n checkText(text, 'The text of a dual value', {\n column: column.name,\n row,\n half: 'text',\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n const slot = slotFor(column, number, text);\n\n if (column.byObject.size < OBJECT_MEMO_BASE + 2 * column.keys.length) {\n column.byObject.set(value, slot);\n }\n\n return slot;\n}\n\n/** Tags that only hold while every value in the field has a number. */\nconst NUMERIC_TAGS = new Set(['$numeric', '$integer', '$date', '$time', '$timestamp']);\n\n/** Tags that only hold while every value in the field is plain text. */\nconst TEXT_TAGS = new Set(['$text', '$ascii']);\n\n/** Tags that only hold while every number in the field is a whole number. */\nconst WHOLE_NUMBER_TAGS = new Set(['$integer', '$date']);\n\n/** Number formats that describe how Qlik displays a number, and so mean nothing on a text field. */\nconst NUMERIC_FORMATS = new Set(['INTEGER', 'REAL', 'FIX', 'MONEY', 'DATE', 'TIME', 'TIMESTAMP', 'INTERVAL']);\n\n/** What a field with no number format of its own is written with. */\nconst UNKNOWN_NUMBER_FORMAT = Object.freeze({Type: 'UNKNOWN', nDec: '0', UseThou: '0', Fmt: '', Dec: '', Thou: ''});\n\n/**\n * The field's tags, less any the written values contradict.\n *\n * Tags are carried from the header a frame was read with, and a caller can change a field's values\n * without touching its tags - read a timestamp field with `{duals: 'text'}` and write it back, and the\n * values are text while the header still says `$numeric` and `$timestamp`, which tells Qlik a text\n * field is numeric. So a tag the values contradict is dropped:\n *\n * - a value with no number drops `$numeric`, `$integer`, `$date`, `$time` and `$timestamp`;\n * - a number that is not whole drops `$integer` and `$date`;\n * - any number drops `$text` and `$ascii`.\n *\n * The definitions are Qlik's field-tag help: `$numeric` - every non-NULL value is numeric; `$integer`\n * - every value is an integer; `$date` - every value can be read as a date, which it defines as an\n * integer; `$text` - no value is numeric. The bundled Qlik files agree where they can: `$text` and\n * `$ascii` appear only on fields whose every value is a pure string, and a field mixing strings and\n * numbers carries neither. They also show what not to derive. Qlik keeps `$ascii` on fields holding\n * characters outside ASCII - their first such value is always past the hundredth symbol, so it looks\n * like a judgement from the first values rather than all of them - and keeps `$timestamp` on a field of\n * timestamps some of which fall exactly on midnight, so a whole number does not contradict it. The\n * reference files in `docs/reference-qvds/` carry `$date`, and only on fields whose every number is\n * whole, which is what the `$date` rule assumes. No file carries `$time`, not even a field Qlik built\n * with `Time()`, so that rule still rests on the help alone.\n *\n * Only removes, never adds. A tag Qlik would have added is Qlik's to add on its next load; inventing\n * one here would be the writer asserting something it has no way to know - `$date` over an integer\n * field, say. `$key`, `$hidden` and custom tags pass through.\n *\n * @param {any} tags The field's tags as carried in the metadata: `{String: string | string[]}`, or\n * something else, which is returned untouched.\n * @param {SlotFacts|undefined} facts What the field's written symbols hold.\n * @return {any} The tags to write.\n */\nfunction pruneContradictedTags(tags, facts) {\n if (tags === null || typeof tags !== 'object' || tags.String === undefined || facts === undefined) {\n return tags || {};\n }\n\n const list = Array.isArray(tags.String) ? tags.String : [tags.String];\n const kept = list.filter((/** @type {string} */ tag) => {\n if (facts.hasNonNumber && NUMERIC_TAGS.has(tag)) return false;\n if (facts.hasFraction && WHOLE_NUMBER_TAGS.has(tag)) return false;\n if (facts.hasNumber && TEXT_TAGS.has(tag)) return false;\n return true;\n });\n\n if (kept.length === list.length) {\n return tags;\n }\n\n return kept.length === 0 ? {} : {...tags, String: kept};\n}\n\n/**\n * The field's number format, reset when the field no longer holds a number to apply it to.\n *\n * A `DATE` or `MONEY` format on a field whose values are all text describes nothing, and misleads\n * whoever reads the header next. A field that still has a single number keeps its format: Qlik's own\n * files carry `REAL` on a field holding only the integer 0 and `MONEY` on fields where some amounts are integers,\n * so no other mismatch is a contradiction.\n *\n * @param {any} numberFormat The field's number format as carried in the metadata.\n * @param {SlotFacts|undefined} facts What the field's written symbols hold.\n * @return {any} The number format to write.\n */\nfunction resetContradictedNumberFormat(numberFormat, facts) {\n if (!numberFormat) {\n return {...UNKNOWN_NUMBER_FORMAT};\n }\n\n if (facts !== undefined && !facts.hasNumber && facts.hasNonNumber && NUMERIC_FORMATS.has(numberFormat.Type)) {\n return {...UNKNOWN_NUMBER_FORMAT};\n }\n\n return numberFormat;\n}\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 /**\n * Symbols written per column. It used to be the symbols themselves, as QvdSymbol objects, kept\n * alive through the header build and the file write for the sake of their count.\n *\n * @type {Array<number>|null}\n */\n this._symbolCounts = null;\n /** @type {Array<SlotFacts>|null} What each column's symbols hold, for pruning its tags. */\n this._symbolFacts = null;\n /** @type {Array<any>|null} */\n this._symbolTableMetadata = null;\n this._indexBuffer = null;\n /**\n * How each column's cells find their stored index: the slot maps `_buildSymbolTable` built.\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<{byCell: Map<number|string, number>, byKey: Map<number|string, number>,\n * byObject: Map<object, 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._symbolCounts?.[index],\n Offset: this._symbolTableMetadata?.[index][0],\n Length: this._symbolTableMetadata?.[index][1],\n Comment: existingField?.Comment || '',\n NumberFormat: resetContradictedNumberFormat(existingField?.NumberFormat, this._symbolFacts?.[index]),\n Tags: pruneContradictedTags(existingField?.Tags, this._symbolFacts?.[index]),\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 // Every text the builder is about to write, so a character XML cannot hold is refused naming the\n // property it is in. The field names were checked before the rows were.\n const {Fields, ...table} = xmlObject.QvdTableHeader;\n\n for (const [property, value] of Object.entries(table)) {\n checkHeaderTexts(value, property, 'the table', {file: this._path, stage: 'buildHeader'});\n }\n\n for (const {FieldName, ...field} of Fields.QvdFieldHeader) {\n for (const [property, value] of Object.entries(field)) {\n checkHeaderTexts(value, property, `field '${FieldName}'`, {\n column: FieldName,\n file: this._path,\n stage: 'buildHeader',\n });\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 * One pass over the rows finds each column's distinct values in the order they first appear,\n * which is the order Qlik lists symbols in, and checks each distinct value once. A second pass per\n * column encodes them: every symbol is sized first, then written into one buffer of exactly that\n * size.\n *\n * What each value is stored as:\n *\n * | Cell | Symbol |\n * | --- | --- |\n * | `null`, `undefined`, a hole, a missing cell | none - the field's `Bias` records NULL |\n * | an integer from -2147483648 to 2147483647, -0 included | pure int, type 1 |\n * | any other finite number | pure double, type 2 |\n * | a string | pure string, type 4 |\n * | a dual - a `QvdDual`, or an object whose only keys are `number` and `text` | dual int or dual double, type 5 or 6, by the number |\n * | a number or a string the frame's `storedSymbols` records | the symbol it was read from |\n *\n * A number is a pure number, with no text. It used to be written as a dual whose text was\n * `String(value)`, which was wrong twice over: it invented text the caller never supplied, and a\n * file Qlik wrote with pure numbers came back out of a read and a write with every one of them\n * turned into a dual. The kind follows `isStoredAsInt`, which is the rule Qlik's own files follow.\n * A string is never parsed, so `'7'` and `7` in one column are two symbols. It is stored as its\n * UTF-8 bytes, or refused where those bytes would not give it back: a NUL ends a stored text, and\n * an unpaired surrogate has no UTF-8 encoding at all.\n *\n * A column holds one symbol per number, as a Qlik field does. Several duals with one number are one\n * symbol with the first text in row order, and a plain number with the same number as a dual joins\n * the dual, in either order - so no text a caller supplied is lost to a plain number that came\n * first. A string is not a number, so a string equal to a dual's text is a symbol of its own.\n *\n * A frame read from a file shows one half of some symbols: a dual read as its number or its text, a\n * string read as a number. Its record says what each such cell stands for, so the frame writes back\n * the symbols it was read from - the dual's text, Qlik's exact double, the string `'007'` - whichever\n * rows the cells were moved to. A cell the record maps to more than one stored value is refused.\n *\n * The complexity claim is the one to trust here: O(rows x columns) for the pass, and O(symbols)\n * for the encoding. The \"80-90% improvement\" this comment once carried is not reproducible in this\n * repository; `benchmarks/` measures what the writer costs now, which is the useful number.\n *\n * @private\n */\n _buildSymbolTable() {\n this._symbolCounts = [];\n this._symbolFacts = [];\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 validateColumnNames(columns, this._path);\n\n // Through the same check a frame's constructor applies, which costs nothing for a record that came\n // from a read or was already checked, and refuses a malformed one handed to the writer directly.\n const record = normaliseStoredSymbols(this._df.storedSymbols);\n\n this._emitProgress('symbol-table', 0, numColumns);\n\n // Per column, the slots in first-appearance order and the maps that find them - see\n // ColumnSymbols. A Map compares keys by SameValueZero, so a number is one symbol however many rows\n // hold it, and 0 and -0 in one column are one symbol - which isStoredAsInt stores as the integer 0\n // either way.\n //\n // No third structure: this used to be a Set per column, then `Array.from` on it, then a Map built\n // from the array, three structures each holding a reference to every distinct value. On a column\n // whose values are all distinct that was roughly 30MB of duplication per million rows.\n /** @type {Array<ColumnSymbols>} */\n const state = columns.map((/** @type {string} */ name) => {\n const entry = record === null ? null : (record.find((candidate) => candidate.field === name) ?? null);\n /** @type {Map<number|string, number>} */\n const byKey = new Map();\n /** @type {Map<number|string, number|Array<number>>|null} */\n let byValue = null;\n /** @type {Map<number|string, string>|null} */\n let textByNumber = null;\n\n if (entry !== null && valuesAreNumbers(entry)) {\n textByNumber = firstTextByValue(entry);\n } else if (entry !== null) {\n byValue = new Map();\n\n // An index per value, and an array only for a value two entries share, which a record read from\n // a Qlik file never has: a field of distinct duals costs a map entry per value, not an array.\n for (let index = 0; index < entry.values.length; index++) {\n const found = byValue.get(entry.values[index]);\n\n if (found === undefined) {\n byValue.set(entry.values[index], index);\n } else if (typeof found === 'number') {\n byValue.set(entry.values[index], [found, index]);\n } else {\n found.push(index);\n }\n }\n }\n\n return {\n name,\n keys: [],\n texts: [],\n byKey,\n // A cell is its own key without a record entry, and with one whose values are their numbers, so\n // one Map serves both. On a field of distinct duals that is a map entry per symbol fewer.\n byCell: entry === null || textByNumber !== null ? byKey : new Map(),\n byObject: new Map(),\n entry,\n textByNumber,\n byValue,\n facts: {hasNumber: false, hasNonNumber: false, hasFraction: false},\n };\n });\n\n // Hoisted out of the column objects, so the row loop's common case - a value the column has seen\n // - is an array read and a Map lookup, as it was before the column had anything else to keep.\n const byCells = state.map((column) => column.byCell);\n const byObjects = state.map((column) => column.byObject);\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 // A missing row is a row of NULLs, which is what a hole in a sparse array already means.\n // A row that is present but is not an array is different: `values?.[column]` reads\n // `undefined` from it for every column, so `{columns: ['a'], data: [1, 2]}` used to write a\n // two-row file of NULLs and report success, discarding everything the caller passed.\n if (values !== null && values !== undefined && !Array.isArray(values)) {\n throw new QvdValidationError('Each row must be an array of values', {\n row,\n type: typeof values,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n // A short row is padded with NULLs, deliberately. A long one is not truncated, because\n // dropping the extra cells silently is how a caller whose columns and data have drifted\n // apart gets a plausible file with a column missing.\n if (values !== null && values !== undefined && values.length > numColumns) {\n throw new QvdValidationError(`Row ${row} has ${values.length} values but there are ${numColumns} fields`, {\n row,\n values: values.length,\n fields: numColumns,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\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 // A dual object is looked up by identity in its own map, so the primitive map is never asked\n // about an object it cannot hold.\n if (typeof value === 'object') {\n if (!byObjects[column].has(value)) {\n slotForObject(state[column], value, row, this._path);\n }\n\n continue;\n }\n\n // A primitive the column has already seen costs this one lookup, as it did before duals.\n if (byCells[column].has(value)) {\n continue;\n }\n\n // Once per distinct value, not once per row: a repeat has already been through this. The\n // problem functions allocate nothing for a good value, so the context object is only built\n // for a value that is about to be refused.\n if (typeof value === 'number') {\n if (numberProblem(value) !== null) {\n checkNumber(value, null, {column: columns[column], row, file: this._path, stage: 'buildSymbolTable'});\n }\n } else if (typeof value === 'string') {\n if (textProblem(value) !== null) {\n checkText(value, 'A string value', {\n column: columns[column],\n row,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n } else {\n refuseCell(value, columns[column], row, this._path);\n }\n\n byCells[column].set(value, slotForCell(state[column], value, row, this._path));\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 {keys, texts} = state[column];\n const kinds = new Uint8Array(keys.length);\n let byteLength = 0;\n\n for (let slot = 0; slot < keys.length; slot++) {\n const key = keys[slot];\n const text = texts[slot];\n\n if (typeof key === 'number') {\n // Both halves were checked when the cell was, or when the record was; this is the last look\n // before the bytes are written. A record a read built is taken as the file stored it, so a\n // damaged file's NaN dual read as its text reaches a slot only through the record - and is\n // refused here as the NaN cell it stands for would have been.\n if (numberProblem(key) !== null) {\n checkNumber(key, null, {column: columns[column], file: this._path, stage: 'buildSymbolTable'});\n }\n\n if (text !== null && textProblem(text) !== null) {\n checkText(text, 'The text of a dual value', {\n column: columns[column],\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n kinds[slot] = kindOf(key, text);\n byteLength += symbolByteLength(kinds[slot], key, text);\n } else {\n kinds[slot] = kindOf(null, key);\n byteLength += symbolByteLength(kinds[slot], null, key);\n }\n }\n\n // allocUnsafe, because every byte is about to be written. The assertion below holds it to that:\n // a byte left unwritten would carry whatever memory the buffer was given into the file.\n const columnBuffer = Buffer.allocUnsafe(byteLength);\n let offset = 0;\n\n for (let slot = 0; slot < keys.length; slot++) {\n const key = keys[slot];\n\n offset =\n typeof key === 'number'\n ? writeSymbol(columnBuffer, offset, kinds[slot], key, texts[slot])\n : writeSymbol(columnBuffer, offset, kinds[slot], null, key);\n }\n\n assert(offset === byteLength, 'A column was encoded into a different number of bytes than it was sized for.');\n\n columnBuffers.push(columnBuffer);\n this._symbolTableMetadata?.push([symbolsOffset, byteLength, containsNull[column]]);\n this._symbolCounts?.push(keys.length);\n this._symbolFacts?.push(state[column].facts);\n this._symbolIndexByValue?.push({\n byCell: state[column].byCell,\n byKey: state[column].byKey,\n byObject: state[column].byObject,\n });\n\n symbolsOffset += byteLength;\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._symbolCounts, '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._symbolCounts[column];\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 these maps, so validating the\n // maps 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 const lookup = this._symbolIndexByValue[column];\n const maps = lookup.byCell === lookup.byKey ? [lookup.byKey, lookup.byObject] : Object.values(lookup);\n\n for (const map of maps) {\n for (const index of map.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\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 // Hoisted, as in the symbol table pass, so a cell costs one array read and one lookup.\n const byCells = this._symbolIndexByValue.map((lookup) => lookup.byCell);\n const byKeys = this._symbolIndexByValue.map((lookup) => lookup.byKey);\n const byObjects = this._symbolIndexByValue.map((lookup) => lookup.byObject);\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 // A dual object is remembered by identity up to a bound, and past it found by its number, which\n // the symbol table pass has already checked for this same object.\n const index =\n typeof value === 'object'\n ? (byObjects[column].get(value) ?? byKeys[column].get(value.number))\n : byCells[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 * 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: ${formatCount(recommendedValue)} rows or less).`;\n } else {\n advice = `Try holding fewer rows using the ${knob} parameter (recommended: ${formatCount(recommendedValue)} 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 * Formats a row count for a human reading a diagnostic.\n *\n * Pinned to `en-US` rather than left to `toLocaleString()`'s default, which follows the host's\n * locale. The messages here are English prose, so a number grouped by the machine's convention was\n * inconsistent with the sentence around it - and worse, it made the same message differ between\n * platforms: `9,999,999` on the Linux and macOS runners against `9 999 999` on the Windows ones,\n * where the separator is a narrow no-break space. That is invisible until something matches on the\n * text. A test of this module's warning did, and passed everywhere it was run before failing all\n * three Windows legs in CI.\n *\n * The same property matters outside tests: a diagnostic that reads the same on every platform is\n * one a caller can grep for in a log aggregator collecting from all three.\n *\n * @param {number} value The count.\n * @return {string} The count, grouped the same way everywhere.\n */\nfunction formatCount(value) {\n return value.toLocaleString('en-US');\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 ${formatCount(rowsToLoad)} of ${formatCount(totalRows)} 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 {QvdCorruptedError, QvdParseError} from '../QvdErrors.js';\n\n/**\n * The longest text one symbol may hold. A damaged file cannot then make the reader decode a string the\n * size of the whole symbol table.\n */\nconst MAX_TEXT_BYTES = 1048576;\n\n/**\n * One field's symbols, as the two halves each can have, decoded straight from the symbol table's bytes.\n *\n * A pure number has a number and no text, a pure string a text and no number, and a dual both. A symbol\n * the two-pass path did not need has neither: nothing was decoded for it, and every symbol a file holds\n * has at least one half, so null in both cannot be mistaken for a value.\n *\n * Two arrays per field rather than an object per symbol. The reader resolves what each symbol reads as\n * from these, once, and nothing else keeps them; a high-cardinality field used to allocate a symbol\n * object, a result object and two typed arrays for every numeric value it held.\n *\n * A read reports what the file holds, unchecked: a damaged file's NaN double reads as NaN, and it is the\n * writer that refuses to store it again.\n *\n * @typedef {Object} FieldSymbols\n * @property {Array<number|null>} numbers Each symbol's number: an int's, a double's or a dual's.\n * @property {Array<string|null>} texts Each symbol's text: a string's or a dual's.\n */\n\n/**\n * Where the text starting at `from` ends: the index of its NUL terminator.\n *\n * @param {Buffer} symbolBuffer The symbol table.\n * @param {number} from The first byte of the text.\n * @param {string} kind 'String symbol' or 'Dual string symbol', for the error.\n * @param {string} fieldName The field, for the error.\n * @param {string} filePath The file, for the error.\n * @return {number} The index of the terminator.\n * @throws {QvdCorruptedError} If the text runs past the longest a symbol may hold, or has no terminator.\n */\nfunction textEnd(symbolBuffer, from, kind, fieldName, filePath) {\n const bufferLength = symbolBuffer.length;\n const found = symbolBuffer.indexOf(0, from);\n\n if ((found === -1 ? bufferLength : found) - from > MAX_TEXT_BYTES) {\n throw new QvdCorruptedError(`${kind} exceeds maximum length`, {\n field: fieldName,\n maxLength: MAX_TEXT_BYTES,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n if (found === -1) {\n throw new QvdCorruptedError(`${kind} not null-terminated`, {\n field: fieldName,\n pointer: bufferLength,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return found;\n}\n\n/**\n * Refuses a number that would be read past the end of the symbol table.\n *\n * @param {string} message What was being read.\n * @param {number} pointer The first byte of the number.\n * @param {number} bufferLength The symbol table's length.\n * @param {string} fieldName The field, for the error.\n * @param {string} filePath The file, for the error.\n * @return {never}\n * @throws {QvdCorruptedError} Always.\n */\nfunction overflow(message, pointer, bufferLength, fieldName, filePath) {\n throw new QvdCorruptedError(message, {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n}\n\n/**\n * Decodes one field's symbols from the symbol table.\n *\n * Each symbol is a type byte - 1 int, 2 double, 4 string, 5 dual int, 6 dual double - then a 4-byte\n * int or 8-byte double, then a NUL-terminated UTF-8 text, as the type says. A symbol outside `keep` is\n * walked past without decoding, but its length still has to be found, and a text's terminator is\n * checked either way.\n *\n * @param {Buffer} symbolBuffer The whole symbol table.\n * @param {number} start The field's first byte in it.\n * @param {number} end The byte after the field's last.\n * @param {Set<number>|null} keep The symbols to decode, by index, or null for all of them.\n * @param {string} fieldName The field, for errors.\n * @param {string} filePath The file, for errors.\n * @return {FieldSymbols} The field's symbols.\n * @throws {QvdCorruptedError} If a symbol runs past the end of the symbol table.\n * @throws {QvdParseError} If a type byte is not one of the five.\n */\nexport function parseFieldSymbols(symbolBuffer, start, end, keep, fieldName, filePath) {\n const bufferLength = symbolBuffer.length;\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n let pointer = start;\n\n while (pointer < end) {\n const typeByte = symbolBuffer[pointer++];\n const decode = keep === null || keep.has(numbers.length);\n let number = null;\n let text = null;\n\n switch (typeByte) {\n case 1: {\n if (decode) {\n if (pointer + 4 > bufferLength) {\n overflow('Buffer overflow reading integer symbol', pointer, bufferLength, fieldName, filePath);\n }\n number = symbolBuffer.readInt32LE(pointer);\n }\n pointer += 4;\n break;\n }\n case 2: {\n if (decode) {\n if (pointer + 8 > bufferLength) {\n overflow('Buffer overflow reading double symbol', pointer, bufferLength, fieldName, filePath);\n }\n number = symbolBuffer.readDoubleLE(pointer);\n }\n pointer += 8;\n break;\n }\n case 4: {\n const terminator = textEnd(symbolBuffer, pointer, 'String symbol', fieldName, filePath);\n if (decode) {\n text = symbolBuffer.toString('utf8', pointer, terminator);\n }\n pointer = terminator + 1;\n break;\n }\n case 5:\n case 6: {\n const numberBytes = typeByte === 5 ? 4 : 8;\n if (pointer + numberBytes > bufferLength) {\n const read = !decode ? 'dual symbol' : typeByte === 5 ? 'dual integer symbol' : 'dual double symbol';\n overflow(`Buffer overflow reading ${read}`, pointer, bufferLength, fieldName, filePath);\n }\n\n const terminator = textEnd(symbolBuffer, pointer + numberBytes, 'Dual string symbol', fieldName, filePath);\n if (decode) {\n number = typeByte === 5 ? symbolBuffer.readInt32LE(pointer) : symbolBuffer.readDoubleLE(pointer);\n text = symbolBuffer.toString('utf8', pointer + numberBytes, terminator);\n }\n pointer = terminator + 1;\n break;\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 numbers.push(number);\n texts.push(text);\n }\n\n return {numbers, texts};\n}\n","// @ts-check\n\nimport {dualFromSymbol} from '../QvdDual.js';\nimport {isNumericText} from './cellRules.js';\n\n/**\n * @typedef {import('./storedSymbols.js').StoredSymbolsEntry} StoredSymbolsEntry\n */\n\n/**\n * Both halves of each symbol of a field, aligned with its symbols: the text, or null for a pure\n * number, and the number, or null for a pure string.\n *\n * What a columnar read keeps for a field whose cells do not show every half, so a column can answer\n * `textAt` and give a date read as text its serial.\n *\n * @typedef {Object} SymbolHalves\n * @property {ReadonlyArray<string|null>} texts Each symbol's text.\n * @property {ReadonlyArray<number|null>} numbers Each symbol's number.\n */\n\n/**\n * What one field's symbols read as, and what has to be kept so they write back as the same symbols.\n *\n * Runs once per symbol, not once per cell: every row holding a symbol shares the value resolved here.\n *\n * A symbol reads as follows, the representation depending only on its type and the options - never on\n * the other symbols of the field, and never on the window:\n *\n * | Symbol | `'number'` (default) | `'text'` | `'both'` |\n * | --- | --- | --- | --- |\n * | int, double | the number | the number | the number |\n * | string | the string | the string | the string |\n * | string, numeric text, `coerce` on | `Number(text)` | `Number(text)` | `Number(text)` |\n * | dual | its number | its text | a frozen `QvdDual` |\n * | dual, numeric text, `coerce` on | its number | its number | a frozen `QvdDual` |\n * | NULL | null | null | null |\n *\n * A numeric text is one `isNumericText` accepts. `coerce` reaches only a cell that would otherwise be a\n * string: a string symbol in every mode, and a dual under `'text'`. A dual's numeric text reads as the\n * number Qlik *stored*, not as `Number(text)`, so a dual's number is the same in every mode that shows it.\n * The two need not be close. A text that spells the number can still parse to the double beside it -\n * Qlik stores 1.1400000000000001 for `1.14` - and a text that shows it rounded, or shows another value\n * such as a date as `20160113`, parses to a different number altogether.\n *\n * Wherever a cell shows only one half, the symbol is recorded, keyed by the value the cell holds, in\n * symbol order - which for a Qlik file is the order values first appear. That is pass A. Pass B runs\n * only for a field in which pass A recorded something and which also holds pure symbols: a pure\n * symbol that reads as a value already recorded is recorded too, so the writer can see that the value\n * stands for two different symbols and refuse it, rather than silently writing both as one. A Qlik\n * file keeps one symbol per value in a field, so for one pass B finds nothing to add.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols, both halves null where\n * the two-pass path did not decode one.\n * @param {string} field The field name, for the record.\n * @param {'number'|'text'|'both'} mode The `duals` option.\n * @param {boolean} coerce Whether a numeric text reads as a number.\n * @param {boolean} wantHalves Whether to return both halves of every symbol, for a columnar read.\n * @return {{values: Array<any>, entry: StoredSymbolsEntry|null, halves: SymbolHalves|null}} The value of\n * each symbol - undefined where it was filtered out - the field's record entry, or null when every\n * cell shows its whole symbol, and the halves when asked for and the field has a symbol whose cell\n * does not show both.\n */\nexport function resolveFieldSymbols(symbols, field, mode, coerce, wantHalves) {\n const length = symbols.numbers.length;\n const values = new Array(length);\n\n // Pass A's entries, in symbol order. Pushed as they are found rather than marked and collected,\n // because a field read from a Qlik file never needs pass B to add anything.\n /** @type {Array<number|string>} */\n const entryValues = [];\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n let pure = 0;\n let partial = false;\n\n for (let index = 0; index < length; index++) {\n const text = symbols.texts[index];\n const number = symbols.numbers[index];\n\n if (text === null) {\n // Neither half: a symbol the two-pass path did not decode, which no row of the window uses.\n values[index] = number === null ? undefined : number;\n if (number !== null) pure++;\n continue;\n }\n\n if (number === null) {\n if (coerce && isNumericText(text)) {\n values[index] = Number(text);\n entryValues.push(values[index]);\n numbers.push(null);\n texts.push(text);\n partial = true;\n } else {\n values[index] = text;\n pure++;\n }\n\n continue;\n }\n\n partial = true;\n\n if (mode === 'both') {\n // One frozen QvdDual per symbol, shared by every row holding it. Only this mode builds one; the\n // parser never does.\n values[index] = dualFromSymbol(number, text);\n continue;\n }\n\n values[index] = mode === 'number' || (coerce && isNumericText(text)) ? number : text;\n entryValues.push(values[index]);\n numbers.push(number);\n texts.push(text);\n }\n\n /** @type {StoredSymbolsEntry|null} */\n let entry = null;\n\n if (entryValues.length > 0) {\n entry =\n pure > 0 && collides(symbols, values, new Set(entryValues))\n ? collisionEntry(symbols, field, values, mode)\n : Object.freeze({\n field,\n values: Object.freeze(entryValues),\n numbers: Object.freeze(numbers),\n texts: Object.freeze(texts),\n });\n }\n\n return {values, entry, halves: wantHalves && partial ? symbolHalves(symbols) : null};\n}\n\n/**\n * Whether a pure symbol reads as a value pass A recorded - pass B's question.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {Array<any>} values What each symbol reads as.\n * @param {Set<any>} recorded The values pass A recorded. A Set compares by SameValueZero, the same\n * equality the writer's Map uses to look a cell up.\n * @return {boolean} True when one does.\n */\nfunction collides(symbols, values, recorded) {\n for (let index = 0; index < values.length; index++) {\n if (!isPure(symbols, index, values[index])) {\n continue;\n }\n\n if (recorded.has(values[index])) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether a symbol's cell shows the whole symbol: a pure number, or a pure string read as itself.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {number} index The symbol.\n * @param {any} value What it reads as.\n * @return {boolean} True for a pure symbol pass A did not record; false for one never decoded.\n */\nfunction isPure(symbols, index, value) {\n const text = symbols.texts[index];\n const number = symbols.numbers[index];\n\n return text === null ? number !== null : number === null && value === text;\n}\n\n/**\n * A field's record entry when pass B has something to add: pass A's symbols, and every pure symbol\n * that reads as one of their values, all in symbol order.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {string} field The field name.\n * @param {Array<any>} values What each symbol reads as.\n * @param {'number'|'text'|'both'} mode The `duals` option.\n * @return {StoredSymbolsEntry} The frozen entry.\n */\nfunction collisionEntry(symbols, field, values, mode) {\n const recorded = new Set();\n /** @type {Array<boolean>} */\n const inPassA = values.map((value, index) => {\n if ((symbols.numbers[index] === null && symbols.texts[index] === null) || isPure(symbols, index, value)) {\n return false;\n }\n\n // A dual read as a half, or a string coerced to a number. A 'both' dual is its own QvdDual cell.\n const recordedHere = !(mode === 'both' && symbols.texts[index] !== null && symbols.numbers[index] !== null);\n\n if (recordedHere) {\n recorded.add(values[index]);\n }\n\n return recordedHere;\n });\n\n /** @type {Array<number|string>} */\n const entryValues = [];\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n\n for (let index = 0; index < values.length; index++) {\n if (inPassA[index] || (isPure(symbols, index, values[index]) && recorded.has(values[index]))) {\n entryValues.push(values[index]);\n numbers.push(symbols.numbers[index]);\n texts.push(symbols.texts[index]);\n }\n }\n\n return Object.freeze({\n field,\n values: Object.freeze(entryValues),\n numbers: Object.freeze(numbers),\n texts: Object.freeze(texts),\n });\n}\n\n/**\n * Both halves of every symbol of a field: the decoded arrays themselves, frozen, since nothing else\n * holds them once the read resolves.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @return {SymbolHalves} The halves, null for a filtered-out symbol.\n */\nfunction symbolHalves(symbols) {\n return Object.freeze({texts: Object.freeze(symbols.texts), numbers: Object.freeze(symbols.numbers)});\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {asDual} from './util/cellRules.js';\nimport {readerOptionsFrom, windowFrom} from './util/readOptions.js';\n\n/**\n * @typedef {import('./util/resolveSymbols.js').SymbolHalves} SymbolHalves\n */\n\n/**\n * The number a symbol's value stands for, or NaN.\n *\n * A number is itself and a dual is its number. A string is NaN, unless the read kept its halves and\n * the symbol has a number - a dual read as its text, such as a date read with `{duals: 'text'}`, whose\n * serial is still the value Qlik sums and compares by.\n *\n * @param {any} value The symbol's value.\n * @param {number|null} number The symbol's stored number, from its halves, or null.\n * @return {number} The number.\n */\nfunction numberOf(value, number) {\n if (typeof value === 'number') {\n return value;\n }\n\n if (typeof value === 'string') {\n return number ?? NaN;\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.number === 'number' ? dual.number : NaN;\n}\n\n/**\n * The text a symbol's value stands for, derived from the value alone.\n *\n * @param {any} value The symbol's value.\n * @return {string|null} A string itself, a dual's text, or null.\n */\nfunction textOf(value) {\n if (typeof value === 'string') {\n return value;\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.text === 'string' ? dual.text : null;\n}\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\n * `chicago_taxi_rides_2016_01` fixture, read with the default options, **exactly one of its 20\n * columns is strictly numeric** - `trip_start_timestamp`, whose timestamps read as numbers - and\n * two are 100% strings: `pickup_census_tract`, every cell of it blank, and `payment_type`.\n * `dropoff_census_tract` is 43.3% empty strings, and a `Float64Array` of values would put NaN in\n * all of those rows 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 * @param {SymbolHalves|null} [halves=null] Both halves of each symbol, aligned with `symbols`, for a\n * field whose values do not show them all - a dual read as one half, a string read as a number.\n * Without them, the halves are derived from the values: a string is its own text, a dual has its\n * own, and a number has none.\n */\n constructor(name, codes, symbols, halves = null) {\n this._name = name;\n this._codes = codes;\n this._symbols = symbols;\n this._halves = halves;\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 * A windowed read that filters the symbol table decodes only the symbols its rows use. Every other\n * entry is `undefined` - not `null`, which a QVD never stores as a symbol - and no code refers to it.\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 * The text of one row: the text Qlik displays for its value.\n *\n * A string is its own text and a dual has its own. A value read as one half of a symbol - a date\n * read as its serial, a string read as a number - has the text the file stores for it, and a pure\n * number has none.\n *\n * @param {number} row The row index.\n * @return {string|null} The text, or null for NULL and for a number with no text.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n textAt(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 if (code < 0) {\n return null;\n }\n\n return this._halves !== null ? (this._halves.texts[code] ?? null) : textOf(this._symbols[code]);\n }\n\n /**\n * The text of each distinct value, indexed by the codes, as `textAt` gives it per row.\n *\n * @return {ReadonlyArray<string|null>} One text per symbol, null where a symbol has none.\n */\n symbolTexts() {\n if (this._halves !== null) {\n return this._halves.texts;\n }\n\n return Object.freeze(this._symbols.map(textOf));\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 * A dual is its number, however it was read: a `QvdDual` gives `.number`, and a date read with\n * `{duals: 'text'}` gives the serial the file stores for it, not NaN.\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 out[index] = numberOf(this._symbols[index], this._halves?.numbers[index] ?? null);\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. A dual is a\n * number here, as it is to `numericSymbols`.\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 // A dual's number, from the value or from the halves the read kept. NULL has neither.\n const number = value === null ? NaN : numberOf(value, this._halves?.numbers[code] ?? null);\n\n if (!Number.isNaN(number)) {\n out[row] = number;\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 {Array<SymbolHalves|null>} [decoded.halvesByField] Both halves of each symbol, per field,\n * or null for a field whose values show them.\n * @param {number} decoded.rowCount Rows decoded.\n * @param {any} decoded.metadata The raw QvdTableHeader.\n * @param {import('./util/storedSymbols.js').StoredSymbols|null} [decoded.storedSymbols] The\n * stored-symbol record, as a data frame of the same read carries it.\n * @param {any} decoded.loadStats Statistics about the read.\n */\n constructor({columns, codesByField, symbolsByField, halvesByField, rowCount, metadata, storedSymbols, loadStats}) {\n this._columns = columns;\n this._codesByField = codesByField;\n this._symbolsByField = symbolsByField;\n this._halvesByField = halvesByField ?? null;\n this._rowCount = rowCount;\n this._metadata = metadata;\n this._storedSymbols = storedSymbols ?? null;\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 {'number'|'text'|'both'} [options.duals='number'] What a dual symbol's value is: its\n * number, its text, or a frozen `QvdDual` holding both. Whichever it is, `column.textAt` gives the\n * text and `numericSymbols` the number. Anything else throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a value that would be a string is a\n * number when its text is not blank and `Number(text)` is finite - a string symbol as\n * `Number(text)`, a dual read as text as its stored number. `column.textAt` still gives the text.\n * Anything but a boolean throws.\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 * The stored-symbol record of the read, as `QvdDataFrame.storedSymbols` describes it.\n *\n * @return {import('./util/storedSymbols.js').StoredSymbols|null} The record, or null.\n */\n get storedSymbols() {\n return this._storedSymbols;\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(\n name,\n this._codesByField[index],\n this._symbolsByField[index],\n this._halvesByField?.[index] ?? null,\n );\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport xml from 'xml2js';\n// Node's assert, used only for invariants a bug in this library would violate - \"this private\n// method ran after the one that fills the field it reads\". Never for input: everything a caller\n// can get wrong throws a QvdError with a context object instead.\n//\n// #143 read the old Copilot instruction \"use assertions for validation\" as an explanation for\n// these calls. It is not: every one sits after a method that either assigns the field\n// unconditionally or throws, and 3,570 corruption cases across every bundled fixture and every\n// entry point produced no AssertionError. They are checked, and they stay.\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 {parseFieldSymbols} from './util/symbolParser.js';\nimport {\n normaliseCoerceNumericStrings,\n normaliseDuals,\n normaliseWindow,\n resolveWindow,\n selectFields,\n} from './util/readOptions.js';\nimport {resolveFieldSymbols} from './util/resolveSymbols.js';\nimport {attachStoredSymbols, trustStoredSymbols} from './util/storedSymbols.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 */\n/**\n * Waits until a read stream has let go of its file handle.\n *\n * `destroy()` only schedules the close - `fs.close` is a threadpool call - so a read that destroys\n * the header stream and returns leaves the handle open after its own promise has resolved. That was\n * measurable: `readMetadata` left one open past a `setImmediate` turn. On POSIX it is invisible,\n * because a handle does not stop an unlink. On Windows the file cannot be deleted or renamed while\n * it lasts, and a caller that removes it synchronously - `fs.rmSync` - blocks the very event loop\n * the close needs, so no amount of waiting on their side helps. Only waiting here does.\n *\n * Resolves on `error` as well as `close`, because a failure to close must not replace whatever the\n * read is already reporting.\n *\n * @param {import('fs').ReadStream} stream The stream to close.\n * @return {Promise<void>} Resolves once the handle is gone.\n */\nfunction closeReadStream(stream) {\n if (stream.closed) {\n return Promise.resolve();\n }\n\n return new Promise((resolve) => {\n stream.once('close', () => resolve());\n stream.once('error', () => resolve());\n stream.destroy();\n });\n}\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 {'number'|'text'|'both'} [options.duals='number'] What a dual symbol - a number with the\n * text Qlik displays for it, such as a date - reads as. `'number'` gives its number, which is the\n * value Qlik sums, sorts and compares by; `'text'` gives its text; `'both'` gives a frozen\n * `QvdDual` holding both halves, shared by every row that holds the symbol. Under `'number'` and\n * `'text'` the half a cell does not show is kept in the frame's `storedSymbols`, so a write stores\n * the dual again. An int, a double, a string and NULL read the same in every mode. Any other value\n * throws a `QvdValidationError`.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite: a string symbol in\n * every `duals` mode, as `Number(text)`, and a dual's text under `duals: 'text'`, as the number the\n * dual stores. The text is kept in the frame's `storedSymbols`, so a write stores the string or the\n * dual again. Anything but a boolean, `undefined` or null throws a `QvdValidationError`.\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 duals,\n coerceNumericStrings,\n onProgress,\n signal,\n } = options;\n this._materialisesRows = materialisesRows;\n this._path = validatePath(filePath, allowedDir);\n /** What a dual symbol reads as. Checked here, so a bad value fails before the file is opened. */\n this._duals = normaliseDuals(duals, this._path);\n /**\n * Whether a cell that would be a string reads as a number when its text is a finite number. Off\n * unless asked for; on, the text is recorded in the frame's `storedSymbols`, so a write stores the\n * string or the dual it was read from. Checked here, like `duals`, before the file is opened.\n */\n this._coerceNumericStrings = normaliseCoerceNumericStrings(coerceNumericStrings, this._path);\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<import('./util/symbolParser.js').FieldSymbols>|null} Each selected field's decoded symbols. */\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 * A windowed read - anything with `offset`, `limit` or `maxRows` - reads only the bytes it\n * needs, rather than the file. Measured on `chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows\n * over 20 fields: the last thousand rows take 19 ms against 636 ms for the whole file.\n *\n * The saving is in the index table and the rows, not in the symbol table, which is read in\n * full whatever the window because a stored index in any row can address any symbol. So the\n * gain scales with how much of the file is rows: on a file whose bytes are mostly distinct\n * values there is very little to save, which is what `symbolFilteringThreshold` and the\n * two-pass path exist for.\n *\n * Algorithm for a windowed read:\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 } finally {\n // Before this read resolves, rather than whenever the scheduled close next gets a turn.\n await closeReadStream(stream);\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 // Decode the symbols of each *selected* field, straight from the bytes into their two halves.\n // Phase 2.5 optimization: a symbol the window does not use is walked past without decoding.\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 symbols = parseFieldSymbols(\n symbolBuffer,\n symbolsOffset,\n symbolsOffset + symbolsLength,\n // By position, matching how `_analyzeIndexTableSymbolUsage` built it. Both walk\n // `this._selectedFields`, so position is the one key that cannot collide.\n symbolsToKeep ? symbolsToKeep[position] : null,\n field['FieldName'],\n this._path,\n );\n\n this._emitProgress('symbol-table', position + 1, fields.length);\n\n return symbols;\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(\n data,\n prepared.columns,\n prepared.metadata,\n {\n ...prepared.loadStats,\n rowsLoaded: data.length,\n },\n prepared.storedSymbols,\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, null, true);\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 halvesByField: prepared.halvesByField,\n rowCount: this._rowsDecoded,\n metadata: prepared.metadata,\n storedSymbols: prepared.storedSymbols,\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 // Every chunk shares the one record: the symbol table was parsed once, in full, for all of them.\n yield new QvdDataFrame(\n data,\n prepared.columns,\n prepared.metadata,\n {\n ...prepared.loadStats,\n offset,\n rowsLoaded: data.length,\n },\n prepared.storedSymbols,\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 * @param {boolean} [wantHalves=false] Whether to keep both halves of each symbol of a field whose\n * cells do not show them, which only a columnar read has a use for.\n * @return {Promise<{columns: Array<string>, metadata: any, loadStats: any,\n * resolvedByField: Array<Array<any>>,\n * halvesByField: Array<import('./util/resolveSymbols.js').SymbolHalves|null>,\n * storedSymbols: import('./util/storedSymbols.js').StoredSymbols|null,\n * rowsAvailable: number, offset: number}>} The parsed file, with the window as it resolved\n * against it.\n * @private\n */\n async _prepare(window, liveRows = null, wantHalves = false) {\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 assert(this._selectedFields, 'The QVD file fields have not been resolved.');\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 what it reads as depends only on the\n // index. 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 symbol the two-pass path did not decode has neither half, and an index past the end of the\n // array reads as undefined. Both resolve to undefined here, which is what the per-cell version\n // produced through optional chaining.\n //\n // A dual used to resolve to its text alone, so its number was unreachable and a write stored the\n // date as a string (#138). What it resolves to now depends on the `duals` option, and the half a\n // cell does not show goes into the stored-symbol record, which is what a write reads it back from.\n /** @type {Array<Array<any>>} */\n const resolvedByField = [];\n /** @type {Array<import('./util/resolveSymbols.js').SymbolHalves|null>} */\n const halvesByField = [];\n /** @type {Array<import('./util/storedSymbols.js').StoredSymbolsEntry>} */\n const entries = [];\n\n this._symbolTable.forEach((symbols, position) => {\n const {values, entry, halves} = resolveFieldSymbols(\n symbols,\n // @ts-ignore - asserted above\n this._selectedFields[position]['FieldName'],\n this._duals,\n this._coerceNumericStrings,\n wantHalves,\n );\n\n resolvedByField.push(values);\n halvesByField.push(halves);\n\n if (entry !== null) {\n entries.push(entry);\n }\n });\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 // Null rather than an empty record when every cell shows its whole symbol, which is the common case\n // for a file without duals. The record is also left on the header object, not enumerably, so a frame\n // built as `new QvdDataFrame(data, columns, df.metadata)` keeps it.\n const storedSymbols = entries.length > 0 ? trustStoredSymbols(entries) : null;\n\n if (storedSymbols !== null) {\n attachStoredSymbols(metadata, storedSymbols);\n }\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 {\n columns,\n metadata,\n loadStats,\n resolvedByField,\n halvesByField,\n storedSymbols,\n rowsAvailable,\n offset: resolved.offset,\n };\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 {asDual, describeType, isPlainObject} from './util/cellRules.js';\nimport {metadataOptionsFrom, readerOptionsFrom, windowFrom} from './util/readOptions.js';\nimport {\n STORED_SYMBOLS,\n attachStoredSymbols,\n narrowStoredSymbols,\n normaliseStoredSymbols,\n storedSymbolsEntry,\n storedTextOf,\n} from './util/storedSymbols.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 * @typedef {import('./util/storedSymbols.js').StoredSymbols} QvdStoredSymbols\n */\n\n/**\n * A data frame in a form that survives `JSON`, `structuredClone`, `postMessage` and `v8.serialize`,\n * and that `fromDict` turns back into a frame writing the same symbols.\n *\n * @typedef {Object} QvdDataFrameDict\n * @property {Array<string>} columns The columns.\n * @property {Array<Array<any>>} data The rows.\n * @property {QvdMetadata|null} [metadata] The header, or null.\n * @property {QvdStoredSymbols|null} [storedSymbols] The stored-symbol record, or null.\n */\n\n/**\n * The header entry `toQvd` writes for a field nobody has described.\n *\n * @param {string} fieldName The field.\n * @return {Object} A field header with no comment, no tags and an UNKNOWN number format.\n */\nfunction defaultFieldHeader(fieldName) {\n return {\n FieldName: fieldName,\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\n/**\n * The header a metadata setter starts from on a frame that has none - one built by `fromDict`, or by\n * the constructor without metadata.\n *\n * @param {Array<string>} columns The frame's columns.\n * @return {QvdMetadata} A header describing every column and nothing else.\n */\nfunction defaultHeader(columns) {\n return {\n QvBuildNo: 50667,\n CreatorDoc: '',\n CreateUtcTime: '',\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: '',\n Fields: {\n QvdFieldHeader: columns.map(defaultFieldHeader),\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/**\n * Represents a loaded QVD file.\n */\nexport class QvdDataFrame {\n /**\n * Represents the data frame stored inside a QVD file.\n *\n * The record is resolved once, here: the fifth argument when given, otherwise the one a read left on\n * its header object, so `new QvdDataFrame(data, columns, df.metadata)` keeps what `df` would write.\n * Either is narrowed to `columns`. An entry for a field the frame does not have describes no cell it\n * holds, and would make the frame's own `toDict()` a dictionary `fromDict` refuses - which is what a\n * header's record did for a frame built from some of a read's columns.\n *\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 * @param {QvdStoredSymbols|null} storedSymbols What the frame's cells were read from, where a cell\n * shows only one half of its symbol (optional) - see `storedSymbols`.\n * @throws {QvdValidationError} If the record is malformed.\n */\n constructor(data, columns, metadata = null, loadStats = null, storedSymbols = null) {\n this._data = data;\n this._columns = columns;\n this._metadata = metadata;\n /** Whether `_metadata` is this frame's own to change - see `_ownMetadata`. */\n this._ownsMetadata = false;\n this._loadStats = loadStats;\n /** @type {QvdStoredSymbols|null} */\n this._storedSymbols = narrowStoredSymbols(\n normaliseStoredSymbols(\n // @ts-ignore - a symbol-keyed property the reader defines on the header object\n storedSymbols ?? (metadata !== null && typeof metadata === 'object' ? metadata[STORED_SYMBOLS] : null),\n ),\n columns,\n );\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 * What the frame's cells were read from, where a cell shows only one half of its symbol.\n *\n * A dual read as its number has a text the cell does not show; one read as its text has a number;\n * a string read as a number has the text it was spelled with. The record keeps those halves, per\n * field, keyed by the value the cell holds, so `toQvd` writes the symbols the frame was read from\n * and `textAt` can return any cell's text. It moves with the frame through `head`, `tail`, `rows`,\n * `select`, `toDict` and `fromDict`.\n *\n * Frozen plain data: `[{field, values, numbers, texts}]`, where a cell holding `values[i]` stands for\n * the stored symbol (`numbers[i]`, `texts[i]`), a null number meaning a pure string and a null text a\n * pure number.\n *\n * @return {QvdStoredSymbols|null} The record, or null when the frame has none: every cell of the read\n * showed its whole symbol, or the frame was built without one. A frame whose columns have no entry\n * in the record it was given or found - one from `select`, or one built from some of a read's\n * columns and its header - has an empty record rather than null, because a frame given null takes\n * the record its header carries, which describes every field of the read.\n */\n get storedSymbols() {\n return this._storedSymbols;\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 * The header a metadata setter may change: this frame's own.\n *\n * A frame's header can be shared. `head`, `tail`, `rows` and `select` pass theirs on, every chunk\n * `iterate()` yields holds the same one, and `fromDict` uses the object it is given. So the first\n * change copies it, and a change made through one frame never reaches another. A frame with no header\n * gets the one `toQvd` would write for it. The copy keeps the stored-symbol record the header carries,\n * so `new QvdDataFrame(data, columns, df.metadata)` still writes what `df` would.\n *\n * @return {any} The header.\n */\n _ownMetadata() {\n if (!this._metadata) {\n this._metadata = defaultHeader(this._columns);\n } else if (!this._ownsMetadata) {\n // @ts-ignore - a symbol-keyed property the reader defines on the header object\n const record = this._metadata[STORED_SYMBOLS];\n this._metadata = structuredClone(this._metadata);\n if (record) {\n attachStoredSymbols(this._metadata, record);\n }\n }\n this._ownsMetadata = true;\n return this._metadata;\n }\n\n /**\n * Sets modifiable file-level metadata. Immutable properties related to data storage are ignored.\n *\n * The change applies to this frame only, never to a frame it was derived from or shares a header\n * with.\n *\n * @param {FileMetadataUpdate} metadata Object containing metadata properties to update.\n */\n setFileMetadata(metadata) {\n const header = this._ownMetadata();\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 header[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 *\n * Works on any frame, including one with no header yet - one from `fromDict` - and on a column the\n * header does not describe. The change applies to this frame only, never to a frame it was derived\n * from or shares a header with.\n *\n * @param {string} fieldName The name of the field.\n * @param {FieldMetadataUpdate} metadata Object containing field metadata properties to update.\n * @throws {QvdValidationError} If the frame has no column of that name.\n */\n setFieldMetadata(fieldName, metadata) {\n if (!this._columns.includes(fieldName)) {\n throw new QvdValidationError(`Column '${fieldName}' does not exist`, {\n column: fieldName,\n availableColumns: this._columns,\n });\n }\n\n const header = this._ownMetadata();\n if (!header.Fields || typeof header.Fields !== 'object' || !header.Fields.QvdFieldHeader) {\n header.Fields = {QvdFieldHeader: []};\n }\n\n let fields = header.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n header.Fields.QvdFieldHeader = fields;\n }\n\n let field = fields.find((/** @type {any} */ f) => f.FieldName === fieldName);\n if (!field) {\n field = defaultFieldHeader(fieldName);\n fields.push(field);\n }\n\n // Only allow modification of Comment, NumberFormat, and Tags (not Offset, Length, BitOffset, etc.)\n if (metadata.comment !== undefined) {\n field.Comment = metadata.comment;\n }\n if (metadata.numberFormat !== undefined) {\n field.NumberFormat = metadata.numberFormat;\n }\n if (metadata.tags !== undefined) {\n field.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, null, this._storedSymbols);\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 n === 0 ? [] : this._data.slice(-n),\n this._columns,\n this._metadata,\n null,\n this._storedSymbols,\n );\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 null,\n this._storedSymbols,\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 const index = this._cellIndex(row, column);\n\n return this._data[row][index];\n }\n\n /**\n * Returns the text of the value at the specified row and column.\n *\n * The text Qlik displays for it: a string cell is its own text, and a dual cell's text is its\n * `.text`. A number cell's text comes from the frame's `storedSymbols` - the dual it was read from,\n * or the string it was spelled as - and is null for a number that was stored as a pure number.\n *\n * ```js\n * const df = await QvdDataFrame.fromQvd('stockholm_temp.qvd');\n * df.at(0, 'date'); // -52593\n * df.textAt(0, 'date'); // '1756-01-01'\n * ```\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {string|null} The text, or null for NULL and for a number with no text.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n textAt(row, column) {\n const index = this._cellIndex(row, column);\n const value = this._data[row][index];\n\n if (typeof value === 'string') {\n return value;\n }\n\n if (typeof value === 'number') {\n const entry = storedSymbolsEntry(this._storedSymbols, column);\n\n return entry === null ? null : storedTextOf(entry, value);\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.text === 'string' ? dual.text : null;\n }\n\n /**\n * Checks a row and a column name, and returns the column's position.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {number} The column's position.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n * @private\n */\n _cellIndex(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._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 // The constructor narrows the record to the fields kept, sharing their entries rather than copying them.\n return new QvdDataFrame(data, columns, this._metadata, null, this._storedSymbols);\n }\n\n /**\n * Returns the data frame as a dictionary.\n *\n * Everything a frame needs to write the same file again, as plain data: the header, and the\n * stored-symbol record that says what cells showing one half of a symbol were read from. So\n * `fromDict(await df.toDict())` writes what `df` writes, and so does a dictionary that went through\n * `JSON`, `structuredClone` or a worker on the way. The arrays are the frame's own, not copies.\n *\n * @return {Promise<QvdDataFrameDict>} The data frame as a dictionary.\n */\n async toDict() {\n return this.toJSON();\n }\n\n /**\n * The same dictionary `toDict` returns, synchronously, so `JSON.stringify(df)` gives something\n * `fromDict(JSON.parse(...))` can revive.\n *\n * @return {QvdDataFrameDict} The data frame as a dictionary.\n */\n toJSON() {\n return {\n columns: this._columns,\n data: this._data,\n metadata: this._metadata,\n storedSymbols: this._storedSymbols,\n };\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 {'number'|'text'|'both'} [options.duals='number'] What a dual symbol - a number with the\n * text Qlik displays for it, such as a date, a timestamp or a formatted amount - reads as.\n * `'number'` gives its number, the value Qlik sums, sorts and compares by, so a date is its serial.\n * `'text'` gives its text. `'both'` gives a frozen `QvdDual` with `.number` and `.text`, whose\n * implicit conversions throw. Under `'number'` and `'text'` the other half is kept in\n * `storedSymbols`, so `toQvd` writes the dual back, and `textAt` returns any cell's text. An int, a\n * double, a string and NULL read the same in every mode: a number, a string and null. Anything else\n * throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite. A string symbol then\n * reads as `Number(text)`, so `'007'` is 7, in every `duals` mode; a dual read with\n * `duals: 'text'` reads as the number it stores. Blank text, and text such as `'8E5597'` whose\n * `Number()` is Infinity, stay strings. The text is kept in `storedSymbols`, so `toQvd` writes the\n * original string or dual back, and a value that two stored values read as is refused there\n * rather than written as either. Anything but a boolean 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, if `fields` names a column the file does not have, if `duals`\n * is not one of its modes, or if `coerceNumericStrings` is not a boolean.\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 * Every chunk carries the same `storedSymbols`, because the symbol table is parsed once for all of\n * them, so a chunk written on its own writes the symbols its cells were read from.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Reading options, with the meanings they have on `fromQvd`.\n * @param {number} [options.chunkSize=100000] Rows per frame. Must be a positive integer.\n * @param {number|null} [options.maxRows] Rows to cover. The older name for `limit`.\n * @param {number|null} [options.limit] Rows to cover, counting from `offset`.\n * @param {number} [options.offset=0] File row to start at.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should appear.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol reads as: its number,\n * its text, or a frozen `QvdDual` holding both. Anything else throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite - a string symbol as\n * `Number(text)`, a dual read as text as its stored number - with the text kept in every chunk's\n * `storedSymbols`. Anything but a boolean throws.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}`; progress\n * over the rows counts the whole window, not each chunk.\n * @param {AbortSignal} [options.signal] Cancels the iteration, rejecting with `signal.reason`.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction of the memory budget the read may use,\n * charged for two chunks of rows rather than the window. Zero disables the check.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size above which a\n * windowed read switches to two-pass filtering.\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 * Takes what `toDict` returns. `metadata` and `storedSymbols` are optional; with the record, a frame\n * rebuilt from a read writes the symbols the read found - duals with their texts, strings with their\n * spelling - even after a trip through `JSON`. The record is checked, so a malformed one is refused\n * here rather than written.\n *\n * @param {QvdDataFrameDict} data The dictionary to construct the data frame from.\n * @return {Promise<QvdDataFrame>} The constructed data frame.\n * @throws {QvdValidationError} If `columns` or `data` is missing, `metadata` is not a plain object,\n * or `storedSymbols` is malformed or names a field that is not one of the columns.\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 const {metadata = null, storedSymbols = null} = data;\n\n if (metadata !== null && !isPlainObject(metadata)) {\n throw new QvdValidationError(`metadata must be a plain object; got ${describeType(metadata)}`, {\n type: typeof metadata,\n });\n }\n\n const record = normaliseStoredSymbols(storedSymbols);\n\n if (record !== null) {\n const unknown = record.find((entry) => !data.columns.includes(entry.field));\n\n if (unknown !== undefined) {\n throw new QvdValidationError(`storedSymbols names field '${unknown.field}', which is not one of the columns`, {\n field: unknown.field,\n availableColumns: data.columns,\n });\n }\n }\n\n return new QvdDataFrame(data.data, data.columns, metadata, null, record);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {INT32_MAX, INT32_MIN, asDual, checkNumber, checkText, describeType, isStoredAsInt} from './util/cellRules.js';\nimport {symbolByteLength, writeSymbol} from './util/symbolBytes.js';\n\n/**\n * Throws unless a value can be stored as the integer of a symbol.\n *\n * @param {any} value The value.\n * @param {Object} context Merged into the error's context.\n * @throws {QvdValidationError} If the value is not an integer inside the int32 range.\n */\nfunction checkInteger(value, context) {\n if (typeof value === 'number' && isStoredAsInt(value)) {\n return;\n }\n\n throw new QvdValidationError(\n `The integer of a symbol must be an integer from ${INT32_MIN} to ${INT32_MAX}; got ` +\n (typeof value === 'number' ? String(value) : describeType(value)),\n {...context, half: 'integer', type: typeof value},\n );\n}\n\n/**\n * One stored symbol, as the symbol table holds it: an int, a double, a string, or a dual of an int or\n * a double with its text.\n *\n * A low-level record of the file's contents rather than a cell. A read never puts one in a data frame\n * - a cell is a number, a string, a `QvdDual` or null - and the writer refuses one as a cell, pointing\n * at `QvdDual`, because a symbol carries a storage kind the writer derives from the value itself.\n *\n * The factories validate what they are given and throw `QvdValidationError` naming the half, so a\n * symbol built through them can be encoded. The constructor checks nothing, and\n * `toByteRepresentation` refuses whatever it cannot encode.\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 * The kind is the one the symbol carries - an int, a double, a string, or a dual of an int or a\n * double with its text - so a symbol built with `fromDoubleValue(4)` stays a double. Each half is\n * checked before a byte is written, because `QvdSymbol`'s constructor checks nothing: an integer\n * outside int32 used to surface as a bare `RangeError` from `writeInt32LE`, a symbol holding an\n * integer and a double silently lost the double, a text with a NUL produced a symbol that ends\n * early, and a text with an unpaired surrogate was written with U+FFFD in its place.\n *\n * A half left `undefined` - `new QvdSymbol()`, or `new QvdSymbol(7)` - is absent, as it is to\n * `toPrimaryValue`. It used to be read as present: `new QvdSymbol(7)` threw a bare `TypeError` from\n * `Buffer.from`, and `new QvdSymbol(undefined, 4.5, '4.50')` was written as a dual of the integer 0.\n *\n * @return {Buffer} The byte representation of the symbol.\n * @throws {QvdValidationError} If the symbol holds both an integer and a double, holds nothing, or\n * holds a half no symbol can store. The message names the half.\n */\n toByteRepresentation() {\n const intValue = this._intValue ?? null;\n const doubleValue = this._doubleValue ?? null;\n const stringValue = this._stringValue ?? null;\n\n if (intValue !== null && doubleValue !== null) {\n throw new QvdValidationError('A symbol holds an integer or a double, not both', {\n intValue,\n doubleValue,\n });\n }\n\n if (intValue === null && doubleValue === null && stringValue === null) {\n throw new QvdValidationError('The symbol does not contain any value.', {\n intValue,\n doubleValue,\n stringValue,\n });\n }\n\n if (intValue !== null) {\n checkInteger(intValue, {});\n }\n\n if (doubleValue !== null) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n }\n\n if (stringValue !== null) {\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n }\n\n const number = intValue ?? doubleValue;\n const kind = number === null ? 4 : (intValue !== null ? 1 : 2) + (stringValue !== null ? 4 : 0);\n const buffer = Buffer.allocUnsafe(symbolByteLength(kind, number, stringValue));\n\n writeSymbol(buffer, 0, kind, number, stringValue);\n\n return buffer;\n }\n\n /**\n * Checks if this symbol is equal to another symbol.\n *\n * By shape rather than by class: another value is equal when its `intValue`, `doubleValue` and\n * `stringValue` are, compared with `===`, whichever copy of this library built it - `instanceof`\n * answers false for a symbol from the CommonJS build tested by the ESM one. A dual value, a `QvdDual`\n * or `{number, text}`, is equal to a dual symbol with the same number and text: a dual carries no\n * storage kind, so either kind matches.\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 === null || typeof value !== 'object') {\n return false;\n }\n\n const intValue = this._intValue ?? null;\n const doubleValue = this._doubleValue ?? null;\n const stringValue = this._stringValue ?? null;\n const dual = asDual(value);\n\n if (dual !== null) {\n return (\n stringValue !== null &&\n stringValue === dual.text &&\n (intValue === null) !== (doubleValue === null) &&\n (intValue ?? doubleValue) === dual.number\n );\n }\n\n if (!('intValue' in value && 'doubleValue' in value && 'stringValue' in value)) {\n return false;\n }\n\n return (\n intValue === (value.intValue ?? null) &&\n doubleValue === (value.doubleValue ?? null) &&\n stringValue === (value.stringValue ?? null)\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 * @throws {QvdValidationError} If the integer is not an integer inside the int32 range.\n */\n static fromIntValue(intValue) {\n checkInteger(intValue, {});\n\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 * @throws {QvdValidationError} If the double is not a finite number.\n */\n static fromDoubleValue(doubleValue) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n\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 * @throws {QvdValidationError} If the string is not a string, or holds a NUL or an unpaired surrogate.\n */\n static fromStringValue(stringValue) {\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\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 * @throws {QvdValidationError} If the integer is not an integer inside the int32 range, or the text\n * is not a string, or holds a NUL or an unpaired surrogate.\n */\n static fromDualIntValue(intValue, stringValue) {\n checkInteger(intValue, {});\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\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 * @throws {QvdValidationError} If the double is not a finite number, or the text is not a string,\n * or holds a NUL or an unpaired surrogate.\n */\n static fromDualDoubleValue(doubleValue, stringValue) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\n return new QvdSymbol(null, doubleValue, stringValue);\n }\n}\n","// @ts-check\n\nexport {QvdSymbol} from './QvdSymbol.js';\nexport {QvdDual} from './QvdDual.js';\nexport {qlikSerialToDate, dateToQlikSerial} from './util/qlikDate.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","// @ts-check\n\nimport {types} from 'util';\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {asDual, describeType} from './cellRules.js';\n\n/** Qlik's day 0: 30 December 1899, so that 1 January 1900 is day 2, as in Excel and Lotus 1-2-3. */\nconst QLIK_EPOCH_MS = Date.UTC(1899, 11, 30);\n\nconst MS_PER_DAY = 86400000;\n\n/** The furthest a JavaScript `Date` reaches either side of 1970, in milliseconds. */\nconst MAX_DATE_MS = 8.64e15;\n\n/** The serials of the first and last days a `Date` can hold: -99974431 and 100025569. */\nconst MIN_SERIAL = (-MAX_DATE_MS - QLIK_EPOCH_MS) / MS_PER_DAY;\nconst MAX_SERIAL = (MAX_DATE_MS - QLIK_EPOCH_MS) / MS_PER_DAY;\n\n/**\n * Converts a Qlik date or timestamp serial to a JavaScript `Date`.\n *\n * Qlik stores a date as the number of days since 30 December 1899, with the time of day as the\n * fraction: 42382.260416666664 is 13 January 2016 at 06:15. That number is what a date field's cell\n * reads as, whether Qlik stored it as a dual with the date's text or as a pure number with a `DATE`\n * format - and it is the `number` of a dual value read with `{duals: 'both'}`.\n *\n * **The serial has no time zone, and the result is read in UTC.** Qlik's serial means \"this wall-clock\n * date and time\", not an instant. The `Date` returned carries those wall-clock fields in its UTC\n * getters, so `toISOString()` and `getUTCHours()` show what Qlik shows. The local-time getters apply\n * the machine's own offset, which is almost never what you want here.\n *\n * Checked against the text Qlik stored beside every date in stockholm_temp and every trip start\n * timestamp in a chicago_taxi_rides file, and rounded to the millisecond, which is finer than any Qlik\n * timestamp text shows.\n *\n * ```js\n * qlikSerialToDate(-52593).toISOString(); // '1756-01-01T00:00:00.000Z'\n * qlikSerialToDate(new QvdDual(-52593, '1756-01-01')).toISOString(); // a dual works too, through its number\n * ```\n *\n * @param {number|import('../QvdDual.js').QvdDual|{number: number, text: string}} serial The serial, or a dual whose number is one.\n * @return {Date} The date, with Qlik's wall-clock fields in its UTC getters.\n * @throws {QvdValidationError} If the serial is not a finite number, or is a day a `Date` cannot hold.\n */\nexport function qlikSerialToDate(serial) {\n const dual = asDual(serial);\n const number = dual === null ? serial : dual.number;\n\n if (typeof number !== 'number' || !Number.isFinite(number)) {\n throw new QvdValidationError('A Qlik date serial must be a finite number', {\n provided: describeType(number),\n type: typeof serial,\n });\n }\n\n const ms = Math.round(QLIK_EPOCH_MS + number * MS_PER_DAY);\n\n // Past this a Date is Invalid Date, which fails later and somewhere else - in toISOString(), say.\n if (!(Math.abs(ms) <= MAX_DATE_MS)) {\n throw new QvdValidationError(`A Qlik date serial of ${number} is outside the range a JavaScript Date can hold`, {\n serial: number,\n minSerial: MIN_SERIAL,\n maxSerial: MAX_SERIAL,\n });\n }\n\n return new Date(ms);\n}\n\n/**\n * Converts a JavaScript `Date` to a Qlik date or timestamp serial.\n *\n * The inverse of `qlikSerialToDate`, and it reads the date's UTC fields for the same reason: a\n * serial is a wall-clock value. Build the `Date` from UTC parts - `new Date(Date.UTC(2016, 0, 13, 6,\n * 15))`, or an ISO string ending in `Z` - to get the serial Qlik would store for that date and time.\n *\n * For every date and timestamp checked against `qlikSerialToDate`, converting Qlik's serial to a\n * `Date` and back returns Qlik's stored double exactly.\n *\n * A `Date` from another realm - a `vm` context, or a Node core module under Jest - is accepted: the\n * check is on what the value is, not on which `Date` constructor made it.\n *\n * To write a date Qlik will treat as a date, pair the serial with the text to display:\n *\n * ```js\n * const when = new Date(Date.UTC(2016, 0, 13, 6, 15));\n * const cell = new QvdDual(dateToQlikSerial(when), '2016-01-13 06:15:00');\n * ```\n *\n * @param {Date} date The date.\n * @return {number} The serial: whole days since 30 December 1899, with the time of day as the fraction.\n * @throws {QvdValidationError} If the argument is not a valid `Date`.\n */\nexport function dateToQlikSerial(date) {\n const ms = types.isDate(date) ? Date.prototype.getTime.call(date) : Number.NaN;\n\n if (Number.isNaN(ms)) {\n throw new QvdValidationError('dateToQlikSerial needs a valid Date', {\n provided: describeType(date),\n type: typeof date,\n });\n }\n\n return (ms - QLIK_EPOCH_MS) / MS_PER_DAY;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/QvdErrors.js","../src/util/cellRules.js","../src/util/symbolBytes.js","../src/QvdDual.js","../src/util/optionTypes.js","../src/util/readOptions.js","../src/util/storedSymbols.js","../src/util/linkTarget.js","../src/util/validatePath.js","../src/util/ioErrors.js","../src/util/openChecked.js","../src/util/replaceFile.js","../src/util/bitUtils.js","../src/QvdFileWriter.js","../src/util/memoryUtils.js","../src/util/validationUtils.js","../src/util/symbolParser.js","../src/util/resolveSymbols.js","../src/QvdColumnTable.js","../src/QvdFileReader.js","../src/QvdDataFrame.js","../src/QvdSymbol.js","../src/index.js","../src/util/qlikDate.js"],"names":["fs","path","assert","crypto","wait","xml","QvdFileReader","fileSize","QvdColumnTable","QvdFileWriter"],"mappings":"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","file":"index.js","sourcesContent":["// @ts-check\n\n/**\n * The name each of this module's classes reports, written out rather than read from the class.\n *\n * A class's own `name` is whatever the build left it: the CommonJS bundle of every release checked from\n * 0.6.2 to 0.11.0 gave these classes no name at all, so `error.name` was `''` for a `require`d qvdjs,\n * and a bundler minifying the source renames them. `error.name` is what callers match on, so it must\n * not depend on either.\n *\n * @type {Map<Function, string>}\n */\nconst ERROR_NAMES = new Map();\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 * @param {{cause?: unknown}} [options] Passed on to `Error`, so a `cause` becomes `error.cause`: the\n * error this one reports, such as the operating system's refusal behind a `QvdIOError`.\n */\n constructor(message, code, context = {}, options = undefined) {\n super(message, options);\n // A caller's own subclass keeps its own name.\n this.name = ERROR_NAMES.get(new.target) ?? new.target.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 * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_PARSE_ERROR', context, options);\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 * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_VALIDATION_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when the operating system refuses a file-system call made to read or write a QVD\n * file: a missing file, a directory where a file was expected, a permission error, and on Windows a\n * file another process has locked (`EBUSY`). Locks on Linux and macOS are advisory, so a locked file\n * there reads and writes without an error at all.\n *\n * `context.code` is the system code Node reported - `ENOENT`, `EISDIR`, `EACCES`, `EBUSY` and so\n * on - and `context.operation` the call that failed, as Node names it: `open`, `fstat`, `read`,\n * `write`, `ftruncate`, `fsync` and `close`, and from a write that replaces the file rather than\n * rewriting it, `fchmod` and `rename` as well. `context.file` is the resolved path the caller asked\n * for, even where the call that failed was made on the temporary file a write builds beside it;\n * `cause` is Node's own error, unchanged, so its `errno`, `syscall` and the path it names are there\n * too. On Windows a `rename` that reports `EPERM` or `EBUSY` usually means another program has the\n * destination open - Qlik Sense reading it, most often - and the previous file is untouched.\n *\n * `context.temporaryFile` appears on one of these and only one: a write that failed and could not\n * remove the file it was building either, which is the only way one is left behind while a process is\n * still running. It names that file, so a caller can remove it.\n *\n * One has neither `context.code` nor `cause`, though its `code` is `QVD_IO_ERROR` like every other's:\n * a write that stored nothing while the operating system reported no error. There is no system code\n * to carry, so `context.filePosition` says where the file stops.\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 * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_IO_ERROR', context, options);\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 * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_CORRUPTED_ERROR', context, options);\n }\n}\n\n/**\n * Error thrown when security violations occur.\n * Used for path traversal attempts, XXE attacks, or other security issues.\n *\n * A refused path says why in `context.reason`. `'outside_allowed_directory'` is a path that resolves\n * outside allowedDir, and `'null_byte'` one with a NUL in it. `'changed_after_check'` is a file that\n * was not the one the containment check approved by the time it was opened: `context.change` is\n * `'became_a_symlink'`; `'replaced'` for a different file at the same name; or `'appeared'` for a\n * read that found a file at a name the check found empty. Each, left alone, would have read or\n * written a file the check never saw, and on a sandbox shared with someone else it is what a symlink\n * race looks like. See `openChecked` for what it covers and what it cannot.\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 * @param {{cause?: unknown}} [options] Passed on to `Error`; a `cause` becomes `error.cause`.\n */\n constructor(message, context = {}, options = undefined) {\n super(message, 'QVD_SECURITY_ERROR', context, options);\n }\n}\n\nERROR_NAMES.set(QvdError, 'QvdError');\nERROR_NAMES.set(QvdParseError, 'QvdParseError');\nERROR_NAMES.set(QvdValidationError, 'QvdValidationError');\nERROR_NAMES.set(QvdIOError, 'QvdIOError');\nERROR_NAMES.set(QvdCorruptedError, 'QvdCorruptedError');\nERROR_NAMES.set(QvdSecurityError, 'QvdSecurityError');\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * What a QVD symbol can hold, said once.\n *\n * Only the writer used to apply these rules. It defined the int32 range, to choose between an int\n * and a double, and refused NaN, the infinities and a string containing NUL. `QvdSymbol` checked\n * nothing: the RangeError from Node's `writeInt32LE` was its only range check, and it wrote a NUL\n * whole - so the same value could be refused by one and written by the other. Everything that\n * decides whether a number or a text can be stored now reads it from here, and throws from here.\n */\n\n/** Lower bound of the integer a type 1 or type 5 symbol holds. */\nexport const INT32_MIN = -2147483648;\n\n/** Upper bound of the integer a type 1 or type 5 symbol holds. */\nexport const INT32_MAX = 2147483647;\n\n/** Terminates a text in the symbol table, so a stored text cannot contain one. */\nexport const NUL = String.fromCharCode(0);\n\n/**\n * Marks a `QvdDual`, from whichever copy of this library built it.\n *\n * `Symbol.for` rather than `Symbol()`, and a brand rather than `instanceof`, because a cell can come\n * from a different copy of the class than the one checking it: the CommonJS and ESM builds loaded in\n * one process, two installed copies of the package, a Jest module registry that has been reset, or a\n * vm realm. Each has its own `QvdDual`, and `instanceof` answers false across all of them.\n */\nexport const DUAL_BRAND = Symbol.for('qvdjs.QvdDual');\n\n/**\n * The dual value a cell holds, or null when it is not one.\n *\n * A dual is either a `QvdDual` - recognised by its brand, so one built by another copy of this\n * library counts - or a plain object whose own enumerable keys are exactly `number` and `text`. The\n * second form is what every clone of a `QvdDual` produces: `structuredClone`, `postMessage`,\n * `v8.serialize` and `JSON` all keep own enumerable data properties and drop the class, so a frame\n * sent to a worker and back writes the same duals it was read with.\n *\n * The shape is exact because a looser one writes the wrong file silently. An object that merely\n * *has* `number` and `text` - a record `{number, text, date}`, an array given the two properties, an\n * object that inherits them - is somebody's own data, and storing it as a dual would discard the rest\n * of it without a word. It is refused instead, and so is anything that is not a plain object - see\n * `isPlainObject` - so an object literal from a vm realm is accepted where `instanceof Object` would\n * refuse it.\n *\n * The halves are not type-checked here. The caller validates them, so that a refusal can say which\n * half is wrong rather than that the object is not a dual.\n *\n * @param {any} value Any value.\n * @return {{number: any, text: any}|null} The value itself when it is a dual, or null.\n */\nexport function asDual(value) {\n if (value === null || typeof value !== 'object') {\n return null;\n }\n\n try {\n if (value[DUAL_BRAND] === true) {\n return value;\n }\n\n if (!isPlainObject(value)) {\n return null;\n }\n\n const keys = Object.keys(value);\n\n return keys.length === 2 &&\n ((keys[0] === 'number' && keys[1] === 'text') || (keys[0] === 'text' && keys[1] === 'number'))\n ? value\n : null;\n } catch {\n // A revoked Proxy throws from every one of those operations. It is not a dual, and the refusal\n // that follows describes it without touching it again.\n return null;\n }\n}\n\n/**\n * Whether a value is a plain object: an object literal from any realm, or one with a null prototype.\n *\n * Tested as \"a prototype that is null, or whose own prototype is null\", which is what a realm's\n * `Object.prototype` is. An array, a class instance and an object made with `Object.create(other)` are\n * not plain, although an instance of an anonymous class and the last read their constructor name as\n * `Object` through the chain.\n *\n * @param {any} value The value.\n * @return {boolean} True for a plain object.\n * @throws {TypeError} For a revoked Proxy, from `Array.isArray` and `Object.getPrototypeOf`.\n */\nexport function isPlainObject(value) {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === null || Object.getPrototypeOf(prototype) === null;\n}\n\n/**\n * Whether a text reads as a finite number.\n *\n * This is the rule `{coerceNumericStrings: true}` applies, and the one every read applied from #212 until\n * coercion became opt-in. The reader started from `!isNaN(Number(text))` and was narrowed twice.\n * `Number('')` and `Number(' ')` are 0, which turned every blank cell Qlik stored into a real zero, so\n * blank text is never numeric. And `Number.isFinite` rather than `!isNaN`, because JavaScript reads `E` as\n * an exponent: `Number('8E5597')` is Infinity, and that string is a LEGO colour code in this repository's\n * own `lego/colors.qvd`. A text whose numeric reading is not finite stays text.\n *\n * @param {string} text The text.\n * @return {boolean} True when the text reads as a finite number.\n */\nexport function isNumericText(text) {\n return text.trim() !== '' && Number.isFinite(Number(text));\n}\n\n/**\n * Whether a number is stored as a 32-bit integer rather than as a double.\n *\n * This is the rule Qlik follows, read off the files it wrote rather than chosen here: every numeric\n * symbol in the bundled Qlik files is an int exactly when its value is an integer inside the int32\n * range, whether it is a pure number or a dual. The kind follows the value, never the text.\n *\n * -0 is stored as the integer 0, because `Number.isInteger(-0)` is true and -0 is inside the range.\n * That is the cause, and not a Map folding the two together: a Map only merges 0 and -0 when both\n * occur in one column, and a column holding -0 alone is stored as 0 all the same. Qlik's engine\n * compares -0 equal to 0 and `Num()` shows it as 0.\n *\n * @param {number} value A finite number.\n * @return {boolean} True when the value is stored as an int symbol.\n */\nexport function isStoredAsInt(value) {\n return Number.isInteger(value) && value >= INT32_MIN && value <= INT32_MAX;\n}\n\n/**\n * Why a value cannot be stored as a number, or null when it can.\n *\n * @param {any} value The value.\n * @return {string|null} `'is a string, not a number'` and the like, `'is NaN'`, `'is Infinity'`,\n * `'is -Infinity'`, or null.\n */\nexport function numberProblem(value) {\n if (typeof value !== 'number') {\n return `is ${describeType(value)}, not a number`;\n }\n\n return Number.isFinite(value) ? null : `is ${String(value)}`;\n}\n\n/**\n * Why a value cannot be stored as a text, or null when it can.\n *\n * NUL is refused because it is what ends a text in the symbol table: a text containing one was\n * written whole, and the reader then took the character after it for the next symbol's type byte.\n *\n * An unpaired surrogate is refused because UTF-8 has no encoding for one. A JavaScript string is a\n * sequence of UTF-16 code units, and a code unit from U+D800 to U+DFFF is half of a character unless\n * a high one is followed by a low one. Node writes each half on its own as U+FFFD, the replacement\n * character, so `'\\uD800'` and `'\\uDFFF'` were written as the same three bytes: two different strings\n * became two symbols with one stored value, and neither read back as what was written.\n *\n * A string with both problems reports the NUL.\n *\n * @param {any} value The value.\n * @return {{reason: 'type'|'nul'|'surrogate', position?: number}|null} The problem, with the index of\n * the offending code unit where there is one, or null.\n */\nexport function textProblem(value) {\n if (typeof value !== 'string') {\n return {reason: 'type'};\n }\n\n // indexOf rather than includes: this runs once per distinct value on a table that may have\n // millions of them, and indexOf on a string primitive is the cheaper of the two.\n const position = value.indexOf(NUL);\n\n if (position !== -1) {\n return {reason: 'nul', position};\n }\n\n // isWellFormed is one native call for the whole string, so the scan for where the problem is runs\n // only for a string that is about to be refused.\n return value.isWellFormed() ? null : {reason: 'surrogate', position: unpairedSurrogateIndex(value)};\n}\n\n/**\n * The index of the first code unit in a string that is half of a surrogate pair without the other\n * half.\n *\n * @param {string} value A string that is not well formed.\n * @return {number} The index, or -1 when every surrogate is paired.\n */\nfunction unpairedSurrogateIndex(value) {\n for (let index = 0; index < value.length; index++) {\n const unit = value.charCodeAt(index);\n\n if (unit < 0xd800 || unit > 0xdfff) {\n continue;\n }\n\n // A high surrogate followed by a low one is one character: step over both. charCodeAt past the\n // end is NaN, which fails the comparison, so a high surrogate at the end is unpaired.\n const next = value.charCodeAt(index + 1);\n\n if (unit <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) {\n index++;\n continue;\n }\n\n return index;\n }\n\n return -1;\n}\n\n/**\n * Throws unless a value can be stored as a number.\n *\n * `subject` names the half being checked, as the message starts: `'The double of a symbol'` gives\n * \"The double of a symbol must be a finite number; got a string\". A cell is the exception, and is\n * checked with a null subject: it is already known to be a number, so all that can be wrong with it\n * is NaN or an infinity, and the message for that has been quoted to callers since the writer first\n * refused it.\n *\n * @param {any} value The value.\n * @param {string|null} subject What the value is, capitalised; null for a cell.\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If the value is not a finite number.\n */\nexport function checkNumber(value, subject, context) {\n if (numberProblem(value) === null) {\n return;\n }\n\n if (subject === null && typeof value === 'number') {\n throw new QvdValidationError('NaN and Infinity cannot be stored in a QVD field', {\n ...context,\n provided: String(value),\n });\n }\n\n throw new QvdValidationError(`${subject ?? 'A number'} must be a finite number; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n}\n\n/**\n * Throws unless a value can be stored as a text.\n *\n * @param {any} value The value.\n * @param {string} subject What the value is, capitalised, as the message starts: `'A string value'`\n * gives \"A string value cannot contain a NUL character\".\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If the value is not a string, or holds a NUL or an unpaired surrogate,\n * which no stored text can; `context.position` is that code unit's index.\n */\nexport function checkText(value, subject, context) {\n const problem = textProblem(value);\n\n if (problem === null) {\n return;\n }\n\n if (problem.reason === 'type') {\n throw new QvdValidationError(`${subject} must be a string; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n }\n\n if (problem.reason === 'surrogate') {\n throw new QvdValidationError(`${subject} cannot contain an unpaired surrogate`, {\n ...context,\n position: problem.position,\n });\n }\n\n throw new QvdValidationError(`${subject} cannot contain a NUL character`, {...context, position: problem.position});\n}\n\n/**\n * The name of a value's constructor, read without letting the read throw.\n *\n * A getter, or a revoked Proxy, can throw from `value.constructor`, and an error message is the\n * wrong place to find that out: the caller would get that error instead of the one being built.\n *\n * @param {any} value An object.\n * @return {string|null} The name, or null when there is none to read.\n */\nexport function constructorName(value) {\n try {\n const name = value.constructor?.name;\n\n return typeof name === 'string' && name !== '' ? name : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Names a value's type the way a caller reading an error would.\n *\n * `typeof` alone says \"object\" for a Date, an array and a Map alike, which is the least useful thing\n * it could say in a message whose job is to tell somebody what to convert. The value is never\n * converted to a string along the way: an object's own conversion can throw, or say nothing about\n * what the object is.\n *\n * @param {any} value The value.\n * @return {string} `'a Date'`, `'an array'`, `'a plain object with keys a, b'`, `'a boolean'`,\n * `'NaN'`, and so on.\n */\nexport function describeType(value) {\n if (value === null) {\n return 'null';\n }\n\n if (typeof value === 'number') {\n // A number that fails a number check is NaN or an infinity, and \"got a number\" would say nothing.\n return Number.isFinite(value) ? 'a number' : String(value);\n }\n\n if (typeof value === 'undefined') {\n return 'undefined';\n }\n\n if (typeof value !== 'object') {\n return `a ${typeof value}`;\n }\n\n let name;\n\n try {\n if (Array.isArray(value)) {\n return 'an array';\n }\n\n // '[object Date]' when there is no constructor name to read: a null prototype, a replaced\n // constructor property.\n name = constructorName(value) ?? Object.prototype.toString.call(value).slice(8, -1);\n\n if (name === 'Object') {\n // The name an object inheriting from another reads through its chain, too - from\n // `Object.create({number: 1, text: 'x'})`, or an instance of an anonymous class - and calling that\n // plain would contradict a message asking for one: \"metadata must be a plain object; got a plain\n // object\".\n if (!isPlainObject(value)) {\n return 'an object whose prototype is not Object.prototype';\n }\n\n const keys = Object.keys(value);\n\n if (keys.length === 0) {\n return 'a plain object';\n }\n\n // Capped, because the message is for a person and an object can have any number of keys.\n return `a plain object with keys ${keys.slice(0, 5).join(', ')}${keys.length > 5 ? ', ...' : ''}`;\n }\n } catch {\n // A revoked Proxy throws from Array.isArray itself.\n return 'an object';\n }\n\n // 'an Error', 'an Int32Array', but 'a Uint8Array': a leading U is read \"you\".\n return `${/^[aeio]/i.test(name) ? 'an' : 'a'} ${name}`;\n}\n","// @ts-check\n\nimport {isStoredAsInt} from './cellRules.js';\n\n/**\n * How one symbol is laid out in the symbol table, said once.\n *\n * | Kind | Bytes after the type byte |\n * | --- | --- |\n * | 1, int | int32, little-endian |\n * | 2, double | float64, little-endian |\n * | 4, string | UTF-8 text, then a NUL |\n * | 5, dual int | int32, then UTF-8 text and a NUL |\n * | 6, dual double | float64, then UTF-8 text and a NUL |\n *\n * Nothing here validates. A caller checks its values through `cellRules` first, and these\n * functions encode what they are given.\n */\n\n/**\n * The kind a value is stored as.\n *\n * The number decides between int and double - through `isStoredAsInt`, which is Qlik's rule - and\n * the presence of a text decides between pure and dual. Nothing else does: a text is never parsed\n * to choose a kind.\n *\n * @param {number|null} number The numeric half, or null for a string.\n * @param {string|null} text The text, or null for a pure number.\n * @return {1|2|4|5|6} The type byte.\n */\nexport function kindOf(number, text) {\n if (number === null) {\n return 4;\n }\n\n if (isStoredAsInt(number)) {\n return text === null ? 1 : 5;\n }\n\n return text === null ? 2 : 6;\n}\n\n/**\n * The bytes one symbol takes, type byte and terminator included.\n *\n * @param {number} kind The type byte.\n * @param {number|null} number The numeric half, unused for kind 4.\n * @param {string|null} text The text, unused for kinds 1 and 2.\n * @return {number} The length in bytes.\n */\nexport function symbolByteLength(kind, number, text) {\n const numberBytes = kind === 1 || kind === 5 ? 4 : kind === 2 || kind === 6 ? 8 : 0;\n // @ts-ignore - a kind of 4, 5 or 6 carries a text\n const textBytes = kind >= 4 ? Buffer.byteLength(text, 'utf8') + 1 : 0;\n\n return 1 + numberBytes + textBytes;\n}\n\n/**\n * Encodes one symbol into a buffer.\n *\n * The buffer is expected to be sized with `symbolByteLength`, so every byte in the range is written:\n * a buffer from `Buffer.allocUnsafe` holds whatever memory it was given, and a byte skipped here\n * would put that memory into the file.\n *\n * @param {Buffer} buffer The buffer.\n * @param {number} offset Where the type byte goes.\n * @param {number} kind The type byte.\n * @param {number|null} number The numeric half, unused for kind 4.\n * @param {string|null} text The text, unused for kinds 1 and 2.\n * @return {number} The offset after the symbol.\n */\nexport function writeSymbol(buffer, offset, kind, number, text) {\n buffer[offset++] = kind;\n\n if (kind === 1 || kind === 5) {\n // @ts-ignore - kinds 1 and 5 carry a number\n offset = buffer.writeInt32LE(number, offset);\n } else if (kind === 2 || kind === 6) {\n // @ts-ignore - kinds 2 and 6 carry a number\n offset = buffer.writeDoubleLE(number, offset);\n }\n\n if (kind >= 4) {\n // @ts-ignore - kinds 4, 5 and 6 carry a text\n offset += buffer.write(text, offset, 'utf8');\n buffer[offset++] = 0;\n }\n\n return offset;\n}\n","// @ts-check\n\nimport {DUAL_BRAND, asDual, checkNumber, checkText} from './util/cellRules.js';\n\n/**\n * A Qlik dual value, holding both of its halves: a number, and the text Qlik displays for it.\n *\n * Qlik stores dates, timestamps and formatted numbers this way - the date `1756-01-01` is the number\n * -52593 with that text, and a fare of `4.50` is the number 4.5 with that text. To Qlik the value\n * *is* the number: it sums, sorts and compares by it, and the text belongs to how the field shows it.\n * That is why a read returns a dual as its number by default, and keeps the text with the frame so a\n * write puts it back. Read with `{duals: 'both'}` to get this object instead, for a cell that has to\n * carry both halves on its own - through a worker, or into another frame.\n *\n * It has no `valueOf` and no `toString`, and every implicit conversion throws a `TypeError`: `+`,\n * `-`, `<`, `==` against a primitive, a template literal, `String()`, `Number()`, `new Date()`,\n * `join()` and a default `sort()`. Each of those has to pick one half, and whichever it picked would\n * be wrong somewhere - `new Date(dual)` of a date's serial is a moment in January 1970, and a string\n * comparison of a fare's number is not a comparison of its text. Read `.number` or `.text` instead:\n *\n * ```js\n * const fare = new QvdDual(4.5, '4.50');\n * fare.number + 1; // 5.5\n * fare.text; // '4.50'\n * `${fare}`; // TypeError\n * ```\n *\n * It is plain data: `number` and `text` are own, enumerable, read-only properties, and the object is\n * frozen. So `structuredClone`, `postMessage`, `v8.serialize` and `JSON` all turn it into\n * `{number, text}`, and the writer accepts exactly that shape as a dual, from any copy of this\n * library. `===` compares identity, as for any object.\n */\nexport class QvdDual {\n /**\n * Constructs a dual value.\n *\n * The storage kind is not chosen here. The writer derives it from the number, as Qlik does: an\n * integer inside the int32 range is stored as a dual int, anything else as a dual double.\n *\n * @param {number} number The numeric half. Must be a finite number.\n * @param {string} text The text half. Must be a string with no NUL and no unpaired surrogate.\n * @throws {QvdValidationError} If either half cannot be stored in a QVD. The message names the half.\n */\n constructor(number, text) {\n checkNumber(number, 'The number of a dual value', {half: 'number'});\n checkText(text, 'The text of a dual value', {half: 'text'});\n\n defineHalves(this, number, text);\n }\n\n /**\n * Refuses every implicit conversion. See the class comment for why neither half is a safe answer.\n *\n * The hint JavaScript passes is not used: `'number'`, `'string'` and `'default'` say which\n * conversion ran, not which half the caller meant, and the fix is the same for all three.\n *\n * @return {never}\n * @throws {TypeError} Always.\n */\n [Symbol.toPrimitive]() {\n throw new TypeError(\n `A QvdDual holds two values, ${this.number} and ${JSON.stringify(this.text)}; use .number or .text`,\n );\n }\n\n /**\n * Both halves, so `JSON.stringify` loses neither - and produces the shape the writer accepts back.\n *\n * @return {{number: number, text: string}} The dual as a plain object.\n */\n toJSON() {\n return {number: this.number, text: this.text};\n }\n\n /**\n * How Node's `util.inspect` and `console.log` show a dual.\n *\n * @return {string} For example `QvdDual(4.5, \"4.50\")`.\n */\n [Symbol.for('nodejs.util.inspect.custom')]() {\n return `QvdDual(${this.number}, ${JSON.stringify(this.text)})`;\n }\n\n /** @return {string} `'QvdDual'`, for `Object.prototype.toString`. */\n get [Symbol.toStringTag]() {\n return 'QvdDual';\n }\n\n /**\n * Whether a value is a dual cell: a `QvdDual` from any copy of this library, or a plain object whose\n * own enumerable keys are exactly `number` and `text`, which is what a clone of one becomes.\n *\n * Recognition only. The halves are checked when the value is written.\n *\n * @param {any} value Any value.\n * @return {boolean} True for a dual cell.\n */\n static isDual(value) {\n return asDual(value) !== null;\n }\n}\n\n// On the prototype and not enumerable, so it is never copied: a clone is recognised by its shape,\n// and a copy of this class loaded elsewhere by the same key.\nObject.defineProperty(QvdDual.prototype, DUAL_BRAND, {value: true});\n\n/**\n * Defines a dual's halves as own, enumerable, read-only properties and freezes it.\n *\n * Own and enumerable is the point: those are the properties every clone keeps. A getter on the\n * prototype would clone to `{}`.\n *\n * @param {object} target The object being built.\n * @param {number} number The numeric half.\n * @param {string} text The text half.\n */\nfunction defineHalves(target, number, text) {\n Object.defineProperties(target, {\n number: {value: number, enumerable: true},\n text: {value: text, enumerable: true},\n });\n\n Object.freeze(target);\n}\n\n/**\n * A `QvdDual` for a symbol read from a file, taken as stored.\n *\n * Not validated, because a read reports what the file holds: a damaged file's NaN double reads as\n * NaN, and the writer refuses it if anyone stores it again. Built without calling the constructor\n * rather than by setting a flag the constructor reads, so no state outlives the call - a flag left\n * set by a call that threw would have switched validation off for the next `new QvdDual`.\n *\n * @param {number} number The stored int or double.\n * @param {string} text The stored text.\n * @return {QvdDual} A frozen dual.\n */\nexport function dualFromSymbol(number, text) {\n const dual = Object.create(QvdDual.prototype);\n\n defineHalves(dual, number, text);\n\n return dual;\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Checks an option that is a boolean and nothing else.\n *\n * A truthy string is the reason this refuses rather than coerces: `{atomic: 'false'}` would switch on\n * exactly what the caller asked to switch off, and a write that replaces the file where one was asked\n * to rewrite it - or the other way round - is not something they would find out about until it\n * mattered. The same goes for `{coerceNumericStrings: 1}`, which is where the rule started.\n *\n * `undefined` and `null` both mean \"nothing was said\", and `whenUnset` decides what that means. The\n * two callers read it differently on purpose: a read's `coerceNumericStrings` is off unless asked\n * for, while a write's `atomic` and `fsync` are on unless refused, because a null out of optional\n * configuration or a JSON round trip must not quietly become the way that loses the previous file.\n * `validatePath` reads a null `allowedDir` as the working directory for the same reason.\n *\n * Both callers get the same message and the same context, which is what this exists for: two copies\n * of the rule agreed only for as long as somebody kept them in step.\n *\n * @param {any} value The option as passed.\n * @param {{option: string, file: string, whenUnset: boolean}} about The option's name, the file being\n * read or written, and what an unset option means.\n * @return {boolean} What the option says, or `whenUnset`.\n * @throws {QvdValidationError} If the value is neither a boolean nor unset.\n */\nexport function booleanOption(value, {option, file, whenUnset}) {\n if (value === undefined || value === null) {\n return whenUnset;\n }\n\n if (typeof value !== 'boolean') {\n throw new QvdValidationError(`${option} must be true or false`, {\n option,\n provided: value,\n type: typeof value,\n file,\n });\n }\n\n return value;\n}\n","// @ts-check\n\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {booleanOption} from './optionTypes.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/** What a dual symbol can read back as. The first is the default. */\nconst DUAL_MODES = Object.freeze(['number', 'text', 'both']);\n\n/**\n * Checks the `duals` option.\n *\n * A dual is a number with the text Qlik displays for it: the date -52593 shown as `1756-01-01`, the\n * fare 4.5 shown as `4.50`. Qlik treats the value as its number - it sums, sorts and compares by it -\n * so `'number'` is the default, and the text is kept with the frame so a write puts it back.\n * `'text'` returns the text instead, and `'both'` a frozen `QvdDual` holding both halves.\n *\n * Refused rather than defaulted when unrecognised: a typo such as `'numbers'` falling back to the\n * default would look like it worked, and the first sign of the mistake would be somewhere else.\n *\n * @param {any} value The option as passed. `undefined` and null mean the default.\n * @param {string} filePath The file being read, for the error.\n * @return {'number'|'text'|'both'} The mode.\n * @throws {QvdValidationError} If the value is not one of the modes.\n */\nexport function normaliseDuals(value, filePath) {\n if (value === undefined || value === null) {\n return 'number';\n }\n\n if (!DUAL_MODES.includes(value)) {\n throw new QvdValidationError(`duals must be one of ${DUAL_MODES.map((mode) => `'${mode}'`).join(', ')}`, {\n option: 'duals',\n provided: value,\n file: filePath,\n });\n }\n\n return value;\n}\n\n/**\n * Checks the `coerceNumericStrings` option.\n *\n * Off by default. A string symbol is a value stored with no number, and a read that turned the ones\n * spelled like numbers into numbers returned values the file does not hold: `Number()` accepts\n * leading zeros, exponents, hex prefixes and surrounding whitespace, so `'007'` read as 7 and `'0x10'`\n * as 16. On, it is that rule - see `isNumericText` - for callers who relied on it, and the original\n * text is kept in the frame's `storedSymbols`, so a write stores the string again.\n *\n * It applies to every cell a read would return as a string: a string symbol in every `duals` mode, and\n * a dual's text under `{duals: 'text'}`, which reads as the number the dual stores rather than as\n * `Number(text)`.\n *\n * A boolean and nothing else. A truthy string such as `'false'` switching it on would be the opposite\n * of what was asked, with no error to say so.\n *\n * @param {any} value The option as passed. `undefined` and null mean off.\n * @param {string} filePath The file being read, for the error.\n * @return {boolean} Whether to coerce.\n * @throws {QvdValidationError} If the value is not a boolean.\n */\nexport function normaliseCoerceNumericStrings(value, filePath) {\n return booleanOption(value, {option: 'coerceNumericStrings', file: filePath, whenUnset: false});\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 duals: options.duals,\n coerceNumericStrings: options.coerceNumericStrings,\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`, `fields`, `duals` and `coerceNumericStrings` are absent because they mean\n * nothing here, not because they were forgotten: a read that stops at the XML header has no rows to\n * window and parses no field's symbols to skip or resolve. They are ignored rather than refused, so that\n * one options object can be passed to `readMetadata` and to a data read without the caller having to\n * 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 {QvdValidationError} from '../QvdErrors.js';\nimport {checkNumber, checkText, describeType} from './cellRules.js';\n\n/**\n * The stored-symbol record: what a frame keeps so that the cells it shows write back as the symbols\n * they were read from.\n *\n * A cell shows one value. Usually that value is the whole symbol - a pure number, a pure string - but\n * not always: a dual read as its number has a text the cell does not show, a dual read as its text has\n * a number, and a string read as a number has the text it was spelled with. For each field that holds\n * such a symbol the record keeps one entry, and entry `i` says that a cell holding `values[i]` stands\n * for the stored symbol (`numbers[i]`, `texts[i]`):\n *\n * | `numbers[i]` | `texts[i]` | The stored symbol |\n * | --- | --- | --- |\n * | a number | a string | a dual |\n * | null | a string | a pure string - one read as a number |\n * | a number | null | a pure number, recorded because another symbol reads as the same value |\n *\n * The last row is what lets the writer see a collision: when two different symbols read as one value,\n * both are recorded, and the writer refuses that value rather than guess which symbol a cell meant.\n *\n * It is plain data - arrays of numbers, strings and nulls - so it survives `JSON`, `structuredClone`,\n * `postMessage` and `v8.serialize` whole, and a frame sent elsewhere can be rebuilt with `fromDict`.\n * It is frozen, because every frame derived from a read shares it: a change through one would change\n * what all of them write.\n *\n * @typedef {Object} StoredSymbolsEntry\n * @property {string} field The field the entry describes.\n * @property {ReadonlyArray<number|string>} values What a cell holds for each recorded symbol.\n * @property {ReadonlyArray<number|null>} numbers Each symbol's number, or null for a pure string.\n * @property {ReadonlyArray<string|null>} texts Each symbol's text, or null for a pure number.\n */\n\n/**\n * @typedef {ReadonlyArray<StoredSymbolsEntry>} StoredSymbols\n */\n\n/**\n * Where a reader leaves the record on the header object it returns.\n *\n * `Symbol.for`, so any copy of this library finds it. The property is not enumerable, so the header\n * still deep-equals the one `readMetadata` returns for the same file, and a caller who builds a frame\n * the way the architecture notes show - `new QvdDataFrame(data, columns, df.metadata)` - keeps the\n * record without knowing it exists.\n */\nexport const STORED_SYMBOLS = Symbol.for('qvdjs.storedSymbols');\n\n/**\n * Records this copy of the module has built or validated, so passing one on - to `head()`, `select()`,\n * a chunk of `iterate()` - costs nothing. A WeakSet, so it holds no record alive.\n *\n * @type {WeakSet<object>}\n */\nconst trusted = new WeakSet();\n\n/**\n * Freezes a record the reader built and marks it as needing no validation.\n *\n * A reader's record is taken as the file stores it. A damaged file's NaN double is recorded as NaN,\n * which validation would refuse: a read reports what is there, and the writer refuses the value if\n * anyone stores it again.\n *\n * @param {Array<StoredSymbolsEntry>} entries Entries whose arrays are already frozen.\n * @return {StoredSymbols} The record.\n */\nexport function trustStoredSymbols(entries) {\n const record = Object.freeze(entries);\n\n trusted.add(record);\n\n return record;\n}\n\n/**\n * Leaves a record on a header object, without making it part of what the header enumerates.\n *\n * @param {any} metadata The header object a read returns.\n * @param {StoredSymbols} record The record.\n */\nexport function attachStoredSymbols(metadata, record) {\n if (metadata !== null && typeof metadata === 'object' && Object.isExtensible(metadata)) {\n Object.defineProperty(metadata, STORED_SYMBOLS, {value: record, enumerable: false, configurable: true});\n }\n}\n\n/**\n * Throws a validation error about a record.\n *\n * @param {string} message The message.\n * @param {Object} context The context.\n * @return {never}\n * @throws {QvdValidationError} Always.\n */\nfunction refuse(message, context) {\n throw new QvdValidationError(message, context);\n}\n\n/**\n * A record checked, frozen and safe to write from, or null for none.\n *\n * Every check a writer relies on is made here, once, so a record typed by hand or rebuilt from JSON\n * can be refused with a message rather than producing a file. What it does *not* check is whether two\n * entries make a value ambiguous; the writer works that out for the values a column actually holds,\n * so a record merged from two reads is checked against the cells it is used with.\n *\n * @param {any} record The record, null or undefined.\n * @return {StoredSymbols|null} A frozen record - the same one when it was already trusted, otherwise\n * a frozen copy - or null.\n * @throws {QvdValidationError} If the record is not an array of well-formed entries.\n */\nexport function normaliseStoredSymbols(record) {\n if (record === null || record === undefined) {\n return null;\n }\n\n if (typeof record === 'object' && trusted.has(record)) {\n return record;\n }\n\n if (!Array.isArray(record)) {\n refuse(`storedSymbols must be an array of field entries; got ${describeType(record)}`, {\n option: 'storedSymbols',\n type: typeof record,\n });\n }\n\n /** @type {Set<string>} */\n const fields = new Set();\n\n const entries = record.map((entry, index) => {\n if (entry === null || typeof entry !== 'object' || Array.isArray(entry) || typeof entry.field !== 'string') {\n refuse('Each storedSymbols entry must be an object with a string field name', {entry: index});\n }\n\n const {field, values, numbers, texts} = entry;\n\n if (fields.has(field)) {\n refuse(`storedSymbols lists field '${field}' twice`, {field, entry: index});\n }\n\n fields.add(field);\n\n if (\n !Array.isArray(values) ||\n !Array.isArray(numbers) ||\n !Array.isArray(texts) ||\n values.length !== numbers.length ||\n values.length !== texts.length\n ) {\n refuse(`The values, numbers and texts of the storedSymbols entry for '${field}' must be arrays of one length`, {\n field,\n entry: index,\n });\n }\n\n for (let symbol = 0; symbol < values.length; symbol++) {\n const value = values[symbol];\n const number = numbers[symbol];\n const text = texts[symbol];\n const context = {field, symbol};\n\n if (typeof value !== 'number' && typeof value !== 'string') {\n refuse(`A stored symbol's value must be a number or a string; got ${describeType(value)}`, {\n ...context,\n type: typeof value,\n });\n }\n\n if (number !== null) {\n checkNumber(number, \"A stored symbol's number\", context);\n }\n\n if (text !== null) {\n checkText(text, \"A stored symbol's text\", context);\n }\n\n // What each kind of symbol can be read as. A dual reads as one of its halves; a pure string as\n // itself or, coerced, as a number; a pure number only as itself. An entry that says otherwise\n // would write a symbol no read of it could have produced.\n const consistent =\n number !== null && text !== null\n ? sameValueZero(value, number) || value === text\n : number === null && text !== null\n ? value === text || (typeof value === 'number' && Number.isFinite(value))\n : number !== null && sameValueZero(value, number);\n\n if (!consistent) {\n refuse(\n number === null && text === null\n ? 'A stored symbol needs a number or a text'\n : \"A stored symbol's value must be its number or its text\",\n {...context, value, number, text},\n );\n }\n }\n\n return Object.freeze({\n field,\n values: Object.freeze(values.slice()),\n numbers: Object.freeze(numbers.slice()),\n texts: Object.freeze(texts.slice()),\n });\n });\n\n return trustStoredSymbols(entries);\n}\n\n/**\n * The entries of a record for some of its fields, sharing them rather than copying.\n *\n * @param {StoredSymbols|null} record The record.\n * @param {ReadonlyArray<string>} columns The fields to keep.\n * @return {StoredSymbols|null} The narrowed record: the same one when nothing is dropped, an empty one\n * when nothing is kept, and null only when there was none. Never null for a record, because a frame\n * given null takes the one a read left on its header, with entries for every field of the read.\n */\nexport function narrowStoredSymbols(record, columns) {\n if (record === null) {\n return null;\n }\n\n const kept = record.filter((entry) => columns.includes(entry.field));\n\n return kept.length === record.length ? record : trustStoredSymbols(kept);\n}\n\n/**\n * The entry for one field, or null.\n *\n * @param {StoredSymbols|null} record The record.\n * @param {string} field The field.\n * @return {StoredSymbolsEntry|null} The entry.\n */\nexport function storedSymbolsEntry(record, field) {\n if (record === null) {\n return null;\n }\n\n return record.find((entry) => entry.field === field) ?? null;\n}\n\n/**\n * Value-to-text maps for `textAt`, built on first use per entry. Weak, so an entry that is no longer\n * referenced takes its map with it.\n *\n * @type {WeakMap<StoredSymbolsEntry, Map<number|string, string>>}\n */\nconst firstTexts = new WeakMap();\n\n/**\n * Each value of a record entry, mapped to the text a cell holding it stands for.\n *\n * The text of the first symbol holding the value that has one. Symbols are in the order they appear\n * in the file, and a pure number recorded for a collision has no text, so a dual's text wins over it\n * whichever of the two the file stores first. A value no symbol gives a text is not in the map.\n *\n * Built from the last symbol to the first, so an earlier text overwrites a later one and each symbol\n * costs one write rather than a lookup and a write.\n *\n * @param {StoredSymbolsEntry} entry The field's entry.\n * @return {Map<number|string, string>} Value to text.\n */\nexport function firstTextByValue(entry) {\n /** @type {Map<number|string, string>} */\n const byValue = new Map();\n\n for (let index = entry.values.length - 1; index >= 0; index--) {\n const text = entry.texts[index];\n\n if (text !== null) {\n byValue.set(entry.values[index], text);\n }\n }\n\n return byValue;\n}\n\n/**\n * The text a cell stands for, according to a record entry - see `firstTextByValue`.\n *\n * @param {StoredSymbolsEntry} entry The field's entry.\n * @param {number|string} value The cell.\n * @return {string|null} The text, or null when the entry gives the value none.\n */\nexport function storedTextOf(entry, value) {\n let byValue = firstTexts.get(entry);\n\n if (byValue === undefined) {\n byValue = firstTextByValue(entry);\n firstTexts.set(entry, byValue);\n }\n\n return byValue.get(value) ?? null;\n}\n\n/**\n * `SameValueZero`, the equality a Map uses for its keys: `===`, except that NaN equals NaN.\n *\n * @param {any} a One value.\n * @param {any} b The other.\n * @return {boolean} Whether they are the same value.\n */\nexport function sameValueZero(a, b) {\n return a === b || (a !== a && b !== b);\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\n\n/**\n * How many symlinks one path may be followed through before the walk gives up.\n *\n * A chain of dangling links terminates only because the kernel answers ELOOP for a cycle rather\n * than ENOENT, and every caller here reaches this code only after the kernel has already answered\n * ENOENT for the same path. This is the belt to that brace: past this many hops the open() these\n * callers precede would answer ELOOP itself, so stopping costs nothing real, and the walk cannot\n * run away on a filesystem that reports a cycle some other way. 40 is Linux's own MAXSYMLINKS, the\n * most permissive of the platforms here.\n */\nexport const MAX_LINK_HOPS = 40;\n\n/**\n * What `readDanglingLink` returns for a name that is on disk and is not a symlink, so there is\n * nothing to follow.\n */\nexport const NOT_A_LINK = Symbol('not a link');\n\n/**\n * What `readDanglingLink` returns for a symlink whose target it could not read. Callers must decide\n * what that means for them rather than treating it as either of the other two answers: it is a link,\n * so it is not `NOT_A_LINK`, and where it points is unknown, so it is not a path.\n */\nexport const UNREADABLE_LINK = Symbol('unreadable link');\n\n/**\n * Follows one symlink whose target does not exist.\n *\n * `realpath()` answers ENOENT for two different things, and they need opposite treatment:\n *\n * - A name that is not on disk. Whoever asked is about to create it, and the name they gave is the\n * name that will be created.\n * - A symlink pointing at a name that is not on disk. The name *is* on disk - it is the link's\n * target that is missing - and an `open()` of the path follows the link and creates the file at\n * the target, wherever that is.\n *\n * Telling the two apart is what decides both whether a path is inside its sandbox and which file a\n * write replaces. `validatePath` answers both in one walk, and the writer and the reader open what\n * that walk found rather than resolving the path again - see `checkPath` there. The two questions\n * used to be answered by two walks through this one function, which kept their rules alike but still\n * let them reach different files when a link changed between the walks: #247.\n *\n * @param {string} target Path whose `realpath()` or `stat()` answered ENOENT or ENOTDIR.\n * @return {string|typeof NOT_A_LINK|typeof UNREADABLE_LINK} Where the link points, resolved against\n * its own directory, or one of the two sentinels above.\n */\nexport function readDanglingLink(target) {\n /** @type {import('fs').Stats} */\n let link;\n\n try {\n link = fs.lstatSync(target);\n } catch {\n // Not on disk under its own name either, or an ancestor is a file or a dangling link itself.\n // Nothing here to follow.\n return NOT_A_LINK;\n }\n\n if (!link.isSymbolicLink()) {\n // The name is on disk and is not a link, yet the caller's own call could not resolve it: the two\n // disagree, which on a quiet filesystem they cannot. What they can disagree about is a link\n // replaced between them. There is nothing here to follow either way.\n return NOT_A_LINK;\n }\n\n /** @type {string} */\n let destination;\n\n try {\n destination = fs.readlinkSync(target);\n } catch {\n return UNREADABLE_LINK;\n }\n\n if (path.isAbsolute(destination)) {\n return destination;\n }\n\n // A relative target is resolved against the directory the link *physically* lives in, which is\n // what the kernel does: by the time it reads the link it has already resolved every directory it\n // walked through. Resolving against the lexical parent instead is not a near-enough approximation,\n // it is an escape. Given an alias inside allowedDir pointing at a shallower directory inside it -\n // say `<allowed>/deep/sub/alias` -> `<allowed>` - a link reached as `.../alias/link.qvd` lives at\n // `<allowed>/link.qvd`, so `../outside/x` means `<outside>/x` to the kernel and\n // `<allowed>/deep/sub/outside/x` to path.dirname. The first is out of the sandbox and the second\n // is in it, so the check passed a path an in-place write then created outside allowedDir.\n //\n // A parent that cannot be canonicalised leaves the target unknown, which is not the same as there\n // being no link: saying so lets each caller refuse rather than guess.\n try {\n return path.resolve(fs.realpathSync(path.dirname(target)), destination);\n } catch {\n return UNREADABLE_LINK;\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport {QvdSecurityError, QvdValidationError} from '../QvdErrors.js';\nimport {MAX_LINK_HOPS, NOT_A_LINK, UNREADABLE_LINK, readDanglingLink} from './linkTarget.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 * What resolveDeepestExisting returns for a path that must be refused outright rather than handed\n * to the lexical fallback.\n *\n * Falling back is safe for EACCES and ELOOP because the open() that follows fails for the same\n * reason, so letting the path through costs nothing. That argument does not hold for a symlink the\n * walk could not read: the open() would succeed, at whatever the link points at, while the lexical\n * test saw only the link's own name inside allowedDir.\n */\nconst REFUSED = Symbol('refused');\n\n/**\n * What resolveDeepestExisting found.\n *\n * @typedef {Object} DeepestExisting\n * @property {string} deepest Canonical path of the deepest existing ancestor: the target itself when\n * it exists.\n * @property {boolean} exists Whether `deepest` is the target itself rather than an ancestor of it.\n * @property {string} farEnd The name an open() of the target reaches: the target, or the far end of\n * the dangling symlinks it names. It is what a write creates when the target does not exist.\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 * A component that is a dangling symlink is followed rather than stepped over. See\n * readDanglingLink in ./linkTarget.js for why the difference is what decides whether a write stays\n * in the sandbox.\n *\n * It also reports where the path leads, and not only whether that is inside the sandbox, because\n * the reader and the writer open what this walk found rather than resolving the path a second time.\n * A second resolution is a second answer, and #247 was the reader and the writer each following a\n * symlink swapped in after the first one: the check approved one file and the open reached another.\n *\n * @param {string} target Absolute, lexically resolved path.\n * @return {DeepestExisting|null|typeof REFUSED} What the walk found, null if it could not be\n * determined, or REFUSED for a path that must not reach the lexical test.\n */\nfunction resolveDeepestExisting(target) {\n let current = target;\n let farEnd = target;\n let walkedUp = false;\n /** Whether a link was followed after the walk had started climbing - see below. */\n let followedWhileClimbing = false;\n let hops = 0;\n\n for (;;) {\n try {\n const deepest = fs.realpathSync(current);\n\n // A file that does not exist yet is created at the far end, and the far end is spelled through\n // the directory the walk just resolved: its canonical path, then whatever lay below it. So the\n // name is opened through directories this check resolved rather than through the path again - a\n // symlinked directory that existed at the check is not traversed a second time at the open. That\n // holds only where the walk reached this directory by climbing from the far end; a link followed\n // on the way up leaves the file's directory missing, so the open fails whatever is said here.\n const canonicalFarEnd =\n walkedUp && !followedWhileClimbing ? path.join(deepest, path.relative(current, farEnd)) : farEnd;\n\n return {deepest, exists: !walkedUp, farEnd: canonicalFarEnd};\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 // Unless the component is a dangling symlink, which answers ENOENT while being very much on\n // disk. Stepping up past it would judge the link's own name rather than its target.\n const followed = readDanglingLink(current);\n\n if (followed === UNREADABLE_LINK) {\n return REFUSED;\n }\n\n if (followed !== NOT_A_LINK) {\n if (++hops > MAX_LINK_HOPS) {\n return REFUSED;\n }\n\n current = followed;\n\n // Only a link at the end of the path moves the file. One met on the way up - a directory\n // that is a dangling link - leaves the file with no directory to be created in, so an\n // open() of it fails whatever this says, and the far end stays where it was.\n if (walkedUp) {\n followedWhileClimbing = true;\n } else {\n farEnd = followed;\n }\n\n continue;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n walkedUp = true;\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 * - Dangling symlinks. A link whose target does not exist yet is followed to where it points\n * rather than resolved, because realpath() cannot tell that name from one that is simply absent.\n * Both answer ENOENT, and treating the link as absent judged its parent instead of its target -\n * which let an in-place write create the file outside allowedDir.\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 * Identity is read with {bigint: true}, and that is load-bearing. On Windows the inode is the\n * 64-bit NTFS file ID, with the MFT record number in the low 48 bits and a reuse counter in the\n * high 16, so any record whose counter has reached 32 has an ID of 2^53 or more. As a Number that\n * loses its low bits, and two directories created one after the other - adjacent records with the\n * same counter - can round to the same value. The sibling then compares equal to the base, and\n * every path under it passes as contained, symlink or not. It is the likeliest explanation of CI\n * run 35339008309, where a Windows runner accepted every path under a sibling of allowedDir.\n *\n * A check on a path is only as good as the open that follows it, because the path can change in\n * between. So this also returns what it approved: the file an open of the path reaches, and that\n * file's identity when it exists. `openChecked` in ./openChecked.js opens exactly that file, refuses\n * a symlink swapped in at its name, and compares the descriptor it gets with this identity, which is\n * what #247 was missing. What no check made through Node's API can cover is a directory further up\n * the path swapped for a symlink: see `openChecked` for that residual, and why it remains.\n *\n * @param {string} resolvedBaseDir Absolute, lexically resolved base directory.\n * @param {string} resolvedPath Absolute, lexically resolved candidate path.\n * @return {{contained: boolean, target: string, stats: import('fs').BigIntStats|null}|null} Whether\n * the path is contained, the file an open of it reaches, and that file's stats if it exists - or\n * null when the filesystem could not answer.\n */\nfunction isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {\n /** @type {import('fs').BigIntStats} */\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), {bigint: true});\n } catch {\n return null;\n }\n\n const found = resolveDeepestExisting(resolvedPath);\n\n // A dangling symlink the walk could not read. The lexical fallback would judge the link's own\n // name, which is inside allowedDir, while the open() still went wherever the link points, so\n // there is nothing safe to fall back to.\n if (found === REFUSED) {\n return {contained: false, target: resolvedPath, stats: null};\n }\n\n if (found === null) {\n return null;\n }\n\n // An existing file is opened by its canonical path, whose last component is not a symlink - which\n // is what lets the open refuse one that appears there afterwards. A file that does not exist yet is\n // created at the far end of any dangling links, as an open() of the path itself would create it.\n const target = found.exists ? found.deepest : found.farEnd;\n /** @type {import('fs').BigIntStats|null} */\n let stats = null;\n let current = found.deepest;\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 (let first = true; ; first = false) {\n const ownIdentity = first && found.exists;\n let stat;\n try {\n // The file's own identity is read without following a link at its name. realpathSync() resolved\n // it a moment ago to a name whose last component was not a link, but a link can be swapped in\n // before this line, and stat would then record whatever it points at - outside allowedDir,\n // perhaps - as the file this check approved. An open that follows the same link, which is what\n // Windows does for want of O_NOFOLLOW, would then match that identity and be let through. lstat\n // records the link as the link it is, which no open of its target can match. Only the file\n // itself: the directories above it are compared as they always were.\n stat = ownIdentity ? fs.lstatSync(current, {bigint: true}) : fs.statSync(current, {bigint: true});\n } catch {\n return null;\n }\n\n // The first stat is of the file itself when it exists. It is kept from this walk rather than\n // taken again later, so the identity an open is held to is the identity this check approved.\n if (ownIdentity) {\n stats = stat;\n }\n\n // Both sides are BigInts, so this compares every bit of the ID rather than a rounded double.\n if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {\n return {contained: true, target, stats};\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return {contained: false, target, stats};\n }\n current = parent;\n }\n}\n\n/**\n * A path the containment check approved, and what it approved.\n *\n * @typedef {Object} CheckedPath\n * @property {string} path The lexically resolved path, which is what callers report: the path they\n * were given, made absolute.\n * @property {string} base The allowed directory the check was made against, resolved. Held so that a\n * later check of the same path is made against the same directory, whatever the working directory\n * has become since.\n * @property {string} target The file an open of the path reaches: its canonical path when it exists,\n * or the name a write would create. This, and not `path`, is what is opened.\n * @property {import('fs').BigIntStats|null} stats The target's stats as the check found them, or null\n * when it did not exist then. Its `dev` and `ino` are what the opened descriptor is compared with.\n * @property {boolean} onDisk Whether the filesystem decided containment. False when it could not -\n * allowedDir does not exist, or a component refused to resolve - and the lexical fallback did. The\n * target is then only the lexical path, so there is nothing for an open to be held to.\n */\n\n/**\n * Checks that a path stays inside the allowed directory, and says what it found there.\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 * The answer is a path and the file it reaches, and the second half is the one that matters to the\n * reader and the writer: they open `target` through `openChecked`, which holds the open to what this\n * approved. Opening `path` instead would resolve it again, and a second resolution can reach a\n * different file from the first.\n *\n * @param {string} filePath The path to check.\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 {CheckedPath} What was checked, and what it reaches.\n */\nexport function checkPath(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.contained;\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 if (onDisk === null) {\n return {path: resolvedPath, base: resolvedBaseDir, target: resolvedPath, stats: null, onDisk: false};\n }\n\n return {path: resolvedPath, base: resolvedBaseDir, target: onDisk.target, stats: onDisk.stats, onDisk: true};\n}\n\n/**\n * Validates that a file path stays inside the allowed directory.\n *\n * `checkPath` without the half that says what the path reaches, for a caller that only needs the\n * answer. The reader and the writer do not use it: see `checkPath` for why.\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 return checkPath(filePath, allowedDir).path;\n}\n","// @ts-check\n\nimport {QvdIOError} from '../QvdErrors.js';\n\n/**\n * Whether an error is the operating system's refusal of a file-system call.\n *\n * Node reports those as system errors, which name the call in `syscall` and the reason in `code`:\n * `ENOENT`, `EISDIR`, `EACCES`, `EBUSY`. Nothing else carries a `syscall` - not this library's own\n * errors, not a `TypeError` from a bug, and not the `RangeError` `readFile` raises for a file above\n * 2 GiB, which is a limit of Node's rather than a failure of the disk and is #122's to answer.\n *\n * Tested by shape rather than with `instanceof Error`, because a system error is made in Node's own\n * realm, and a runner that sandboxes modules - Jest does - has a different `Error` to compare it with.\n *\n * @param {unknown} error What was thrown.\n * @return {boolean} True for a system error.\n */\nfunction isSystemError(error) {\n const candidate = /** @type {{code?: unknown, syscall?: unknown}|null} */ (error);\n\n return (\n candidate !== null &&\n typeof candidate === 'object' &&\n typeof candidate.syscall === 'string' &&\n typeof candidate.code === 'string'\n );\n}\n\n/**\n * A failed file-system call as a `QvdIOError`, or anything else unchanged.\n *\n * Every one of these used to reach the caller as Node's own error (#126), so a caller's\n * `catch (error) { if (error instanceof QvdError) ... }` saw a corrupt file but not a missing one.\n * The system code moves to `context.code` rather than being lost, and Node's error is kept whole as\n * `cause`.\n *\n * The message ends with Node's own - `ENOENT: no such file or directory, open '/data/sales.qvd'` -\n * so a log that prints only messages still names the code, and a search for it still finds the line.\n *\n * @param {unknown} error What the call threw.\n * @param {string} file The QVD file being read or written.\n * @param {'read'|'write'} direction Which of the two, for the message.\n * @return {unknown} A `QvdIOError` whose `cause` is `error`, if the operating system raised it;\n * otherwise `error` itself.\n */\nexport function asIoError(error, file, direction) {\n if (!isSystemError(error)) {\n return error;\n }\n\n const {message, syscall, code} = /** @type {{message: string, syscall: string, code: string}} */ (error);\n\n return new QvdIOError(\n `Could not ${direction} the QVD file: ${message}`,\n {file, operation: syscall, code},\n {cause: error},\n );\n}\n\n/**\n * A `.catch()` handler that rethrows a failed file-system call as a `QvdIOError`.\n *\n * Attached to each call rather than wrapped around the method that makes them, because those methods\n * also run code that is not a file-system call: a caller's `onProgress`, and `signal.throwIfAborted()`,\n * which throws whatever reason the caller aborted with. A system error thrown from either belongs to\n * the caller, and reporting it as a failure to read the QVD file would send them to the wrong place.\n *\n * @param {string} file The QVD file being read or written.\n * @param {'read'|'write'} direction Which of the two, for the message.\n * @return {(error: unknown) => never} The handler.\n */\nexport function rethrowAsIoError(file, direction) {\n return (error) => {\n throw asIoError(error, file, direction);\n };\n}\n\n/**\n * Runs `use` on an open file, then closes it - reporting a failed close only when `use` succeeded.\n *\n * `finally { await handle.close() }`, which this replaced, lets a close that fails replace the error\n * `use` was already throwing, and that error is the one that says what went wrong: a truncated file\n * read as a `QvdCorruptedError`, or a write the disk refused with `ENOSPC`, came back as an `EIO`\n * from the close. A close can fail on the same path for the same reason - a network share reports a\n * write's deferred error when the file is closed - so this is not only a corner case. The file is\n * still closed on that path; only the close's own failure is dropped. A read is one handle through\n * this, header and all, so the rule holds for every read as well as every write.\n *\n * When `use` succeeded, a failed close is the only news and is reported: after a write it can mean\n * the data never reached the disk.\n *\n * @template T\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {(error: unknown) => never} failed What a failed close is rethrown through - the\n * `rethrowAsIoError` handler of the read or write it belongs to.\n * @param {() => Promise<T>} use The work to do with the file.\n * @return {Promise<T>} What `use` returned.\n */\nexport async function closeAfter(handle, failed, use) {\n let result;\n\n try {\n result = await use();\n } catch (error) {\n await handle.close().catch(() => {});\n throw error;\n }\n\n await handle.close().catch(failed);\n\n return result;\n}\n","// @ts-check\n\nimport fs from 'fs';\n// Node's assert, for an invariant a bug in this library would violate - as the reader and the writer\n// use it - never for input.\nimport assert from 'assert';\nimport {QvdSecurityError} from '../QvdErrors.js';\n\n/**\n * `O_NOFOLLOW` where the platform defines it, and nothing where it does not.\n *\n * It makes an open() of a symlink fail with ELOOP instead of following it. POSIX defines it; Windows\n * does not, and `fs.constants.O_NOFOLLOW` is undefined there, so there the open follows a link and\n * it is the identity check that refuses what it reaches.\n */\nexport const NOFOLLOW = fs.constants.O_NOFOLLOW ?? 0;\n\nconst {O_RDONLY, O_WRONLY} = fs.constants;\n\n/**\n * What an open answers when the name it was given has become a symlink since it was checked. ELOOP\n * on Linux and macOS; EMLINK is how the BSDs answer the same thing.\n */\nconst BECAME_A_LINK = new Set(['ELOOP', 'EMLINK']);\n\n/**\n * How the file at a checked path differs from what the check approved.\n *\n * @typedef {'became_a_symlink'|'replaced'|'appeared'} Change\n */\n\n/** What each change says in a message. @type {Record<Change, string>} */\nconst DESCRIPTIONS = {\n became_a_symlink: 'the file became a symbolic link after it was checked',\n replaced: 'the file was replaced by a different one after it was checked',\n appeared: 'a file appeared at the path after it was checked',\n};\n\n/**\n * The error for a file that is not the file the containment check approved.\n *\n * A `QvdSecurityError` like any other containment refusal, with a reason of its own, because what\n * it reports is the same thing a refused path is: an open that would have reached a file the\n * sandbox did not approve. `change` says how, for a caller that logs it.\n *\n * @param {import('./validatePath.js').CheckedPath} checked What was checked.\n * @param {Change} change How the file differs from it.\n * @return {QvdSecurityError} The error.\n */\nfunction changedAfterCheck(checked, change) {\n return new QvdSecurityError(`Path traversal detected: ${DESCRIPTIONS[change]}`, {\n path: checked.path,\n resolvedPath: checked.target,\n allowedDir: checked.base,\n reason: 'changed_after_check',\n change,\n });\n}\n\n/**\n * Opens the file a checked path reaches, and holds the open to what the check approved.\n *\n * `checkPath` decides containment on a path, and a path can change between that decision and the\n * open that follows it - #247, a symlink swapped in after the check and followed by the open. So the\n * open is made on the file the check resolved rather than on the path, and two things hold it\n * there:\n *\n * - **`O_NOFOLLOW`.** The check resolved the file to its canonical path, whose last component was\n * not a symlink. One that is now is refused rather than followed.\n * - **Identity.** A file that existed at the check is compared with the descriptor by device and\n * inode, so a file replaced by another - or, where there is no `O_NOFOLLOW`, a symlink followed to\n * another - is refused. The comparison is of the descriptor, not of a second stat of the path:\n * a second stat would be a second resolution, and could be answered by a different file. And a read\n * of a name the check found empty that opens anyway is refused too: there is no identity to compare\n * it with, and what appeared could be a link to anywhere - which, without `O_NOFOLLOW`, the open\n * has already followed. The read would have failed with ENOENT a moment earlier.\n *\n * A rewrite is truncated here and only here, once the descriptor is known to be the right file.\n * `'w'` truncates as it opens, which would empty whatever the open reached before anything could\n * check that it was the file approved.\n *\n * A rewrite is only ever of a file that existed at the check, because only then is there an identity\n * to hold the open to. A write to a name nothing is at yet never comes here: the writer builds the\n * file beside the name and renames it there, in either mode, because a rename replaces a name rather\n * than following a link at it. An open that creates cannot promise that - on Windows even `O_EXCL`\n * follows a dangling symlink planted at the name, and creates the file wherever it points.\n *\n * What this does not cover, and nothing reached through Node's API can: a *directory* further up the\n * path swapped for a symlink after the check. The open resolves every directory it passes through,\n * and closing that needs `openat()` one component at a time with `O_NOFOLLOW`, which Node does not\n * expose. Nor, without `O_NOFOLLOW`, can Windows refuse a swapped-in link before the open has\n * followed it: the identity check refuses what it reached, but only after the open.\n *\n * Without an on-disk answer from the check - allowedDir did not exist, or the path would not resolve\n * - there is nothing to hold the open to, and it is made as it always was.\n *\n * @param {import('./validatePath.js').CheckedPath} checked What `checkPath` approved.\n * @param {'read'|'rewrite'} purpose Whether the file is read, or rewritten in place.\n * @param {(error: unknown) => never} failed The read's or write's `rethrowAsIoError` handler, for\n * everything that is the operating system's refusal rather than a change.\n * @param {{nofollow?: number}} [platform] `nofollow` is `NOFOLLOW` unless a test supplies another.\n * @return {Promise<import('fs/promises').FileHandle>} The open file. The caller closes it.\n * @throws {QvdSecurityError} If the file is not the one the check approved.\n */\nexport async function openChecked(checked, purpose, failed, {nofollow = NOFOLLOW} = {}) {\n assert(purpose === 'read' || checked.stats !== null, 'A rewrite in place is of a file that exists.');\n\n const noFollow = checked.onDisk ? nofollow : 0;\n const flags = (purpose === 'rewrite' ? O_WRONLY : O_RDONLY) | noFollow;\n\n /** @type {import('fs/promises').FileHandle} */\n let handle;\n\n try {\n handle = await fs.promises.open(checked.target, flags);\n } catch (error) {\n const {code} = /** @type {{code?: string}} */ (error) ?? {};\n\n if (checked.onDisk && noFollow !== 0 && code !== undefined && BECAME_A_LINK.has(code)) {\n throw changedAfterCheck(checked, 'became_a_symlink');\n }\n\n return failed(error);\n }\n\n const stats = checked.stats;\n\n if (stats === null) {\n if (checked.onDisk) {\n await handle.close().catch(() => {});\n throw changedAfterCheck(checked, 'appeared');\n }\n\n return handle;\n }\n\n try {\n const opened = await handle.stat({bigint: true}).catch(failed);\n\n if (opened.dev !== stats.dev || opened.ino !== stats.ino) {\n throw changedAfterCheck(checked, 'replaced');\n }\n\n // Only a regular file: O_TRUNC does nothing to a device or a FIFO, and ftruncate refuses one.\n if (purpose === 'rewrite' && stats.isFile()) {\n await handle.truncate(0).catch(failed);\n }\n } catch (error) {\n // The error on its way out says what went wrong; a close that fails as well is not news.\n await handle.close().catch(() => {});\n throw error;\n }\n\n return handle;\n}\n","// @ts-check\n\nimport crypto from 'crypto';\nimport fs from 'fs';\nimport path from 'path';\nimport {setTimeout as wait} from 'timers/promises';\n\n/**\n * The longest file name the usual filesystems accept, in bytes - ext4, APFS, HFS+, XFS, NTFS and SMB\n * all stop at 255. Bytes rather than characters: the limit is on the encoded name, so a name of\n * accented or CJK characters reaches it sooner than its length suggests.\n */\nconst MAX_NAME_BYTES = 255;\n\n/**\n * Keeps at most `budget` bytes of a name, cutting whole characters.\n *\n * `Buffer.prototype.subarray` would cut in the middle of a multi-byte character and leave a\n * replacement character in the name, so the characters are counted instead - `for...of` walks code\n * points, which keeps a surrogate pair together as well.\n *\n * @param {string} name The name to shorten.\n * @param {number} budget How many bytes of it may be kept.\n * @return {string} As much of the start of it as fits.\n */\nfunction firstBytesOf(name, budget) {\n if (Buffer.byteLength(name) <= budget) {\n return name;\n }\n\n let kept = '';\n let bytes = 0;\n\n for (const character of name) {\n const size = Buffer.byteLength(character);\n\n if (bytes + size > budget) {\n break;\n }\n\n kept += character;\n bytes += size;\n }\n\n return kept;\n}\n\n/**\n * The temporary file a write builds before it replaces the destination.\n *\n * It sits in the destination's own directory, because a rename is only atomic within one filesystem\n * and a temporary directory can be on another. Three things about the name are deliberate:\n *\n * - **It does not end in `.qvd`.** A Qlik load that names a folder rather than a file -\n * `LOAD * FROM [lib://data/*.qvd] (qvd)` - would otherwise pick a half-written one up as a table.\n * - **It says what left it.** A process killed part-way through a write cannot remove its temporary\n * file, so one can survive beside the QVD, and whoever finds it should be able to tell what wrote\n * it and that it was never meant to last.\n * - **It is random, and opened with `'wx'`.** Two processes writing the same QVD never share one, and\n * a name planted in advance - a symlink out of the allowed directory, say - is not written through.\n *\n * The destination's own name is kept only as far as it fits. The marks above add 27 bytes, and a file\n * name may be 255, so a QVD named with 229 or more would otherwise have been given a temporary file\n * the filesystem refuses outright: `toQvd()` failed with ENAMETOOLONG on a name it had written\n * happily until 2.0.0 - measured at 235 characters, where the in-place write still succeeded. What is\n * cut is the end, so the part that identifies the file survives.\n *\n * @param {string} target The file to be replaced.\n * @return {string} The temporary file to build it in.\n */\nexport function temporaryPathFor(target) {\n const marks = `.qvdjs-${crypto.randomBytes(8).toString('hex')}.tmp`;\n const name = `${firstBytesOf(path.basename(target), MAX_NAME_BYTES - marks.length)}${marks}`;\n\n return path.join(path.dirname(target), name);\n}\n\n/**\n * What Windows answers while something else has the file open. POSIX has no equivalent: there EPERM\n * and EACCES are about the directory's permissions, which waiting does not change.\n */\nconst IN_USE = new Set(['EPERM', 'EACCES', 'EBUSY']);\n\n/**\n * How long to wait before each further attempt, in milliseconds - seven attempts within two thirds of\n * a second. Long enough for a scanner to let go of a file it opened when this write closed it, and\n * short enough that a file genuinely held open still fails while the caller is watching.\n */\nconst RETRY_DELAYS = [10, 20, 40, 80, 160, 320];\n\n/**\n * Runs a file-system call, retrying on Windows while it answers that the file is in use.\n *\n * Two kinds of program hold a QVD open briefly without anyone asking them to: a virus scanner or an\n * indexer opening the file this write has just closed, and Qlik Sense reading the one it is about to\n * replace. Neither keeps it for long. graceful-fs, which npm installs through, retries a rename on\n * Windows for these same codes and for this same reason.\n *\n * The error of the last attempt is the one thrown, so a file that is genuinely held open is still\n * reported as `EPERM` rather than as something about retrying.\n *\n * @template T\n * @param {() => Promise<T>} call The call to make.\n * @param {{platform?: string, delays?: Array<number>}} [options] `platform` and `delays` are taken\n * from the running process unless a test supplies them.\n * @return {Promise<T>} What the call returned.\n */\nasync function retrying(call, {platform = process.platform, delays = RETRY_DELAYS} = {}) {\n for (let attempt = 0; ; attempt++) {\n try {\n return await call();\n } catch (error) {\n const {code} = /** @type {{code?: string}} */ (error) ?? {};\n\n if (platform !== 'win32' || attempt >= delays.length || code === undefined || !IN_USE.has(code)) {\n throw error;\n }\n\n await wait(delays[attempt]);\n }\n }\n}\n\n/**\n * Renames `from` over `to`, retrying while Windows reports either as in use.\n *\n * This is the step that makes a write atomic. On POSIX, and on one NTFS volume, it either replaces the\n * destination with the finished file or leaves it exactly as it was; nothing that reads the path sees\n * a part of one.\n *\n * @param {string} from The finished temporary file.\n * @param {string} to The destination it replaces.\n * @param {{platform?: string, delays?: Array<number>}} [options] As `retrying` takes them.\n * @return {Promise<void>} Resolves once the destination is the new file.\n */\nexport function renameOver(from, to, options) {\n return retrying(() => fs.promises.rename(from, to), options);\n}\n\n/**\n * Removes a temporary file that will not be used, throwing nothing.\n *\n * Every call reaches this from a failure that is already on its way to the caller, and that failure\n * says what went wrong. A temporary file that cannot be removed as well is the lesser news, and\n * throwing here would replace the error that explains the write with one about the tidying up. It is\n * still news, though, so it is reported by the answer rather than by an error: the writer names the\n * file it could not remove in the error it is already throwing.\n *\n * @param {string} file The temporary file.\n * @param {{platform?: string, delays?: Array<number>}} [options] As `retrying` takes them.\n * @return {Promise<boolean>} Whether it is gone.\n */\nexport async function removeTemporary(file, options) {\n try {\n // `rm` with `force` rather than `unlink`, for its one useful difference: a file that is already\n // gone is not an error. Something else can remove a temporary file - a system that sweeps them,\n // or a scanner that quarantines one - and reporting that as a failure to remove it would have the\n // writer name a file the caller cannot find in the error it throws.\n //\n // Its own `maxRetries` is left alone. Retrying is this module's to decide, because the rename\n // faces the same Windows condition and the two have to answer it the same way; `rm` retries a\n // different set of codes, on every platform, for a budget of its own.\n await retrying(() => fs.promises.rm(file, {force: true}), options);\n\n return true;\n } catch {\n return false;\n }\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';\n// Node's assert, used only for invariants a bug in this library would violate - \"this private\n// method ran after the one that fills the field it reads\". Never for input: everything a caller\n// can get wrong throws a QvdError with a context object instead.\n//\n// #143 read the old Copilot instruction \"use assertions for validation\" as an explanation for\n// these calls. It is not: every one sits after a method that either assigns the field\n// unconditionally or throws, and 3,570 corruption cases across every bundled fixture and every\n// entry point produced no AssertionError. They are checked, and they stay.\nimport assert from 'assert';\nimport {QvdIOError, QvdValidationError} from './QvdErrors.js';\nimport {checkPath} from './util/validatePath.js';\nimport {closeAfter, rethrowAsIoError} from './util/ioErrors.js';\nimport {openChecked} from './util/openChecked.js';\nimport {removeTemporary, renameOver, temporaryPathFor} from './util/replaceFile.js';\nimport {booleanOption} from './util/optionTypes.js';\nimport {fieldGeometry, writeBitField} from './util/bitUtils.js';\nimport {\n asDual,\n checkNumber,\n checkText,\n constructorName,\n describeType,\n isNumericText,\n numberProblem,\n textProblem,\n} from './util/cellRules.js';\nimport {kindOf, symbolByteLength, writeSymbol} from './util/symbolBytes.js';\nimport {firstTextByValue, normaliseStoredSymbols, sameValueZero} from './util/storedSymbols.js';\n\n/**\n * @typedef {import('./QvdDataFrame.js').QvdDataFrame} QvdDataFrame\n */\n\n/**\n * Persists a QVD file to disk.\n */\n/**\n * The index of the first character in a text that XML 1.0 cannot hold, even written as a character\n * reference: a C0 control other than tab, line feed and carriage return, or U+FFFE or U+FFFF. NUL is one\n * of them; a surrogate without its pair, the other thing XML cannot hold, is `textProblem`'s to report.\n *\n * @param {string} value The text.\n * @return {number} The index, or -1 when there is none.\n */\nfunction notXmlIndex(value) {\n for (let index = 0; index < value.length; index++) {\n const unit = value.charCodeAt(index);\n\n if ((unit < 0x20 && unit !== 0x09 && unit !== 0x0a && unit !== 0x0d) || unit === 0xfffe || unit === 0xffff) {\n return index;\n }\n }\n\n return -1;\n}\n\n/**\n * Throws unless a text can be written into the XML header.\n *\n * The header is XML, which has no way to write a NUL, a surrogate without its pair or a control\n * character such as U+0001. The builder refused each with a bare `Error: Invalid character in string`,\n * naming neither the field nor the property. A read can produce such a text: the parser accepts a raw\n * control character in the header it reads, so a file carrying one in its table name read without\n * complaint and could not be written back.\n *\n * @param {string} value The text.\n * @param {string} subject What the text is, capitalised, as the message starts.\n * @param {Object} context Where the text came from, merged into the error's context.\n * @throws {QvdValidationError} If the text holds a character the header cannot; `context.position` is\n * its index.\n */\nfunction checkHeaderText(value, subject, context) {\n checkText(value, subject, context);\n\n const position = notXmlIndex(value);\n\n if (position !== -1) {\n const code = value.charCodeAt(position).toString(16).toUpperCase().padStart(4, '0');\n\n throw new QvdValidationError(`${subject} cannot contain U+${code}, which XML cannot hold`, {...context, position});\n }\n}\n\n/**\n * Checks every text in a part of the header: a string, or the strings inside an object or an array, as\n * the XML builder would write them.\n *\n * @param {any} value The value.\n * @param {string} property Its path in the header, such as `Lineage.LineageInfo.Statement`.\n * @param {string} owner What the property belongs to, for the message: `the table`, or a field.\n * @param {Object} context Where the value came from, merged into the error's context.\n * @throws {QvdValidationError} If a text holds a character the header cannot.\n */\nfunction checkHeaderTexts(value, property, owner, context) {\n if (typeof value === 'string') {\n checkHeaderText(value, `The ${property} of ${owner}`, {...context, property});\n } else if (Array.isArray(value)) {\n value.forEach((item, index) => checkHeaderTexts(item, `${property}[${index}]`, owner, context));\n } else if (value !== null && typeof value === 'object') {\n for (const [key, item] of Object.entries(value)) {\n checkHeaderTexts(item, `${property}.${key}`, owner, context);\n }\n }\n}\n\n/**\n * Checks the field names before a single row is walked.\n *\n * All three of these produced a file rather than an error. A non-string name was written as\n * whatever it stringified to; a duplicate produced two fields of one name, which makes\n * `at(row, name)` and `select(name)` answer about the first and ignore the second - and which\n * broke two-pass symbol filtering, because the usage sets were keyed by name (#181); and an empty\n * name produced a field nothing can address. A name the header cannot hold - see `checkHeaderText` -\n * is refused here too, before the rows rather than after them.\n *\n * @param {Array<any>} columns The field names.\n * @param {string} filePath The file being written, for the error.\n * @throws {QvdValidationError} If a name is not a usable, unique string.\n */\nfunction validateColumnNames(columns, filePath) {\n /** @type {Set<string>} */\n const seen = new Set();\n\n columns.forEach((name, index) => {\n if (typeof name !== 'string' || name.length === 0) {\n throw new QvdValidationError('Field names must be non-empty strings', {\n column: index,\n provided: name,\n type: typeof name,\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n checkHeaderText(name, 'A field name', {column: index, provided: name, file: filePath, stage: 'buildSymbolTable'});\n\n if (seen.has(name)) {\n throw new QvdValidationError(`Field '${name}' appears twice`, {\n column: name,\n columnIndex: index,\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n seen.add(name);\n });\n}\n\n/**\n * Refuses a cell that is neither a number, a string, a dual value nor NULL.\n *\n * Everything refused here previously produced either a raw `TypeError` from deep inside\n * `Buffer.from`, naming neither the field nor the row, or a file. The file cases are the reason\n * this is not merely a nicer error message: `[1, 2]` became `Buffer.from([1, 2])`, so the array was\n * written as the two *bytes* 1 and 2 and read back as two control characters; and a `Date` was\n * written as its full `toString()`, which carries the writing machine's timezone and locale into the\n * data.\n *\n * A `QvdSymbol` is refused too. It carries a storage kind, which the writer derives from the value\n * instead, and a dual symbol built through its factories was never a dual cell anyone could read back.\n * So is an object that only resembles a dual - `{number, text, date}`, or one that inherits the two\n * properties - because storing it as one would discard the rest of it without a word.\n *\n * Numbers and strings are checked in `cellRules`, which is where the other things that used to\n * produce a file are refused: a string containing a NUL, which ends a string symbol early and made\n * `toQvd` produce a file this same library refuses to read; a string containing an unpaired\n * surrogate, which UTF-8 cannot encode, so it was written as U+FFFD and two different strings could\n * become one stored value; and `NaN` or an infinity, which came back as the string `'NaN'` or as the\n * infinity itself.\n *\n * @param {any} value The value.\n * @param {string} column The field it belongs to, for the error.\n * @param {number} row The row it was first seen on, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {never}\n * @throws {QvdValidationError} Always.\n */\nfunction refuseCell(value, column, row, filePath) {\n let resemblesDual = false;\n\n try {\n resemblesDual =\n value !== null &&\n typeof value === 'object' &&\n ('number' in value || 'text' in value || ('intValue' in value && 'stringValue' in value));\n } catch {\n // A revoked Proxy throws from `in`. It resembles nothing.\n }\n\n throw new QvdValidationError(\n `A QVD field holds numbers, strings, dual values and NULL; ${describeType(value)} cannot be written. ` +\n `Convert it first - a Date to new QvdDual(dateToQlikSerial(date), text), the serial and the text Qlik shows, ` +\n `which is how Qlik stores a date; a boolean to -1 and 0, as a Qlik comparison stores it.` +\n (resemblesDual ? ' A dual value is a QvdDual, or an object whose only keys are number and text.' : ''),\n {\n column,\n row,\n type: typeof value,\n constructor: constructorName(value) ?? undefined,\n file: filePath,\n stage: 'buildSymbolTable',\n },\n );\n}\n\n/**\n * How many dual objects a column remembers by identity before it stops adding them: this many, plus\n * two for every symbol the column holds.\n *\n * A read shares one `QvdDual` per symbol between every row that holds it, so remembering each object\n * makes a repeat cost one lookup, as a repeated number does. A caller who builds a fresh object per\n * row would add one entry per row instead - two million rows, two million entries - so past the bound\n * an object is resolved by its number on every row, which costs a validation and a lookup and holds\n * nothing.\n */\nconst OBJECT_MEMO_BASE = 64;\n\n/**\n * One column's symbols while they are collected.\n *\n * `keys` and `texts` are the slots, in first-appearance order: a slot's key is its number or its\n * string, and its text is the text of a dual, or null. `byKey` maps a key to its slot, so one number is\n * one symbol however it arrived - a plain number, a dual object, a cell resolved through the record.\n * `byCell` maps a primitive cell to its slot, and is `byKey` itself unless the field has a record\n * entry that can map a cell to a different key. `byObject` remembers dual objects by identity, up to\n * a bound.\n *\n * A record entry is looked up one of two ways. When every value in it is its own number - as in every\n * entry a `{duals: 'number'}` read builds without `coerceNumericStrings` - a cell is still its own key,\n * and the entry only gives it a text: `textByNumber`. Any other entry can make a cell stand for another\n * key, or for more than one, and `byValue` lists every symbol holding each value, so all of them can be\n * weighed.\n *\n * @typedef {Object} ColumnSymbols\n * @property {string} name The field name.\n * @property {Array<number|string>} keys Each slot's number or string.\n * @property {Array<string|null>} texts Each slot's text, or null.\n * @property {Map<number|string, number>} byKey Key to slot.\n * @property {Map<number|string, number>} byCell Primitive cell to slot.\n * @property {Map<object, number>} byObject Dual object to slot, bounded.\n * @property {import('./util/storedSymbols.js').StoredSymbolsEntry|null} entry The field's record entry.\n * @property {Map<number|string, string>|null} textByNumber For an entry whose every value is its own\n * number, each number's first text.\n * @property {Map<number|string, number|Array<number>>|null} byValue For any other entry, each value's\n * index or indices in it.\n * @property {SlotFacts} facts What kinds of value the slots hold, for the header.\n */\n\n/**\n * What kinds of value a column's written symbols hold - what decides which of its tags and number\n * format still describe it.\n *\n * @typedef {Object} SlotFacts\n * @property {boolean} hasNumber Some symbol has a number: a pure number or a dual.\n * @property {boolean} hasNonNumber Some symbol is a pure string.\n * @property {boolean} hasFraction Some number is not a whole number.\n */\n\n/**\n * Whether every symbol in a record entry is keyed by the value its cell holds - the symbol's own number,\n * as it is for a dual read as its number and for a pure number recorded beside one.\n *\n * Such an entry cannot make a value ambiguous - each value stands for one number, and no symbol in it\n * is a string - and never maps a cell to a key other than itself. So the cell needs no map of its own\n * and no weighing of entries, only the text the first symbol holding it has.\n *\n * @param {import('./util/storedSymbols.js').StoredSymbolsEntry} entry The entry.\n * @return {boolean} True when every value is its symbol's number.\n */\nfunction valuesAreNumbers(entry) {\n const {values, numbers} = entry;\n\n // A pure string's number is null, which no value is the same as.\n for (let index = 0; index < values.length; index++) {\n if (!sameValueZero(values[index], numbers[index])) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * A slot added after the column's others, for a key it does not have. The caller puts the key in\n * `byKey`.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} key The number or string.\n * @param {string|null} text The text supplied with it, or null.\n * @return {number} The slot.\n */\nfunction newSlot(column, key, text) {\n const slot = column.keys.length;\n\n column.keys.push(key);\n column.texts.push(text);\n\n // Every slot is created here, so the facts cost nothing extra: no pass over the symbols afterwards.\n if (typeof key === 'number') {\n column.facts.hasNumber = true;\n if (!Number.isInteger(key)) column.facts.hasFraction = true;\n } else {\n column.facts.hasNonNumber = true;\n }\n\n return slot;\n}\n\n/**\n * The slot for a key, created at its first appearance.\n *\n * A text is attached to a number slot that has none, in place, whatever order the cells came in: a\n * plain number carries no text, so a dual with the same number supplies it rather than losing it. A\n * slot that already has a text keeps it, which is Qlik's rule - values sharing a number share the first\n * text encountered.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} key The number or string.\n * @param {string|null} text The text supplied with it, or null.\n * @return {number} The slot.\n */\nfunction slotFor(column, key, text) {\n let slot = column.byKey.get(key);\n\n if (slot === undefined) {\n slot = newSlot(column, key, text);\n column.byKey.set(key, slot);\n } else if (text !== null && column.texts[slot] === null && typeof key === 'number') {\n column.texts[slot] = text;\n }\n\n return slot;\n}\n\n/**\n * Whether some of a record entry's symbols say different things about the value they share: two\n * numbers, two texts of pure strings, or a number and a pure string. Those are the symbols one cell\n * could stand for, and the writer refuses to pick one.\n *\n * @param {ReadonlyArray<number>} indices Indices into the entry of symbols that read as one value.\n * @param {ReadonlyArray<number|null>} numbers The entry's numbers.\n * @param {ReadonlyArray<string|null>} texts The entry's texts.\n * @return {boolean} True when they stand for more than one stored value.\n */\nfunction standsForSeveral(indices, numbers, texts) {\n /** @type {number|null} */\n let number = null;\n /** @type {string|null} */\n let string = null;\n\n for (const index of indices) {\n if (numbers[index] !== null) {\n if (number === null) {\n number = numbers[index];\n } else if (!sameValueZero(number, numbers[index])) {\n return true;\n }\n } else if (string === null) {\n string = texts[index];\n } else if (string !== texts[index]) {\n return true;\n }\n }\n\n return number !== null && string !== null;\n}\n\n/**\n * Whether a field whose record entry this is could have been read with `{duals: 'text'}` and, read that\n * way without `coerceNumericStrings`, would still have a value that stands for more than one stored value.\n *\n * Without coercion such a read shows every symbol with a text as that text, and a pure number as itself,\n * so the entry's symbols are grouped that way and weighed as the writer weighs a cell. Every symbol that\n * could end up in such a group is in the entry already: a `'text'` read records every dual, and a string\n * with a dual's text is either numeric, so coercion read it as a number and recorded it, or not, so the\n * dual reads as that text with coercion too and the string is recorded beside it.\n *\n * A dual shown as its number whose text is not numeric proves the entry came from a `'number'` read,\n * because a `'text'` read shows that text. Without coercion a `'number'` read maps no value to two stored\n * values: every value it records is a number, and every symbol under one number has that number.\n *\n * @param {import('./util/storedSymbols.js').StoredSymbolsEntry} entry The entry.\n * @return {boolean} True when a `'text'` read without coercion could still be refused.\n */\nfunction ambiguousAsUncoercedText(entry) {\n const {values, numbers, texts} = entry;\n\n for (let index = 0; index < values.length; index++) {\n if (typeof values[index] === 'number' && numbers[index] !== null && texts[index] !== null) {\n // @ts-ignore - the text was just checked for null\n if (!isNumericText(texts[index])) {\n return false;\n }\n }\n }\n\n /** @type {Map<number|string|null, Array<number>>} */\n const byShown = new Map();\n\n for (let index = 0; index < values.length; index++) {\n const shown = texts[index] ?? numbers[index];\n const indices = byShown.get(shown);\n\n if (indices === undefined) {\n byShown.set(shown, [index]);\n } else {\n indices.push(index);\n }\n }\n\n for (const indices of byShown.values()) {\n if (indices.length > 1 && standsForSeveral(indices, numbers, texts)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether reading the field with `{duals: 'both'}`, coercion left as it was, would leave no value standing\n * for more than one stored value.\n *\n * `'both'` records no dual - each is a `QvdDual` cell of its own - so under a value such a read records the\n * entry's symbols less its duals: strings coercion read as that number, and pure symbols beside them. Every\n * one of those is in the entry already, whichever mode built it, because coercion and the pure symbols\n * beside what it records do not depend on the mode.\n *\n * @param {ColumnSymbols} column The column, whose entry has a value that stands for several stored values.\n * @return {boolean} True when `'both'` is enough.\n */\nfunction unambiguousWithoutDuals(column) {\n // @ts-ignore - only a column with a byValue map refuses a value, and it has an entry\n const {numbers, texts} = column.entry;\n\n // @ts-ignore - see above\n for (const found of column.byValue.values()) {\n if (typeof found !== 'number') {\n const kept = found.filter((/** @type {number} */ index) => numbers[index] === null || texts[index] === null);\n\n if (kept.length > 1 && standsForSeveral(kept, numbers, texts)) {\n return false;\n }\n }\n }\n\n return true;\n}\n\n/**\n * What to do about a field in which a value stands for more than one stored value - the end of that\n * refusal.\n *\n * It names the least change to the read after which no value of the field does, so it is worked out from\n * every value in the field's entry and not only the one refused: advice fitted to that one could lead to a\n * second refusal for another. The entry does not say which duals mode built it, only sometimes shows it: a\n * dual shown as its text comes from a `'text'` read, and one shown as its number whose text is not a\n * number from a `'number'` read. Where the least change depends on the mode, the sentence says how.\n *\n * - **No value stands for a string read as a number beside another stored value:** `{duals: 'both'}`, or\n * `QvdDual` cells. Coercion can stay on, because a string it reads as a number reads as that number in\n * every mode: had it made a value ambiguous, that value would be among the ones weighed.\n * - **One does, and dropping coercion is enough for any read:** without `coerceNumericStrings`. A string\n * then reads as itself, and under `'number'` and `'both'` nothing is left to record two stored values\n * under one value; see `ambiguousAsUncoercedText` for `'text'`.\n * - **Dropping coercion is not enough for a `'text'` read, and `{duals: 'both'}` is:** that, for any read.\n * A string `'4'` beside a dual 4 with the text `4` is the example: a `'text'` read without coercion shows\n * both as `'4'`, and `'both'` shows the dual as a `QvdDual`.\n * - **Neither is enough on its own for a `'text'` read:** both, when the entry shows a `'text'` read. When\n * it does not, the read may have been `'number'`, for which dropping coercion is enough, so the sentence\n * asks for `'both'` as well only if the field was read with `'text'`. Switching to `'number'` is not\n * enough either: it records every dual `'both'` leaves out, and what is ambiguous without them stays so.\n *\n * `'007'` and `'7'` read as 7 in every mode, so a refusal that named only `'both'` for them would send\n * the caller to a read that is refused again.\n *\n * @param {ColumnSymbols} column The column, whose entry has a value that stands for several stored values.\n * @return {string} The sentence.\n */\nfunction ambiguityRemedy(column) {\n // @ts-ignore - only a column with a byValue map refuses a value, and it has an entry\n const {values, numbers, texts} = column.entry;\n let coerced = false;\n let other = false;\n\n // @ts-ignore - see above\n for (const [value, found] of column.byValue) {\n if (typeof found !== 'number' && standsForSeveral(found, numbers, texts)) {\n // Under a value that is a number, every symbol with a number has that number, so what disagrees with\n // them is a pure string - and only coercion reads a pure string as a number.\n if (typeof value === 'number') {\n coerced = true;\n } else {\n other = true;\n }\n }\n }\n\n if (!coerced) {\n return \"Read the field with {duals: 'both'}, or write QvdDual cells.\";\n }\n\n // A value that is a string, and stands for several stored values, is a dual's text a 'text' read\n // showed, and dropping coercion leaves it as ambiguous as it was.\n // @ts-ignore - see above\n if (!other && !ambiguousAsUncoercedText(column.entry)) {\n return 'Read the field without {coerceNumericStrings: true}.';\n }\n\n if (unambiguousWithoutDuals(column)) {\n return \"Read the field with {duals: 'both'}.\";\n }\n\n // A dual shown as its text shows a 'text' read, and every value `other` counted is one.\n return values.some((value, index) => typeof value === 'string' && numbers[index] !== null)\n ? \"Read the field with {duals: 'both'} and without {coerceNumericStrings: true}.\"\n : \"Read the field without {coerceNumericStrings: true}, and with {duals: 'both'} as well if it was read \" +\n \"with {duals: 'text'}.\";\n}\n\n/**\n * The slot for a number or a string cell the column has not seen, through the frame's record.\n *\n * With no record entry for the value, the cell is its own key. Otherwise the entries holding it say\n * what it stands for: one pure string's text, or one number with the first text any of them has. When\n * they say more than one thing - two numbers, two texts, or a number and a string - the cell could be\n * either, and it is refused rather than written as one of them.\n *\n * The ambiguity is worked out here, from the entries themselves, rather than trusted to a read: a\n * record merged from two frames, or built by hand, is checked the same way. An entry whose every value\n * is its own number - see `valuesAreNumbers` - has no ambiguity to find, so the cell only takes its text.\n *\n * Called only for a cell the row loop has just looked for in `byCell` and not found, and whose slot the\n * row loop then puts there.\n *\n * @param {ColumnSymbols} column The column.\n * @param {number|string} value The cell.\n * @param {number} row The row, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {number} The slot.\n * @throws {QvdValidationError} If the record maps the value to more than one stored value.\n */\nfunction slotForCell(column, value, row, filePath) {\n // A cell that is its own key. `byCell` is `byKey` here, so the lookup that missed was for the key: the\n // slot is new, and the row loop's write of it is the write to `byKey`. Asking again, and writing twice,\n // cost two map operations per distinct value.\n if (column.byCell === column.byKey) {\n return newSlot(column, value, column.textByNumber === null ? null : (column.textByNumber.get(value) ?? null));\n }\n\n // @ts-ignore - a column whose cells have a map of their own has an entry that is not keyed by numbers\n const found = column.byValue.get(value);\n\n if (found === undefined) {\n return slotFor(column, value, null);\n }\n\n // @ts-ignore - byValue is only set together with entry\n const {numbers, texts} = column.entry;\n const indices = typeof found === 'number' ? [found] : found;\n\n if (standsForSeveral(indices, numbers, texts)) {\n /** @type {Array<{number: number|null, text: string|null}>} */\n const stored = [];\n\n for (const index of indices) {\n if (!stored.some((pair) => sameValueZero(pair.number, numbers[index]) && pair.text === texts[index])) {\n stored.push({number: numbers[index], text: texts[index]});\n }\n }\n\n throw new QvdValidationError(\n `The value ${JSON.stringify(value)} in field '${column.name}' (row ${row}) was read from ${stored.length} ` +\n `different stored values, so writing it back would have to guess which one. ${ambiguityRemedy(column)}`,\n {column: column.name, row, value, stored, file: filePath, stage: 'buildSymbolTable'},\n );\n }\n\n /** @type {number|null} */\n let number = null;\n /** @type {string|null} */\n let numberText = null;\n\n for (const index of indices) {\n // One stored value: a pure string here means every symbol holding the value is that string.\n if (numbers[index] === null) {\n // @ts-ignore - a symbol with no number has a text\n return slotFor(column, texts[index], null);\n }\n\n number ??= numbers[index];\n numberText ??= texts[index];\n }\n\n // @ts-ignore - every index came from an entry that holds a number or a text, and none was a string\n return slotFor(column, number, numberText);\n}\n\n/**\n * The slot for a dual object the column has not remembered.\n *\n * Keyed by its number, so a fresh object per row costs a validation and a lookup, and never a map\n * entry past the bound. Anything that is not a dual - see `asDual` - is refused.\n *\n * @param {ColumnSymbols} column The column.\n * @param {object} value The cell.\n * @param {number} row The row, for the error.\n * @param {string} filePath The file being written, for the error.\n * @return {number} The slot.\n * @throws {QvdValidationError} If the value is not a dual, or a half of it cannot be stored.\n */\nfunction slotForObject(column, value, row, filePath) {\n const dual = asDual(value);\n\n if (dual === null) {\n refuseCell(value, column.name, row, filePath);\n }\n\n const {number, text} = dual;\n\n // The problem functions allocate nothing for a good half, so the context is only built for a bad one.\n if (numberProblem(number) !== null) {\n checkNumber(number, 'The number of a dual value', {\n column: column.name,\n row,\n half: 'number',\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n if (textProblem(text) !== null) {\n checkText(text, 'The text of a dual value', {\n column: column.name,\n row,\n half: 'text',\n file: filePath,\n stage: 'buildSymbolTable',\n });\n }\n\n const slot = slotFor(column, number, text);\n\n if (column.byObject.size < OBJECT_MEMO_BASE + 2 * column.keys.length) {\n column.byObject.set(value, slot);\n }\n\n return slot;\n}\n\n/** Tags that only hold while every value in the field has a number. */\nconst NUMERIC_TAGS = new Set(['$numeric', '$integer', '$date', '$time', '$timestamp']);\n\n/** Tags that only hold while every value in the field is plain text. */\nconst TEXT_TAGS = new Set(['$text', '$ascii']);\n\n/** Tags that only hold while every number in the field is a whole number. */\nconst WHOLE_NUMBER_TAGS = new Set(['$integer', '$date']);\n\n/** Number formats that describe how Qlik displays a number, and so mean nothing on a text field. */\nconst NUMERIC_FORMATS = new Set(['INTEGER', 'REAL', 'FIX', 'MONEY', 'DATE', 'TIME', 'TIMESTAMP', 'INTERVAL']);\n\n/** What a field with no number format of its own is written with. */\nconst UNKNOWN_NUMBER_FORMAT = Object.freeze({Type: 'UNKNOWN', nDec: '0', UseThou: '0', Fmt: '', Dec: '', Thou: ''});\n\n/**\n * The field's tags, less any the written values contradict.\n *\n * Tags are carried from the header a frame was read with, and a caller can change a field's values\n * without touching its tags - read a timestamp field with `{duals: 'text'}` and write it back, and the\n * values are text while the header still says `$numeric` and `$timestamp`, which tells Qlik a text\n * field is numeric. So a tag the values contradict is dropped:\n *\n * - a value with no number drops `$numeric`, `$integer`, `$date`, `$time` and `$timestamp`;\n * - a number that is not whole drops `$integer` and `$date`;\n * - any number drops `$text` and `$ascii`.\n *\n * The definitions are Qlik's field-tag help: `$numeric` - every non-NULL value is numeric; `$integer`\n * - every value is an integer; `$date` - every value can be read as a date, which it defines as an\n * integer; `$text` - no value is numeric. The bundled Qlik files agree where they can: `$text` and\n * `$ascii` appear only on fields whose every value is a pure string, and a field mixing strings and\n * numbers carries neither. They also show what not to derive. Qlik keeps `$ascii` on fields holding\n * characters outside ASCII - their first such value is always past the hundredth symbol, so it looks\n * like a judgement from the first values rather than all of them - and keeps `$timestamp` on a field of\n * timestamps some of which fall exactly on midnight, so a whole number does not contradict it. The\n * reference files in `docs/reference-qvds/` carry `$date`, and only on fields whose every number is\n * whole, which is what the `$date` rule assumes. No file carries `$time`, not even a field Qlik built\n * with `Time()`, so that rule still rests on the help alone.\n *\n * Only removes, never adds. A tag Qlik would have added is Qlik's to add on its next load; inventing\n * one here would be the writer asserting something it has no way to know - `$date` over an integer\n * field, say. `$key`, `$hidden` and custom tags pass through.\n *\n * @param {any} tags The field's tags as carried in the metadata: `{String: string | string[]}`, or\n * something else, which is returned untouched.\n * @param {SlotFacts|undefined} facts What the field's written symbols hold.\n * @return {any} The tags to write.\n */\nfunction pruneContradictedTags(tags, facts) {\n if (tags === null || typeof tags !== 'object' || tags.String === undefined || facts === undefined) {\n return tags || {};\n }\n\n const list = Array.isArray(tags.String) ? tags.String : [tags.String];\n const kept = list.filter((/** @type {string} */ tag) => {\n if (facts.hasNonNumber && NUMERIC_TAGS.has(tag)) return false;\n if (facts.hasFraction && WHOLE_NUMBER_TAGS.has(tag)) return false;\n if (facts.hasNumber && TEXT_TAGS.has(tag)) return false;\n return true;\n });\n\n if (kept.length === list.length) {\n return tags;\n }\n\n return kept.length === 0 ? {} : {...tags, String: kept};\n}\n\n/**\n * The field's number format, reset when the field no longer holds a number to apply it to.\n *\n * A `DATE` or `MONEY` format on a field whose values are all text describes nothing, and misleads\n * whoever reads the header next. A field that still has a single number keeps its format: Qlik's own\n * files carry `REAL` on a field holding only the integer 0 and `MONEY` on fields where some amounts are integers,\n * so no other mismatch is a contradiction.\n *\n * @param {any} numberFormat The field's number format as carried in the metadata.\n * @param {SlotFacts|undefined} facts What the field's written symbols hold.\n * @return {any} The number format to write.\n */\nfunction resetContradictedNumberFormat(numberFormat, facts) {\n if (!numberFormat) {\n return {...UNKNOWN_NUMBER_FORMAT};\n }\n\n if (facts !== undefined && !facts.hasNumber && facts.hasNonNumber && NUMERIC_FORMATS.has(numberFormat.Type)) {\n return {...UNKNOWN_NUMBER_FORMAT};\n }\n\n return numberFormat;\n}\n\n/**\n * Maximum length of a single fs.write call. Node checks that a write's length fits in an Int32 and\n * rejects one of 2 GiB or more with a RangeError, so a symbol or index table that large could not be\n * written in one call at all. QvdFileReader caps its reads at the same size, and there an oversized\n * length aborts the process rather than throwing.\n */\nconst WRITE_CHUNK_SIZE = 512 * 1024 * 1024;\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 * @param {boolean} [options.atomic=true] Whether to replace the destination rather than rewrite it:\n * the file is built beside it under a temporary name and renamed over it, so a failure leaves the\n * previous file exactly as it was and nothing ever reads a part-written one. False rewrites the\n * destination in place, which is what every version before 2.0.0 did: that keeps the file's\n * identity - hard links, its owner, permissions set on the file itself - needs no room for two\n * copies at once and no permission to create files in the directory, and destroys the previous\n * file the moment the write begins. A file that does not exist yet is renamed into place either\n * way, since there is nothing to rewrite - see `_destination`.\n * @param {boolean} [options.fsync=true] Whether to wait for the file's contents to reach the disk\n * before the write is finished. It is what carries an atomic write's promise through a power\n * loss - the contents are on the disk before anything is renamed, so a crash leaves the previous\n * file or the new one and never a damaged one - and it is the only thing that reports a failing\n * disk's deferred error rather than losing it. The rename itself is not flushed, so a crash just\n * after the call can still lose the replacement, or a file that did not exist before. False\n * resolves as soon as the operating system has accepted the bytes, which is faster and is what\n * every version before 2.0.0 did.\n */\n constructor(filePath, df, options = {}) {\n const {allowedDir, onProgress, atomic, fsync} = options;\n const checked = checkPath(filePath, allowedDir);\n this._path = checked.path;\n /**\n * The allowed directory, resolved. Kept because the path is checked again immediately before the\n * file is written - see `_destination` - and building the tables first can take seconds, which is\n * a long time for a path to go unwatched. That check is made against the directory this one was.\n */\n this._allowedDir = checked.base;\n // Unset means on for both: a null out of optional configuration or a JSON round trip must not\n // quietly become the way that loses the previous file. `booleanOption` says the rest.\n this._atomic = booleanOption(atomic, {option: 'atomic', file: this._path, whenUnset: true});\n this._fsync = booleanOption(fsync, {option: 'fsync', file: this._path, whenUnset: true});\n this._df = df;\n this._onProgress = onProgress;\n this._header = null;\n this._symbolBuffer = null;\n /**\n * Symbols written per column. It used to be the symbols themselves, as QvdSymbol objects, kept\n * alive through the header build and the file write for the sake of their count.\n *\n * @type {Array<number>|null}\n */\n this._symbolCounts = null;\n /** @type {Array<SlotFacts>|null} What each column's symbols hold, for pruning its tags. */\n this._symbolFacts = null;\n /** @type {Array<any>|null} */\n this._symbolTableMetadata = null;\n this._indexBuffer = null;\n /**\n * How each column's cells find their stored index: the slot maps `_buildSymbolTable` built.\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<{byCell: Map<number|string, number>, byKey: Map<number|string, number>,\n * byObject: Map<object, 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 // Every file-system call below goes through this, so a missing directory, a permission error or\n // a write the disk refuses is a QvdIOError carrying the system code rather than Node's bare error.\n // The close included: a network share can report a write's failure only when the file is closed.\n // `context.file` is the path the caller named even where the call that failed was made on the\n // temporary file, which is the file they asked to write; Node's own message, kept whole, names it.\n const failed = rethrowAsIoError(this._path, 'write');\n const destination = this._destination();\n\n if (destination.replace) {\n await this._replaceFile(destination, headerBuffer, failed);\n } else {\n await this._writeInPlace(destination, headerBuffer, failed);\n }\n\n // Reported once the file is in place rather than once the last byte has been accepted, so a write\n // that then fails to be flushed, closed or renamed has not already said it finished.\n this._emitProgress('write', 1, 1);\n }\n\n /**\n * What is at the destination, and therefore how it is to be written.\n *\n * Decided by one containment check, made now - immediately before anything is opened - and by\n * nothing else: the file that check approved is the file written, in either mode, and what the\n * check found there is what decides how.\n *\n * It used to stat and resolve the path again for itself, after the check. That second resolution\n * was #247 in the atomic write: a destination swapped for a symlink after the check was followed by\n * it, so the temporary file was built beside a file outside allowedDir and renamed over it. A check\n * reports where it went, so nothing here has to go there again.\n *\n * @return {{checked: import('./util/validatePath.js').CheckedPath, path: string,\n * existing: import('fs').BigIntStats|null, replace: boolean, sync: boolean}} The check, the file it\n * approved, what was there, whether to replace it rather than rewrite it, and whether to flush it.\n * @private\n */\n _destination() {\n // The file an open of the path reaches - its canonical path, so a symlink at the destination is\n // followed and kept, the file at its end replaced; or, where nothing exists yet, the name at the far\n // end of any dangling links, which is where an open() of the path would create it. Both write\n // modes use this one answer, so they agree about which file a symlink names.\n const checked = checkPath(this._path, this._allowedDir);\n const existing = checked.stats;\n\n // A destination that exists and is not a regular file is written in place whatever was asked for,\n // and never flushed. Replacing a device or a FIFO would replace the device: a root process writing\n // to /dev/null would leave a QVD where /dev/null was. A directory is refused rather than written:\n // by the open on POSIX, and on Windows - which opens a directory for writing when it is not also\n // asked to empty it - by the first write, before any byte lands. And fsync on something that is not\n // a file is EINVAL, which would fail a write that is otherwise fine.\n const special = existing !== null && !existing.isFile();\n\n // A name nothing is at yet is written by building the file beside it and renaming it there, in\n // either mode. There is nothing to rewrite, so the file that results is the one an in-place write\n // would have made - and a rename replaces the name rather than following anything at it, which an\n // open that creates cannot promise: on Windows even O_EXCL follows a dangling symlink planted at\n // the name, and creates the file wherever it points. So the in-place write is only ever a rewrite\n // of a file that exists, and `openChecked` is only asked to rewrite one it can hold to an identity.\n const replace = (this._atomic || existing === null) && !special;\n\n return {\n checked,\n path: checked.target,\n existing,\n replace,\n sync: this._fsync && !special,\n };\n }\n\n /**\n * Rewrites the destination where it stands - the way every version before 2.0.0 wrote.\n *\n * The file is emptied as the write begins, so from there until the last byte is written there is no\n * previous version left: a failure part-way through leaves a stub that no read of its rows survives,\n * and anything reading the path meanwhile sees however much of the new file has arrived.\n *\n * It is emptied by `openChecked` rather than by opening with `'w'`, and later than `'w'` would: once\n * the descriptor is known to be the file the check approved. `'w'` empties whatever the open reaches,\n * which is what let #247 truncate a file outside allowedDir through a symlink swapped in after the\n * check. The file that results is the same.\n *\n * @param {{checked: import('./util/validatePath.js').CheckedPath, sync: boolean}} destination Where\n * to write, from `_destination`.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _writeInPlace(destination, headerBuffer, failed) {\n // Closed by `closeAfter` rather than in a `finally`, so a close that fails after a write already\n // has cannot replace the write's error - the ENOSPC that explains the failure, not the close's EIO.\n const fd = await openChecked(destination.checked, 'rewrite', failed);\n\n await closeAfter(fd, failed, async () => {\n await this._writeParts(fd, headerBuffer, failed);\n\n if (destination.sync) {\n await fd.sync().catch(failed);\n }\n });\n }\n\n /**\n * Builds the file beside the destination and renames it over it.\n *\n * Nothing touches the destination until the rename, which either replaces it or leaves it as it was,\n * so a write that fails at any step - a full disk, a process killed, an error from the disk itself -\n * costs the temporary file and nothing else. A reader of the path gets the previous file or the new\n * one, never a part of either, which is the other half of what the old behaviour could not promise.\n *\n * @param {{path: string, existing: import('fs').BigIntStats|null, sync: boolean}} destination Where to\n * write, from `_destination`.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _replaceFile(destination, headerBuffer, failed) {\n const temporary = temporaryPathFor(destination.path);\n // 'wx' rather than 'w', so a name that somehow exists already is never written through. A\n // temporary standing in for a file that exists is created private and given that file's\n // permissions once it is whole: Node creates a file 0666 less the umask, which on a usual machine\n // would leave a half-written copy of a 0600 QVD readable by everyone until the chmod below, and\n // longer if its removal fails. A destination that does not exist yet gets the ordinary mode, which\n // is what a write of a new file has always produced.\n const mode = destination.existing === null ? undefined : 0o600;\n const fd = await fs.promises.open(temporary, 'wx', mode).catch(failed);\n\n try {\n await closeAfter(fd, failed, async () => {\n await this._writeParts(fd, headerBuffer, failed);\n\n // The file that appears keeps the permissions of the one it replaces. Through the handle\n // rather than as the open's mode, which the process umask masks. Not on Windows, where the\n // mode is the read-only attribute and nothing else: copying that would leave a temporary file\n // Windows then refuses to rename or to remove.\n if (destination.existing !== null && process.platform !== 'win32') {\n // The check's stats are BigInts - identity needs every bit of a Windows file ID - so the mode\n // is converted before it is masked: a BigInt and a Number do not mix in `&`.\n await fd.chmod(Number(destination.existing.mode) & 0o777).catch(failed);\n }\n\n // Before the rename, not after it, so that what a crash can lose is the replacement and never\n // the contents: the destination is the old file or the new one, whenever the power goes.\n if (destination.sync) {\n await fd.sync().catch(failed);\n }\n });\n\n await renameOver(temporary, destination.path).catch(failed);\n } catch (error) {\n // The destination has not been touched, so the temporary file is all this attempt leaves.\n const removed = await removeTemporary(temporary);\n\n // The removal can be refused too - on Windows while something else still holds the file open.\n // The error on its way out is the one that explains the write, so it is not replaced; the file\n // left behind is named in its context instead, which is the only way a caller could learn of it.\n //\n // Only where that context will take it. A module is strict code, so assigning to a frozen or\n // sealed object throws, and an error about the tidying up would then replace the ENOSPC that\n // explains the write - which is the whole point of `closeAfter`, undone at the last step. No\n // error reaching here carries a frozen context today; this is so that none ever can.\n const context = /** @type {{context?: Record<string, unknown>}} */ (error)?.context;\n if (!removed && context !== null && typeof context === 'object' && Object.isExtensible(context)) {\n context.temporaryFile = temporary;\n }\n\n throw error;\n }\n }\n\n /**\n * Writes the three parts of a QVD, in their order, into an open file.\n *\n * @param {import('fs/promises').FileHandle} fd The open file.\n * @param {Buffer} headerBuffer The header and its terminator.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler.\n * @private\n */\n async _writeParts(fd, headerBuffer, failed) {\n await this._writeRange(fd, headerBuffer, 0, failed);\n await this._writeRange(fd, this._symbolBuffer, headerBuffer.length, failed);\n await this._writeRange(fd, this._indexBuffer, headerBuffer.length + this._symbolBuffer.length, failed);\n }\n\n /**\n * Writes the whole of one buffer into the file, starting at `filePosition`.\n *\n * A write can resolve having written less than it was given, and that is all a disk that fills\n * part-way through one says. libuv retries a short write(2) itself, and when the retry fails it\n * returns the bytes that did land instead of the error - `uv__fs_write_all` in its `src/unix/fs.c`,\n * and `fs__write` on Windows does the same - so Node resolves with a short `bytesWritten` and never\n * rejects. Taking that for the whole write is how `toQvd()` resolved on a full disk and left a\n * truncated file: the index table, the last of the three writes, stopped part-way, and no later call\n * asked the disk again.\n *\n * So the rest is written until there is none, and it is the next call that reports the failure: the\n * disk refuses it outright, and that rejection is a QvdIOError with the system's code, ENOSPC, like\n * any other refused write. A write that stores nothing and reports nothing would repeat forever, so\n * it is a failure too, the one QvdIOError with no system code to carry.\n *\n * In bounded chunks as well, because Node refuses a single write of 2 GiB or more.\n *\n * @param {import('fs/promises').FileHandle} fd The open file.\n * @param {Buffer} buffer What to write.\n * @param {number} filePosition Where in the file it starts.\n * @param {(error: unknown) => never} failed The write's `rethrowAsIoError` handler, which every call\n * goes through.\n * @private\n */\n async _writeRange(fd, buffer, filePosition, failed) {\n let done = 0;\n\n while (done < buffer.length) {\n const length = Math.min(WRITE_CHUNK_SIZE, buffer.length - done);\n const {bytesWritten} = await fd.write(buffer, done, length, filePosition + done).catch(failed);\n\n // Not `=== 0`: a count that is not a positive number - from a patched `fs`, say - would make\n // `done` NaN and end the loop as though the part were written, which is this bug over again.\n if (!(bytesWritten > 0)) {\n throw new QvdIOError(\n `Could not write the QVD file: nothing was written at byte ${filePosition + done}, ` +\n 'and the operating system reported no error.',\n {file: this._path, operation: 'write', filePosition: filePosition + done},\n );\n }\n\n done += bytesWritten;\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._symbolCounts?.[index],\n Offset: this._symbolTableMetadata?.[index][0],\n Length: this._symbolTableMetadata?.[index][1],\n Comment: existingField?.Comment || '',\n NumberFormat: resetContradictedNumberFormat(existingField?.NumberFormat, this._symbolFacts?.[index]),\n Tags: pruneContradictedTags(existingField?.Tags, this._symbolFacts?.[index]),\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 // Every text the builder is about to write, so a character XML cannot hold is refused naming the\n // property it is in. The field names were checked before the rows were.\n const {Fields, ...table} = xmlObject.QvdTableHeader;\n\n for (const [property, value] of Object.entries(table)) {\n checkHeaderTexts(value, property, 'the table', {file: this._path, stage: 'buildHeader'});\n }\n\n for (const {FieldName, ...field} of Fields.QvdFieldHeader) {\n for (const [property, value] of Object.entries(field)) {\n checkHeaderTexts(value, property, `field '${FieldName}'`, {\n column: FieldName,\n file: this._path,\n stage: 'buildHeader',\n });\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 * One pass over the rows finds each column's distinct values in the order they first appear,\n * which is the order Qlik lists symbols in, and checks each distinct value once. A second pass per\n * column encodes them: every symbol is sized first, then written into one buffer of exactly that\n * size.\n *\n * What each value is stored as:\n *\n * | Cell | Symbol |\n * | --- | --- |\n * | `null`, `undefined`, a hole, a missing cell | none - the field's `Bias` records NULL |\n * | an integer from -2147483648 to 2147483647, -0 included | pure int, type 1 |\n * | any other finite number | pure double, type 2 |\n * | a string | pure string, type 4 |\n * | a dual - a `QvdDual`, or an object whose only keys are `number` and `text` | dual int or dual double, type 5 or 6, by the number |\n * | a number or a string the frame's `storedSymbols` records | the symbol it was read from |\n *\n * A number is a pure number, with no text. It used to be written as a dual whose text was\n * `String(value)`, which was wrong twice over: it invented text the caller never supplied, and a\n * file Qlik wrote with pure numbers came back out of a read and a write with every one of them\n * turned into a dual. The kind follows `isStoredAsInt`, which is the rule Qlik's own files follow.\n * A string is never parsed, so `'7'` and `7` in one column are two symbols. It is stored as its\n * UTF-8 bytes, or refused where those bytes would not give it back: a NUL ends a stored text, and\n * an unpaired surrogate has no UTF-8 encoding at all.\n *\n * A column holds one symbol per number, as a Qlik field does. Several duals with one number are one\n * symbol with the first text in row order, and a plain number with the same number as a dual joins\n * the dual, in either order - so no text a caller supplied is lost to a plain number that came\n * first. A string is not a number, so a string equal to a dual's text is a symbol of its own.\n *\n * A frame read from a file shows one half of some symbols: a dual read as its number or its text, a\n * string read as a number. Its record says what each such cell stands for, so the frame writes back\n * the symbols it was read from - the dual's text, Qlik's exact double, the string `'007'` - whichever\n * rows the cells were moved to. A cell the record maps to more than one stored value is refused.\n *\n * The complexity claim is the one to trust here: O(rows x columns) for the pass, and O(symbols)\n * for the encoding. The \"80-90% improvement\" this comment once carried is not reproducible in this\n * repository; `benchmarks/` measures what the writer costs now, which is the useful number.\n *\n * @private\n */\n _buildSymbolTable() {\n this._symbolCounts = [];\n this._symbolFacts = [];\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 validateColumnNames(columns, this._path);\n\n // Through the same check a frame's constructor applies, which costs nothing for a record that came\n // from a read or was already checked, and refuses a malformed one handed to the writer directly.\n const record = normaliseStoredSymbols(this._df.storedSymbols);\n\n this._emitProgress('symbol-table', 0, numColumns);\n\n // Per column, the slots in first-appearance order and the maps that find them - see\n // ColumnSymbols. A Map compares keys by SameValueZero, so a number is one symbol however many rows\n // hold it, and 0 and -0 in one column are one symbol - which isStoredAsInt stores as the integer 0\n // either way.\n //\n // No third structure: this used to be a Set per column, then `Array.from` on it, then a Map built\n // from the array, three structures each holding a reference to every distinct value. On a column\n // whose values are all distinct that was roughly 30MB of duplication per million rows.\n /** @type {Array<ColumnSymbols>} */\n const state = columns.map((/** @type {string} */ name) => {\n const entry = record === null ? null : (record.find((candidate) => candidate.field === name) ?? null);\n /** @type {Map<number|string, number>} */\n const byKey = new Map();\n /** @type {Map<number|string, number|Array<number>>|null} */\n let byValue = null;\n /** @type {Map<number|string, string>|null} */\n let textByNumber = null;\n\n if (entry !== null && valuesAreNumbers(entry)) {\n textByNumber = firstTextByValue(entry);\n } else if (entry !== null) {\n byValue = new Map();\n\n // An index per value, and an array only for a value two entries share, which a record read from\n // a Qlik file never has: a field of distinct duals costs a map entry per value, not an array.\n for (let index = 0; index < entry.values.length; index++) {\n const found = byValue.get(entry.values[index]);\n\n if (found === undefined) {\n byValue.set(entry.values[index], index);\n } else if (typeof found === 'number') {\n byValue.set(entry.values[index], [found, index]);\n } else {\n found.push(index);\n }\n }\n }\n\n return {\n name,\n keys: [],\n texts: [],\n byKey,\n // A cell is its own key without a record entry, and with one whose values are their numbers, so\n // one Map serves both. On a field of distinct duals that is a map entry per symbol fewer.\n byCell: entry === null || textByNumber !== null ? byKey : new Map(),\n byObject: new Map(),\n entry,\n textByNumber,\n byValue,\n facts: {hasNumber: false, hasNonNumber: false, hasFraction: false},\n };\n });\n\n // Hoisted out of the column objects, so the row loop's common case - a value the column has seen\n // - is an array read and a Map lookup, as it was before the column had anything else to keep.\n const byCells = state.map((column) => column.byCell);\n const byObjects = state.map((column) => column.byObject);\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 // A missing row is a row of NULLs, which is what a hole in a sparse array already means.\n // A row that is present but is not an array is different: `values?.[column]` reads\n // `undefined` from it for every column, so `{columns: ['a'], data: [1, 2]}` used to write a\n // two-row file of NULLs and report success, discarding everything the caller passed.\n if (values !== null && values !== undefined && !Array.isArray(values)) {\n throw new QvdValidationError('Each row must be an array of values', {\n row,\n type: typeof values,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n // A short row is padded with NULLs, deliberately. A long one is not truncated, because\n // dropping the extra cells silently is how a caller whose columns and data have drifted\n // apart gets a plausible file with a column missing.\n if (values !== null && values !== undefined && values.length > numColumns) {\n throw new QvdValidationError(`Row ${row} has ${values.length} values but there are ${numColumns} fields`, {\n row,\n values: values.length,\n fields: numColumns,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\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 // A dual object is looked up by identity in its own map, so the primitive map is never asked\n // about an object it cannot hold.\n if (typeof value === 'object') {\n if (!byObjects[column].has(value)) {\n slotForObject(state[column], value, row, this._path);\n }\n\n continue;\n }\n\n // A primitive the column has already seen costs this one lookup, as it did before duals.\n if (byCells[column].has(value)) {\n continue;\n }\n\n // Once per distinct value, not once per row: a repeat has already been through this. The\n // problem functions allocate nothing for a good value, so the context object is only built\n // for a value that is about to be refused.\n if (typeof value === 'number') {\n if (numberProblem(value) !== null) {\n checkNumber(value, null, {column: columns[column], row, file: this._path, stage: 'buildSymbolTable'});\n }\n } else if (typeof value === 'string') {\n if (textProblem(value) !== null) {\n checkText(value, 'A string value', {\n column: columns[column],\n row,\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n } else {\n refuseCell(value, columns[column], row, this._path);\n }\n\n byCells[column].set(value, slotForCell(state[column], value, row, this._path));\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 {keys, texts} = state[column];\n const kinds = new Uint8Array(keys.length);\n let byteLength = 0;\n\n for (let slot = 0; slot < keys.length; slot++) {\n const key = keys[slot];\n const text = texts[slot];\n\n if (typeof key === 'number') {\n // Both halves were checked when the cell was, or when the record was; this is the last look\n // before the bytes are written. A record a read built is taken as the file stored it, so a\n // damaged file's NaN dual read as its text reaches a slot only through the record - and is\n // refused here as the NaN cell it stands for would have been.\n if (numberProblem(key) !== null) {\n checkNumber(key, null, {column: columns[column], file: this._path, stage: 'buildSymbolTable'});\n }\n\n if (text !== null && textProblem(text) !== null) {\n checkText(text, 'The text of a dual value', {\n column: columns[column],\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n kinds[slot] = kindOf(key, text);\n byteLength += symbolByteLength(kinds[slot], key, text);\n } else {\n kinds[slot] = kindOf(null, key);\n byteLength += symbolByteLength(kinds[slot], null, key);\n }\n }\n\n // allocUnsafe, because every byte is about to be written. The assertion below holds it to that:\n // a byte left unwritten would carry whatever memory the buffer was given into the file.\n const columnBuffer = Buffer.allocUnsafe(byteLength);\n let offset = 0;\n\n for (let slot = 0; slot < keys.length; slot++) {\n const key = keys[slot];\n\n offset =\n typeof key === 'number'\n ? writeSymbol(columnBuffer, offset, kinds[slot], key, texts[slot])\n : writeSymbol(columnBuffer, offset, kinds[slot], null, key);\n }\n\n assert(offset === byteLength, 'A column was encoded into a different number of bytes than it was sized for.');\n\n columnBuffers.push(columnBuffer);\n this._symbolTableMetadata?.push([symbolsOffset, byteLength, containsNull[column]]);\n this._symbolCounts?.push(keys.length);\n this._symbolFacts?.push(state[column].facts);\n this._symbolIndexByValue?.push({\n byCell: state[column].byCell,\n byKey: state[column].byKey,\n byObject: state[column].byObject,\n });\n\n symbolsOffset += byteLength;\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._symbolCounts, '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._symbolCounts[column];\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 these maps, so validating the\n // maps 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 const lookup = this._symbolIndexByValue[column];\n const maps = lookup.byCell === lookup.byKey ? [lookup.byKey, lookup.byObject] : Object.values(lookup);\n\n for (const map of maps) {\n for (const index of map.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\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 // Hoisted, as in the symbol table pass, so a cell costs one array read and one lookup.\n const byCells = this._symbolIndexByValue.map((lookup) => lookup.byCell);\n const byKeys = this._symbolIndexByValue.map((lookup) => lookup.byKey);\n const byObjects = this._symbolIndexByValue.map((lookup) => lookup.byObject);\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 // A dual object is remembered by identity up to a bound, and past it found by its number, which\n // the symbol table pass has already checked for this same object.\n const index =\n typeof value === 'object'\n ? (byObjects[column].get(value) ?? byKeys[column].get(value.number))\n : byCells[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 * 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: ${formatCount(recommendedValue)} rows or less).`;\n } else {\n advice = `Try holding fewer rows using the ${knob} parameter (recommended: ${formatCount(recommendedValue)} 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 * Formats a row count for a human reading a diagnostic.\n *\n * Pinned to `en-US` rather than left to `toLocaleString()`'s default, which follows the host's\n * locale. The messages here are English prose, so a number grouped by the machine's convention was\n * inconsistent with the sentence around it - and worse, it made the same message differ between\n * platforms: `9,999,999` on the Linux and macOS runners against `9 999 999` on the Windows ones,\n * where the separator is a narrow no-break space. That is invisible until something matches on the\n * text. A test of this module's warning did, and passed everywhere it was run before failing all\n * three Windows legs in CI.\n *\n * The same property matters outside tests: a diagnostic that reads the same on every platform is\n * one a caller can grep for in a log aggregator collecting from all three.\n *\n * @param {number} value The count.\n * @return {string} The count, grouped the same way everywhere.\n */\nfunction formatCount(value) {\n return value.toLocaleString('en-US');\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 ${formatCount(rowsToLoad)} of ${formatCount(totalRows)} 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 {QvdCorruptedError, QvdParseError} from '../QvdErrors.js';\n\n/**\n * The longest text one symbol may hold. A damaged file cannot then make the reader decode a string the\n * size of the whole symbol table.\n */\nconst MAX_TEXT_BYTES = 1048576;\n\n/**\n * One field's symbols, as the two halves each can have, decoded straight from the symbol table's bytes.\n *\n * A pure number has a number and no text, a pure string a text and no number, and a dual both. A symbol\n * the two-pass path did not need has neither: nothing was decoded for it, and every symbol a file holds\n * has at least one half, so null in both cannot be mistaken for a value.\n *\n * Two arrays per field rather than an object per symbol. The reader resolves what each symbol reads as\n * from these, once, and nothing else keeps them; a high-cardinality field used to allocate a symbol\n * object, a result object and two typed arrays for every numeric value it held.\n *\n * A read reports what the file holds, unchecked: a damaged file's NaN double reads as NaN, and it is the\n * writer that refuses to store it again.\n *\n * @typedef {Object} FieldSymbols\n * @property {Array<number|null>} numbers Each symbol's number: an int's, a double's or a dual's.\n * @property {Array<string|null>} texts Each symbol's text: a string's or a dual's.\n */\n\n/**\n * Where the text starting at `from` ends: the index of its NUL terminator.\n *\n * @param {Buffer} symbolBuffer The symbol table.\n * @param {number} from The first byte of the text.\n * @param {string} kind 'String symbol' or 'Dual string symbol', for the error.\n * @param {string} fieldName The field, for the error.\n * @param {string} filePath The file, for the error.\n * @return {number} The index of the terminator.\n * @throws {QvdCorruptedError} If the text runs past the longest a symbol may hold, or has no terminator.\n */\nfunction textEnd(symbolBuffer, from, kind, fieldName, filePath) {\n const bufferLength = symbolBuffer.length;\n const found = symbolBuffer.indexOf(0, from);\n\n if ((found === -1 ? bufferLength : found) - from > MAX_TEXT_BYTES) {\n throw new QvdCorruptedError(`${kind} exceeds maximum length`, {\n field: fieldName,\n maxLength: MAX_TEXT_BYTES,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n if (found === -1) {\n throw new QvdCorruptedError(`${kind} not null-terminated`, {\n field: fieldName,\n pointer: bufferLength,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return found;\n}\n\n/**\n * Refuses a number that would be read past the end of the symbol table.\n *\n * @param {string} message What was being read.\n * @param {number} pointer The first byte of the number.\n * @param {number} bufferLength The symbol table's length.\n * @param {string} fieldName The field, for the error.\n * @param {string} filePath The file, for the error.\n * @return {never}\n * @throws {QvdCorruptedError} Always.\n */\nfunction overflow(message, pointer, bufferLength, fieldName, filePath) {\n throw new QvdCorruptedError(message, {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n}\n\n/**\n * Decodes one field's symbols from the symbol table.\n *\n * Each symbol is a type byte - 1 int, 2 double, 4 string, 5 dual int, 6 dual double - then a 4-byte\n * int or 8-byte double, then a NUL-terminated UTF-8 text, as the type says. A symbol outside `keep` is\n * walked past without decoding, but its length still has to be found, and a text's terminator is\n * checked either way.\n *\n * @param {Buffer} symbolBuffer The whole symbol table.\n * @param {number} start The field's first byte in it.\n * @param {number} end The byte after the field's last.\n * @param {Set<number>|null} keep The symbols to decode, by index, or null for all of them.\n * @param {string} fieldName The field, for errors.\n * @param {string} filePath The file, for errors.\n * @return {FieldSymbols} The field's symbols.\n * @throws {QvdCorruptedError} If a symbol runs past the end of the symbol table.\n * @throws {QvdParseError} If a type byte is not one of the five.\n */\nexport function parseFieldSymbols(symbolBuffer, start, end, keep, fieldName, filePath) {\n const bufferLength = symbolBuffer.length;\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n let pointer = start;\n\n while (pointer < end) {\n const typeByte = symbolBuffer[pointer++];\n const decode = keep === null || keep.has(numbers.length);\n let number = null;\n let text = null;\n\n switch (typeByte) {\n case 1: {\n if (decode) {\n if (pointer + 4 > bufferLength) {\n overflow('Buffer overflow reading integer symbol', pointer, bufferLength, fieldName, filePath);\n }\n number = symbolBuffer.readInt32LE(pointer);\n }\n pointer += 4;\n break;\n }\n case 2: {\n if (decode) {\n if (pointer + 8 > bufferLength) {\n overflow('Buffer overflow reading double symbol', pointer, bufferLength, fieldName, filePath);\n }\n number = symbolBuffer.readDoubleLE(pointer);\n }\n pointer += 8;\n break;\n }\n case 4: {\n const terminator = textEnd(symbolBuffer, pointer, 'String symbol', fieldName, filePath);\n if (decode) {\n text = symbolBuffer.toString('utf8', pointer, terminator);\n }\n pointer = terminator + 1;\n break;\n }\n case 5:\n case 6: {\n const numberBytes = typeByte === 5 ? 4 : 8;\n if (pointer + numberBytes > bufferLength) {\n const read = !decode ? 'dual symbol' : typeByte === 5 ? 'dual integer symbol' : 'dual double symbol';\n overflow(`Buffer overflow reading ${read}`, pointer, bufferLength, fieldName, filePath);\n }\n\n const terminator = textEnd(symbolBuffer, pointer + numberBytes, 'Dual string symbol', fieldName, filePath);\n if (decode) {\n number = typeByte === 5 ? symbolBuffer.readInt32LE(pointer) : symbolBuffer.readDoubleLE(pointer);\n text = symbolBuffer.toString('utf8', pointer + numberBytes, terminator);\n }\n pointer = terminator + 1;\n break;\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 numbers.push(number);\n texts.push(text);\n }\n\n return {numbers, texts};\n}\n","// @ts-check\n\nimport {dualFromSymbol} from '../QvdDual.js';\nimport {isNumericText} from './cellRules.js';\n\n/**\n * @typedef {import('./storedSymbols.js').StoredSymbolsEntry} StoredSymbolsEntry\n */\n\n/**\n * Both halves of each symbol of a field, aligned with its symbols: the text, or null for a pure\n * number, and the number, or null for a pure string.\n *\n * What a columnar read keeps for a field whose cells do not show every half, so a column can answer\n * `textAt` and give a date read as text its serial.\n *\n * @typedef {Object} SymbolHalves\n * @property {ReadonlyArray<string|null>} texts Each symbol's text.\n * @property {ReadonlyArray<number|null>} numbers Each symbol's number.\n */\n\n/**\n * What one field's symbols read as, and what has to be kept so they write back as the same symbols.\n *\n * Runs once per symbol, not once per cell: every row holding a symbol shares the value resolved here.\n *\n * A symbol reads as follows, the representation depending only on its type and the options - never on\n * the other symbols of the field, and never on the window:\n *\n * | Symbol | `'number'` (default) | `'text'` | `'both'` |\n * | --- | --- | --- | --- |\n * | int, double | the number | the number | the number |\n * | string | the string | the string | the string |\n * | string, numeric text, `coerce` on | `Number(text)` | `Number(text)` | `Number(text)` |\n * | dual | its number | its text | a frozen `QvdDual` |\n * | dual, numeric text, `coerce` on | its number | its number | a frozen `QvdDual` |\n * | NULL | null | null | null |\n *\n * A numeric text is one `isNumericText` accepts. `coerce` reaches only a cell that would otherwise be a\n * string: a string symbol in every mode, and a dual under `'text'`. A dual's numeric text reads as the\n * number Qlik *stored*, not as `Number(text)`, so a dual's number is the same in every mode that shows it.\n * The two need not be close. A text that spells the number can still parse to the double beside it -\n * Qlik stores 1.1400000000000001 for `1.14` - and a text that shows it rounded, or shows another value\n * such as a date as `20160113`, parses to a different number altogether.\n *\n * Wherever a cell shows only one half, the symbol is recorded, keyed by the value the cell holds, in\n * symbol order - which for a Qlik file is the order values first appear. That is pass A. Pass B runs\n * only for a field in which pass A recorded something and which also holds pure symbols: a pure\n * symbol that reads as a value already recorded is recorded too, so the writer can see that the value\n * stands for two different symbols and refuse it, rather than silently writing both as one. A Qlik\n * file keeps one symbol per value in a field, so for one pass B finds nothing to add.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols, both halves null where\n * the two-pass path did not decode one.\n * @param {string} field The field name, for the record.\n * @param {'number'|'text'|'both'} mode The `duals` option.\n * @param {boolean} coerce Whether a numeric text reads as a number.\n * @param {boolean} wantHalves Whether to return both halves of every symbol, for a columnar read.\n * @return {{values: Array<any>, entry: StoredSymbolsEntry|null, halves: SymbolHalves|null}} The value of\n * each symbol - undefined where it was filtered out - the field's record entry, or null when every\n * cell shows its whole symbol, and the halves when asked for and the field has a symbol whose cell\n * does not show both.\n */\nexport function resolveFieldSymbols(symbols, field, mode, coerce, wantHalves) {\n const length = symbols.numbers.length;\n const values = new Array(length);\n\n // Pass A's entries, in symbol order. Pushed as they are found rather than marked and collected,\n // because a field read from a Qlik file never needs pass B to add anything.\n /** @type {Array<number|string>} */\n const entryValues = [];\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n let pure = 0;\n let partial = false;\n\n for (let index = 0; index < length; index++) {\n const text = symbols.texts[index];\n const number = symbols.numbers[index];\n\n if (text === null) {\n // Neither half: a symbol the two-pass path did not decode, which no row of the window uses.\n values[index] = number === null ? undefined : number;\n if (number !== null) pure++;\n continue;\n }\n\n if (number === null) {\n if (coerce && isNumericText(text)) {\n values[index] = Number(text);\n entryValues.push(values[index]);\n numbers.push(null);\n texts.push(text);\n partial = true;\n } else {\n values[index] = text;\n pure++;\n }\n\n continue;\n }\n\n partial = true;\n\n if (mode === 'both') {\n // One frozen QvdDual per symbol, shared by every row holding it. Only this mode builds one; the\n // parser never does.\n values[index] = dualFromSymbol(number, text);\n continue;\n }\n\n values[index] = mode === 'number' || (coerce && isNumericText(text)) ? number : text;\n entryValues.push(values[index]);\n numbers.push(number);\n texts.push(text);\n }\n\n /** @type {StoredSymbolsEntry|null} */\n let entry = null;\n\n if (entryValues.length > 0) {\n entry =\n pure > 0 && collides(symbols, values, new Set(entryValues))\n ? collisionEntry(symbols, field, values, mode)\n : Object.freeze({\n field,\n values: Object.freeze(entryValues),\n numbers: Object.freeze(numbers),\n texts: Object.freeze(texts),\n });\n }\n\n return {values, entry, halves: wantHalves && partial ? symbolHalves(symbols) : null};\n}\n\n/**\n * Whether a pure symbol reads as a value pass A recorded - pass B's question.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {Array<any>} values What each symbol reads as.\n * @param {Set<any>} recorded The values pass A recorded. A Set compares by SameValueZero, the same\n * equality the writer's Map uses to look a cell up.\n * @return {boolean} True when one does.\n */\nfunction collides(symbols, values, recorded) {\n for (let index = 0; index < values.length; index++) {\n if (!isPure(symbols, index, values[index])) {\n continue;\n }\n\n if (recorded.has(values[index])) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether a symbol's cell shows the whole symbol: a pure number, or a pure string read as itself.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {number} index The symbol.\n * @param {any} value What it reads as.\n * @return {boolean} True for a pure symbol pass A did not record; false for one never decoded.\n */\nfunction isPure(symbols, index, value) {\n const text = symbols.texts[index];\n const number = symbols.numbers[index];\n\n return text === null ? number !== null : number === null && value === text;\n}\n\n/**\n * A field's record entry when pass B has something to add: pass A's symbols, and every pure symbol\n * that reads as one of their values, all in symbol order.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @param {string} field The field name.\n * @param {Array<any>} values What each symbol reads as.\n * @param {'number'|'text'|'both'} mode The `duals` option.\n * @return {StoredSymbolsEntry} The frozen entry.\n */\nfunction collisionEntry(symbols, field, values, mode) {\n const recorded = new Set();\n /** @type {Array<boolean>} */\n const inPassA = values.map((value, index) => {\n if ((symbols.numbers[index] === null && symbols.texts[index] === null) || isPure(symbols, index, value)) {\n return false;\n }\n\n // A dual read as a half, or a string coerced to a number. A 'both' dual is its own QvdDual cell.\n const recordedHere = !(mode === 'both' && symbols.texts[index] !== null && symbols.numbers[index] !== null);\n\n if (recordedHere) {\n recorded.add(values[index]);\n }\n\n return recordedHere;\n });\n\n /** @type {Array<number|string>} */\n const entryValues = [];\n /** @type {Array<number|null>} */\n const numbers = [];\n /** @type {Array<string|null>} */\n const texts = [];\n\n for (let index = 0; index < values.length; index++) {\n if (inPassA[index] || (isPure(symbols, index, values[index]) && recorded.has(values[index]))) {\n entryValues.push(values[index]);\n numbers.push(symbols.numbers[index]);\n texts.push(symbols.texts[index]);\n }\n }\n\n return Object.freeze({\n field,\n values: Object.freeze(entryValues),\n numbers: Object.freeze(numbers),\n texts: Object.freeze(texts),\n });\n}\n\n/**\n * Both halves of every symbol of a field: the decoded arrays themselves, frozen, since nothing else\n * holds them once the read resolves.\n *\n * @param {import('./symbolParser.js').FieldSymbols} symbols The field's symbols.\n * @return {SymbolHalves} The halves, null for a filtered-out symbol.\n */\nfunction symbolHalves(symbols) {\n return Object.freeze({texts: Object.freeze(symbols.texts), numbers: Object.freeze(symbols.numbers)});\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {asDual} from './util/cellRules.js';\nimport {readerOptionsFrom, windowFrom} from './util/readOptions.js';\n\n/**\n * @typedef {import('./util/resolveSymbols.js').SymbolHalves} SymbolHalves\n */\n\n/**\n * The number a symbol's value stands for, or NaN.\n *\n * A number is itself and a dual is its number. A string is NaN, unless the read kept its halves and\n * the symbol has a number - a dual read as its text, such as a date read with `{duals: 'text'}`, whose\n * serial is still the value Qlik sums and compares by.\n *\n * @param {any} value The symbol's value.\n * @param {number|null} number The symbol's stored number, from its halves, or null.\n * @return {number} The number.\n */\nfunction numberOf(value, number) {\n if (typeof value === 'number') {\n return value;\n }\n\n if (typeof value === 'string') {\n return number ?? NaN;\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.number === 'number' ? dual.number : NaN;\n}\n\n/**\n * The text a symbol's value stands for, derived from the value alone.\n *\n * @param {any} value The symbol's value.\n * @return {string|null} A string itself, a dual's text, or null.\n */\nfunction textOf(value) {\n if (typeof value === 'string') {\n return value;\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.text === 'string' ? dual.text : null;\n}\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\n * `chicago_taxi_rides_2016_01` fixture, read with the default options, **exactly one of its 20\n * columns is strictly numeric** - `trip_start_timestamp`, whose timestamps read as numbers - and\n * two are 100% strings: `pickup_census_tract`, every cell of it blank, and `payment_type`.\n * `dropoff_census_tract` is 43.3% empty strings, and a `Float64Array` of values would put NaN in\n * all of those rows 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 * @param {SymbolHalves|null} [halves=null] Both halves of each symbol, aligned with `symbols`, for a\n * field whose values do not show them all - a dual read as one half, a string read as a number.\n * Without them, the halves are derived from the values: a string is its own text, a dual has its\n * own, and a number has none.\n */\n constructor(name, codes, symbols, halves = null) {\n this._name = name;\n this._codes = codes;\n this._symbols = symbols;\n this._halves = halves;\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 * A windowed read that filters the symbol table decodes only the symbols its rows use. Every other\n * entry is `undefined` - not `null`, which a QVD never stores as a symbol - and no code refers to it.\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 * The text of one row: the text Qlik displays for its value.\n *\n * A string is its own text and a dual has its own. A value read as one half of a symbol - a date\n * read as its serial, a string read as a number - has the text the file stores for it, and a pure\n * number has none.\n *\n * @param {number} row The row index.\n * @return {string|null} The text, or null for NULL and for a number with no text.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n textAt(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 if (code < 0) {\n return null;\n }\n\n return this._halves !== null ? (this._halves.texts[code] ?? null) : textOf(this._symbols[code]);\n }\n\n /**\n * The text of each distinct value, indexed by the codes, as `textAt` gives it per row.\n *\n * @return {ReadonlyArray<string|null>} One text per symbol, null where a symbol has none.\n */\n symbolTexts() {\n if (this._halves !== null) {\n return this._halves.texts;\n }\n\n return Object.freeze(this._symbols.map(textOf));\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 * A dual is its number, however it was read: a `QvdDual` gives `.number`, and a date read with\n * `{duals: 'text'}` gives the serial the file stores for it, not NaN.\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 out[index] = numberOf(this._symbols[index], this._halves?.numbers[index] ?? null);\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. A dual is a\n * number here, as it is to `numericSymbols`.\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 // A dual's number, from the value or from the halves the read kept. NULL has neither.\n const number = value === null ? NaN : numberOf(value, this._halves?.numbers[code] ?? null);\n\n if (!Number.isNaN(number)) {\n out[row] = number;\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 + arrayBuffers` either side of a forced collection with each read in a\n * process of its own - `benchmarks/capture-baseline.js`, on 1.0.1:\n *\n * | | retained | of it on the V8 heap | bytes/cell |\n * | --- | --- | --- | --- |\n * | `QvdDataFrame.fromQvd()` | 352 MiB | 352 MiB | 10.83 |\n * | `QvdColumnTable.fromQvd()` | 133 MiB | 3 MiB | 4.08 |\n *\n * Nearly all of a columnar read is its codes, an `Int32Array` per field, whose storage lives\n * outside the V8 heap - which is why the heap alone once put it at a fraction of this.\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 {Array<SymbolHalves|null>} [decoded.halvesByField] Both halves of each symbol, per field,\n * or null for a field whose values show them.\n * @param {number} decoded.rowCount Rows decoded.\n * @param {any} decoded.metadata The raw QvdTableHeader.\n * @param {import('./util/storedSymbols.js').StoredSymbols|null} [decoded.storedSymbols] The\n * stored-symbol record, as a data frame of the same read carries it.\n * @param {any} decoded.loadStats Statistics about the read.\n */\n constructor({columns, codesByField, symbolsByField, halvesByField, rowCount, metadata, storedSymbols, loadStats}) {\n this._columns = columns;\n this._codesByField = codesByField;\n this._symbolsByField = symbolsByField;\n this._halvesByField = halvesByField ?? null;\n this._rowCount = rowCount;\n this._metadata = metadata;\n this._storedSymbols = storedSymbols ?? null;\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 {'number'|'text'|'both'} [options.duals='number'] What a dual symbol's value is: its\n * number, its text, or a frozen `QvdDual` holding both. Whichever it is, `column.textAt` gives the\n * text and `numericSymbols` the number. Anything else throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a value that would be a string is a\n * number when its text is not blank and `Number(text)` is finite - a string symbol as\n * `Number(text)`, a dual read as text as its stored number. `column.textAt` still gives the text.\n * Anything but a boolean throws.\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 * The stored-symbol record of the read, as `QvdDataFrame.storedSymbols` describes it.\n *\n * @return {import('./util/storedSymbols.js').StoredSymbols|null} The record, or null.\n */\n get storedSymbols() {\n return this._storedSymbols;\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(\n name,\n this._codesByField[index],\n this._symbolsByField[index],\n this._halvesByField?.[index] ?? null,\n );\n }\n}\n","// @ts-check\n\nimport xml from 'xml2js';\n// Node's assert, used only for invariants a bug in this library would violate - \"this private\n// method ran after the one that fills the field it reads\". Never for input: everything a caller\n// can get wrong throws a QvdError with a context object instead.\n//\n// #143 read the old Copilot instruction \"use assertions for validation\" as an explanation for\n// these calls. It is not: every one sits after a method that either assigns the field\n// unconditionally or throws, and 3,570 corruption cases across every bundled fixture and every\n// entry point produced no AssertionError. They are checked, and they stay.\nimport assert from 'assert';\nimport {QvdDataFrame} from './QvdDataFrame.js';\nimport {QvdParseError, QvdValidationError, QvdCorruptedError} from './QvdErrors.js';\nimport {checkPath} from './util/validatePath.js';\nimport {openChecked} from './util/openChecked.js';\nimport {closeAfter, rethrowAsIoError} from './util/ioErrors.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 {parseFieldSymbols} from './util/symbolParser.js';\nimport {\n normaliseCoerceNumericStrings,\n normaliseDuals,\n normaliseWindow,\n resolveWindow,\n selectFields,\n} from './util/readOptions.js';\nimport {resolveFieldSymbols} from './util/resolveSymbols.js';\nimport {attachStoredSymbols, trustStoredSymbols} from './util/storedSymbols.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 * Reads a file from its start, a chunk at a time, through a handle already open.\n *\n * The header used to be scanned with `fs.createReadStream(path)`, which opened the file a second time\n * by name - and the body was read by a third open, of the same name. Each was another resolution of\n * a path that can change between them: #247 was a symlink swapped in after the containment check, and\n * every one of those opens followed it. Reading the header through the one handle the read holds keeps\n * the header, the symbol table and the index table in the same file, and that file the one the check\n * approved.\n *\n * Positional reads, so the handle's own file position never moves and a later `readFile()` on it\n * still starts at the beginning. A read can return fewer bytes than it was asked for, and the chunk\n * is then shorter; nothing downstream assumes a size.\n *\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {number} chunkSize The most to read at a time.\n * @param {(error: unknown) => never} failed The read's `rethrowAsIoError` handler.\n * @yield {Buffer} The file's bytes, in order, until its end.\n */\nasync function* chunksFrom(handle, chunkSize, failed) {\n let position = 0;\n\n for (;;) {\n const buffer = Buffer.alloc(chunkSize);\n const {bytesRead} = await handle.read(buffer, 0, chunkSize, position).catch(failed);\n\n if (bytesRead === 0) {\n return;\n }\n\n // What arrived, copied when it is short, so a short last chunk does not pin a whole chunk's buffer.\n yield bytesRead === chunkSize ? buffer : Buffer.from(buffer.subarray(0, bytesRead));\n position += bytesRead;\n }\n}\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 {'number'|'text'|'both'} [options.duals='number'] What a dual symbol - a number with the\n * text Qlik displays for it, such as a date - reads as. `'number'` gives its number, which is the\n * value Qlik sums, sorts and compares by; `'text'` gives its text; `'both'` gives a frozen\n * `QvdDual` holding both halves, shared by every row that holds the symbol. Under `'number'` and\n * `'text'` the half a cell does not show is kept in the frame's `storedSymbols`, so a write stores\n * the dual again. An int, a double, a string and NULL read the same in every mode. Any other value\n * throws a `QvdValidationError`.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite: a string symbol in\n * every `duals` mode, as `Number(text)`, and a dual's text under `duals: 'text'`, as the number the\n * dual stores. The text is kept in the frame's `storedSymbols`, so a write stores the string or the\n * dual again. Anything but a boolean, `undefined` or null throws a `QvdValidationError`.\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 duals,\n coerceNumericStrings,\n onProgress,\n signal,\n } = options;\n this._materialisesRows = materialisesRows;\n const checked = checkPath(filePath, allowedDir);\n this._path = checked.path;\n /**\n * The allowed directory, resolved. Kept because the path is checked again immediately before it is\n * opened - see `_readData` - and that check has to be made against the directory this one was,\n * whatever the working directory has become since.\n */\n this._allowedDir = checked.base;\n /** What a dual symbol reads as. Checked here, so a bad value fails before the file is opened. */\n this._duals = normaliseDuals(duals, this._path);\n /**\n * Whether a cell that would be a string reads as a number when its text is a finite number. Off\n * unless asked for; on, the text is recorded in the frame's `storedSymbols`, so a write stores the\n * string or the dual it was read from. Checked here, like `duals`, before the file is opened.\n */\n this._coerceNumericStrings = normaliseCoerceNumericStrings(coerceNumericStrings, this._path);\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<import('./util/symbolParser.js').FieldSymbols>|null} Each selected field's decoded symbols. */\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 * A windowed read - anything with `offset`, `limit` or `maxRows` - reads only the bytes it\n * needs, rather than the file. Measured on `chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows\n * over 20 fields: the last thousand rows take 19 ms against 636 ms for the whole file.\n *\n * The saving is in the index table and the rows, not in the symbol table, which is read in\n * full whatever the window because a stored index in any row can address any symbol. So the\n * gain scales with how much of the file is rows: on a file whose bytes are mostly distinct\n * values there is very little to save, which is what `symbolFilteringThreshold` and the\n * two-pass path exist for.\n *\n * Algorithm for a windowed read:\n * 1. Read the file a chunk at a time until the 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, by position\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 * - Reading chunks to find the header is efficient for unknown header sizes\n * - Direct byte-range reading for remaining data is fastest\n *\n * All of it goes through one handle, opened once, on the file the containment check approved. See\n * `chunksFrom` and `openChecked` for why a read no longer opens the path more than once.\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\n // Every file-system call below goes through this, so a missing or unreadable file - or on Windows\n // one another process has locked - is a QvdIOError carrying the system code rather than Node's bare\n // error.\n const failed = rethrowAsIoError(this._path, 'read');\n\n // Checked again here, immediately before the open, rather than trusting the check the constructor\n // made: the open is held to what this check approved, and the nearer the two are the less there is\n // to hold. One open for the whole read, closed by `closeAfter`, so a close that fails cannot replace\n // the error the read is already throwing - a truncated file stays a QvdCorruptedError rather than\n // turning into a QvdIOError about the close - and is reported when the read succeeded.\n const handle = await openChecked(checkPath(this._path, this._allowedDir), 'read', failed);\n\n await closeAfter(handle, failed, () => this._readFrom(handle, window, headerOnly, liveRows, failed));\n }\n\n /**\n * Reads what `_readData` was asked for, through the handle it opened.\n *\n * @param {import('fs/promises').FileHandle} handle The open file.\n * @param {QvdRowWindow} window The rows to read.\n * @param {boolean} headerOnly Stop once the XML header has been read.\n * @param {{rows: number, perChunk: number}|null} liveRows Rows held at one instant - see `_prepare`.\n * @param {(error: unknown) => never} failed The read's `rethrowAsIoError` handler.\n * @private\n */\n async _readFrom(handle, window, headerOnly, liveRows, failed) {\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 /** @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 // 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 //\n // A failed read reaches the caller as a QvdIOError through `failed`, and anything else thrown here\n // - the corrupted-file error below, or a bug - passes through as it is. That is not an accident of\n // structure: the stream this used to be caught every error its iterator threw, and a version of\n // that catch once reported a bug with no `code` as a corrupt file.\n for await (const chunk of chunksFrom(handle, CHUNK_SIZE, failed)) {\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 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 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\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 handle.stat().catch(failed);\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 //\n // `readFile()` on a handle reads from the handle's own file position, and the header was read\n // by position, which never moves it - so this is the whole file, from its first byte. It is the\n // same call as the path-based `readFile` this was, with the same limit: 2 GiB and more is Node's\n // RangeError, which #122 is still to answer.\n this._buffer = await handle.readFile().catch(failed);\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, through the handle the header came from.\n const {size: fileSize} = await handle.stat().catch(failed);\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(handle, 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 handle,\n indexTableOffset,\n indexTableBytesToRead,\n indexTableOffset + skippedIndexBytes,\n fileSize,\n fileBytesRequired,\n );\n }\n\n this._bufferFirstRow = resolved.offset;\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 const failed = rethrowAsIoError(this._path, 'read');\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).catch(failed);\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 // Decode the symbols of each *selected* field, straight from the bytes into their two halves.\n // Phase 2.5 optimization: a symbol the window does not use is walked past without decoding.\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 symbols = parseFieldSymbols(\n symbolBuffer,\n symbolsOffset,\n symbolsOffset + symbolsLength,\n // By position, matching how `_analyzeIndexTableSymbolUsage` built it. Both walk\n // `this._selectedFields`, so position is the one key that cannot collide.\n symbolsToKeep ? symbolsToKeep[position] : null,\n field['FieldName'],\n this._path,\n );\n\n this._emitProgress('symbol-table', position + 1, fields.length);\n\n return symbols;\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(\n data,\n prepared.columns,\n prepared.metadata,\n {\n ...prepared.loadStats,\n rowsLoaded: data.length,\n },\n prepared.storedSymbols,\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 133 MiB against the 352 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. The codes' storage lives outside the V8\n * heap: 3 MiB of the 133 is on it.\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, null, true);\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 halvesByField: prepared.halvesByField,\n rowCount: this._rowsDecoded,\n metadata: prepared.metadata,\n storedSymbols: prepared.storedSymbols,\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 // Every chunk shares the one record: the symbol table was parsed once, in full, for all of them.\n yield new QvdDataFrame(\n data,\n prepared.columns,\n prepared.metadata,\n {\n ...prepared.loadStats,\n offset,\n rowsLoaded: data.length,\n },\n prepared.storedSymbols,\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 * @param {boolean} [wantHalves=false] Whether to keep both halves of each symbol of a field whose\n * cells do not show them, which only a columnar read has a use for.\n * @return {Promise<{columns: Array<string>, metadata: any, loadStats: any,\n * resolvedByField: Array<Array<any>>,\n * halvesByField: Array<import('./util/resolveSymbols.js').SymbolHalves|null>,\n * storedSymbols: import('./util/storedSymbols.js').StoredSymbols|null,\n * rowsAvailable: number, offset: number}>} The parsed file, with the window as it resolved\n * against it.\n * @private\n */\n async _prepare(window, liveRows = null, wantHalves = false) {\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 assert(this._selectedFields, 'The QVD file fields have not been resolved.');\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 what it reads as depends only on the\n // index. 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 symbol the two-pass path did not decode has neither half, and an index past the end of the\n // array reads as undefined. Both resolve to undefined here, which is what the per-cell version\n // produced through optional chaining.\n //\n // A dual used to resolve to its text alone, so its number was unreachable and a write stored the\n // date as a string (#138). What it resolves to now depends on the `duals` option, and the half a\n // cell does not show goes into the stored-symbol record, which is what a write reads it back from.\n /** @type {Array<Array<any>>} */\n const resolvedByField = [];\n /** @type {Array<import('./util/resolveSymbols.js').SymbolHalves|null>} */\n const halvesByField = [];\n /** @type {Array<import('./util/storedSymbols.js').StoredSymbolsEntry>} */\n const entries = [];\n\n this._symbolTable.forEach((symbols, position) => {\n const {values, entry, halves} = resolveFieldSymbols(\n symbols,\n // @ts-ignore - asserted above\n this._selectedFields[position]['FieldName'],\n this._duals,\n this._coerceNumericStrings,\n wantHalves,\n );\n\n resolvedByField.push(values);\n halvesByField.push(halves);\n\n if (entry !== null) {\n entries.push(entry);\n }\n });\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 // Null rather than an empty record when every cell shows its whole symbol, which is the common case\n // for a file without duals. The record is also left on the header object, not enumerably, so a frame\n // built as `new QvdDataFrame(data, columns, df.metadata)` keeps it.\n const storedSymbols = entries.length > 0 ? trustStoredSymbols(entries) : null;\n\n if (storedSymbols !== null) {\n attachStoredSymbols(metadata, storedSymbols);\n }\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 {\n columns,\n metadata,\n loadStats,\n resolvedByField,\n halvesByField,\n storedSymbols,\n rowsAvailable,\n offset: resolved.offset,\n };\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 {asDual, describeType, isPlainObject} from './util/cellRules.js';\nimport {metadataOptionsFrom, readerOptionsFrom, windowFrom} from './util/readOptions.js';\nimport {\n STORED_SYMBOLS,\n attachStoredSymbols,\n narrowStoredSymbols,\n normaliseStoredSymbols,\n storedSymbolsEntry,\n storedTextOf,\n} from './util/storedSymbols.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 * @typedef {import('./util/storedSymbols.js').StoredSymbols} QvdStoredSymbols\n */\n\n/**\n * A data frame in a form that survives `JSON`, `structuredClone`, `postMessage` and `v8.serialize`,\n * and that `fromDict` turns back into a frame writing the same symbols.\n *\n * @typedef {Object} QvdDataFrameDict\n * @property {Array<string>} columns The columns.\n * @property {Array<Array<any>>} data The rows.\n * @property {QvdMetadata|null} [metadata] The header, or null.\n * @property {QvdStoredSymbols|null} [storedSymbols] The stored-symbol record, or null.\n */\n\n/**\n * The header entry `toQvd` writes for a field nobody has described.\n *\n * @param {string} fieldName The field.\n * @return {Object} A field header with no comment, no tags and an UNKNOWN number format.\n */\nfunction defaultFieldHeader(fieldName) {\n return {\n FieldName: fieldName,\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\n/**\n * The header a metadata setter starts from on a frame that has none - one built by `fromDict`, or by\n * the constructor without metadata.\n *\n * @param {Array<string>} columns The frame's columns.\n * @return {QvdMetadata} A header describing every column and nothing else.\n */\nfunction defaultHeader(columns) {\n return {\n QvBuildNo: 50667,\n CreatorDoc: '',\n CreateUtcTime: '',\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: '',\n Fields: {\n QvdFieldHeader: columns.map(defaultFieldHeader),\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/**\n * Represents a loaded QVD file.\n */\nexport class QvdDataFrame {\n /**\n * Represents the data frame stored inside a QVD file.\n *\n * The record is resolved once, here: the fifth argument when given, otherwise the one a read left on\n * its header object, so `new QvdDataFrame(data, columns, df.metadata)` keeps what `df` would write.\n * Either is narrowed to `columns`. An entry for a field the frame does not have describes no cell it\n * holds, and would make the frame's own `toDict()` a dictionary `fromDict` refuses - which is what a\n * header's record did for a frame built from some of a read's columns.\n *\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 * @param {QvdStoredSymbols|null} storedSymbols What the frame's cells were read from, where a cell\n * shows only one half of its symbol (optional) - see `storedSymbols`.\n * @throws {QvdValidationError} If the record is malformed.\n */\n constructor(data, columns, metadata = null, loadStats = null, storedSymbols = null) {\n this._data = data;\n this._columns = columns;\n this._metadata = metadata;\n /** Whether `_metadata` is this frame's own to change - see `_ownMetadata`. */\n this._ownsMetadata = false;\n this._loadStats = loadStats;\n /** @type {QvdStoredSymbols|null} */\n this._storedSymbols = narrowStoredSymbols(\n normaliseStoredSymbols(\n // @ts-ignore - a symbol-keyed property the reader defines on the header object\n storedSymbols ?? (metadata !== null && typeof metadata === 'object' ? metadata[STORED_SYMBOLS] : null),\n ),\n columns,\n );\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 * What the frame's cells were read from, where a cell shows only one half of its symbol.\n *\n * A dual read as its number has a text the cell does not show; one read as its text has a number;\n * a string read as a number has the text it was spelled with. The record keeps those halves, per\n * field, keyed by the value the cell holds, so `toQvd` writes the symbols the frame was read from\n * and `textAt` can return any cell's text. It moves with the frame through `head`, `tail`, `rows`,\n * `select`, `toDict` and `fromDict`.\n *\n * Frozen plain data: `[{field, values, numbers, texts}]`, where a cell holding `values[i]` stands for\n * the stored symbol (`numbers[i]`, `texts[i]`), a null number meaning a pure string and a null text a\n * pure number.\n *\n * @return {QvdStoredSymbols|null} The record, or null when the frame has none: every cell of the read\n * showed its whole symbol, or the frame was built without one. A frame whose columns have no entry\n * in the record it was given or found - one from `select`, or one built from some of a read's\n * columns and its header - has an empty record rather than null, because a frame given null takes\n * the record its header carries, which describes every field of the read.\n */\n get storedSymbols() {\n return this._storedSymbols;\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 * The header a metadata setter may change: this frame's own.\n *\n * A frame's header can be shared. `head`, `tail`, `rows` and `select` pass theirs on, every chunk\n * `iterate()` yields holds the same one, and `fromDict` uses the object it is given. So the first\n * change copies it, and a change made through one frame never reaches another. A frame with no header\n * gets the one `toQvd` would write for it. The copy keeps the stored-symbol record the header carries,\n * so `new QvdDataFrame(data, columns, df.metadata)` still writes what `df` would.\n *\n * @return {any} The header.\n */\n _ownMetadata() {\n if (!this._metadata) {\n this._metadata = defaultHeader(this._columns);\n } else if (!this._ownsMetadata) {\n // @ts-ignore - a symbol-keyed property the reader defines on the header object\n const record = this._metadata[STORED_SYMBOLS];\n this._metadata = structuredClone(this._metadata);\n if (record) {\n attachStoredSymbols(this._metadata, record);\n }\n }\n this._ownsMetadata = true;\n return this._metadata;\n }\n\n /**\n * Sets modifiable file-level metadata. Immutable properties related to data storage are ignored.\n *\n * The change applies to this frame only, never to a frame it was derived from or shares a header\n * with.\n *\n * @param {FileMetadataUpdate} metadata Object containing metadata properties to update.\n */\n setFileMetadata(metadata) {\n const header = this._ownMetadata();\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 header[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 *\n * Works on any frame, including one with no header yet - one from `fromDict` - and on a column the\n * header does not describe. The change applies to this frame only, never to a frame it was derived\n * from or shares a header with.\n *\n * @param {string} fieldName The name of the field.\n * @param {FieldMetadataUpdate} metadata Object containing field metadata properties to update.\n * @throws {QvdValidationError} If the frame has no column of that name.\n */\n setFieldMetadata(fieldName, metadata) {\n if (!this._columns.includes(fieldName)) {\n throw new QvdValidationError(`Column '${fieldName}' does not exist`, {\n column: fieldName,\n availableColumns: this._columns,\n });\n }\n\n const header = this._ownMetadata();\n if (!header.Fields || typeof header.Fields !== 'object' || !header.Fields.QvdFieldHeader) {\n header.Fields = {QvdFieldHeader: []};\n }\n\n let fields = header.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n header.Fields.QvdFieldHeader = fields;\n }\n\n let field = fields.find((/** @type {any} */ f) => f.FieldName === fieldName);\n if (!field) {\n field = defaultFieldHeader(fieldName);\n fields.push(field);\n }\n\n // Only allow modification of Comment, NumberFormat, and Tags (not Offset, Length, BitOffset, etc.)\n if (metadata.comment !== undefined) {\n field.Comment = metadata.comment;\n }\n if (metadata.numberFormat !== undefined) {\n field.NumberFormat = metadata.numberFormat;\n }\n if (metadata.tags !== undefined) {\n field.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, null, this._storedSymbols);\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 n === 0 ? [] : this._data.slice(-n),\n this._columns,\n this._metadata,\n null,\n this._storedSymbols,\n );\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 null,\n this._storedSymbols,\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 const index = this._cellIndex(row, column);\n\n return this._data[row][index];\n }\n\n /**\n * Returns the text of the value at the specified row and column.\n *\n * The text Qlik displays for it: a string cell is its own text, and a dual cell's text is its\n * `.text`. A number cell's text comes from the frame's `storedSymbols` - the dual it was read from,\n * or the string it was spelled as - and is null for a number that was stored as a pure number.\n *\n * ```js\n * const df = await QvdDataFrame.fromQvd('stockholm_temp.qvd');\n * df.at(0, 'date'); // -52593\n * df.textAt(0, 'date'); // '1756-01-01'\n * ```\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {string|null} The text, or null for NULL and for a number with no text.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n textAt(row, column) {\n const index = this._cellIndex(row, column);\n const value = this._data[row][index];\n\n if (typeof value === 'string') {\n return value;\n }\n\n if (typeof value === 'number') {\n const entry = storedSymbolsEntry(this._storedSymbols, column);\n\n return entry === null ? null : storedTextOf(entry, value);\n }\n\n const dual = asDual(value);\n\n return dual !== null && typeof dual.text === 'string' ? dual.text : null;\n }\n\n /**\n * Checks a row and a column name, and returns the column's position.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {number} The column's position.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n * @private\n */\n _cellIndex(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._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 // The constructor narrows the record to the fields kept, sharing their entries rather than copying them.\n return new QvdDataFrame(data, columns, this._metadata, null, this._storedSymbols);\n }\n\n /**\n * Returns the data frame as a dictionary.\n *\n * Everything a frame needs to write the same file again, as plain data: the header, and the\n * stored-symbol record that says what cells showing one half of a symbol were read from. So\n * `fromDict(await df.toDict())` writes what `df` writes, and so does a dictionary that went through\n * `JSON`, `structuredClone` or a worker on the way. The arrays are the frame's own, not copies.\n *\n * @return {Promise<QvdDataFrameDict>} The data frame as a dictionary.\n */\n async toDict() {\n return this.toJSON();\n }\n\n /**\n * The same dictionary `toDict` returns, synchronously, so `JSON.stringify(df)` gives something\n * `fromDict(JSON.parse(...))` can revive.\n *\n * @return {QvdDataFrameDict} The data frame as a dictionary.\n */\n toJSON() {\n return {\n columns: this._columns,\n data: this._data,\n metadata: this._metadata,\n storedSymbols: this._storedSymbols,\n };\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 * @param {boolean} [options.atomic=true] Whether to replace the file rather than rewrite it. The QVD\n * is built beside it under a temporary name and renamed over it, so a write that fails leaves the\n * previous file exactly as it was, and a reader of the path - a Qlik reload, say - sees the old\n * file or the new one and never a part of either. False rewrites the file where it stands, as\n * every version before 2.0.0 did: that keeps its identity, including hard links, its owner and\n * permissions set on the file itself, and needs neither room for two copies nor permission to\n * create files in the directory. It also destroys the previous file as the write begins. A file\n * that does not exist yet is renamed into place either way, since there is nothing to rewrite.\n * @param {boolean} [options.fsync=true] Whether to wait for the contents to reach the disk before\n * resolving. It is what carries an atomic write's promise through a power loss - the contents are\n * on the disk before anything is renamed, so a crash leaves the previous file or the new one and\n * never a damaged one - and what reports a failing disk's deferred error instead of losing it. The\n * rename itself is not flushed, so a crash just after the call can still lose the replacement, or\n * a file that did not exist before. False resolves once the operating system has accepted the\n * bytes, which is faster and is what every version before 2.0.0 did.\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 atomic: options.atomic,\n fsync: options.fsync,\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 {'number'|'text'|'both'} [options.duals='number'] What a dual symbol - a number with the\n * text Qlik displays for it, such as a date, a timestamp or a formatted amount - reads as.\n * `'number'` gives its number, the value Qlik sums, sorts and compares by, so a date is its serial.\n * `'text'` gives its text. `'both'` gives a frozen `QvdDual` with `.number` and `.text`, whose\n * implicit conversions throw. Under `'number'` and `'text'` the other half is kept in\n * `storedSymbols`, so `toQvd` writes the dual back, and `textAt` returns any cell's text. An int, a\n * double, a string and NULL read the same in every mode: a number, a string and null. Anything else\n * throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite. A string symbol then\n * reads as `Number(text)`, so `'007'` is 7, in every `duals` mode; a dual read with\n * `duals: 'text'` reads as the number it stores. Blank text, and text such as `'8E5597'` whose\n * `Number()` is Infinity, stay strings. The text is kept in `storedSymbols`, so `toQvd` writes the\n * original string or dual back, and a value that two stored values read as is refused there\n * rather than written as either. Anything but a boolean 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, if `fields` names a column the file does not have, if `duals`\n * is not one of its modes, or if `coerceNumericStrings` is not a boolean.\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 * Every chunk carries the same `storedSymbols`, because the symbol table is parsed once for all of\n * them, so a chunk written on its own writes the symbols its cells were read from.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Reading options, with the meanings they have on `fromQvd`.\n * @param {number} [options.chunkSize=100000] Rows per frame. Must be a positive integer.\n * @param {number|null} [options.maxRows] Rows to cover. The older name for `limit`.\n * @param {number|null} [options.limit] Rows to cover, counting from `offset`.\n * @param {number} [options.offset=0] File row to start at.\n * @param {Array<string>|null} [options.fields] Field names to read, in the order they should appear.\n * @param {'number'|'text'|'both'} [options.duals='number'] What a dual symbol reads as: its number,\n * its text, or a frozen `QvdDual` holding both. Anything else throws.\n * @param {boolean} [options.coerceNumericStrings=false] Whether a cell that would read as a string\n * reads as a number when its text is not blank and `Number(text)` is finite - a string symbol as\n * `Number(text)`, a dual read as text as its stored number - with the text kept in every chunk's\n * `storedSymbols`. Anything but a boolean throws.\n * @param {Function} [options.onProgress] Called with `{stage, current, total, percent}`; progress\n * over the rows counts the whole window, not each chunk.\n * @param {AbortSignal} [options.signal] Cancels the iteration, rejecting with `signal.reason`.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction of the memory budget the read may use,\n * charged for two chunks of rows rather than the window. Zero disables the check.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size above which a\n * windowed read switches to two-pass filtering.\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 * Takes what `toDict` returns. `metadata` and `storedSymbols` are optional; with the record, a frame\n * rebuilt from a read writes the symbols the read found - duals with their texts, strings with their\n * spelling - even after a trip through `JSON`. The record is checked, so a malformed one is refused\n * here rather than written.\n *\n * @param {QvdDataFrameDict} data The dictionary to construct the data frame from.\n * @return {Promise<QvdDataFrame>} The constructed data frame.\n * @throws {QvdValidationError} If `columns` or `data` is missing, `metadata` is not a plain object,\n * or `storedSymbols` is malformed or names a field that is not one of the columns.\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 const {metadata = null, storedSymbols = null} = data;\n\n if (metadata !== null && !isPlainObject(metadata)) {\n throw new QvdValidationError(`metadata must be a plain object; got ${describeType(metadata)}`, {\n type: typeof metadata,\n });\n }\n\n const record = normaliseStoredSymbols(storedSymbols);\n\n if (record !== null) {\n const unknown = record.find((entry) => !data.columns.includes(entry.field));\n\n if (unknown !== undefined) {\n throw new QvdValidationError(`storedSymbols names field '${unknown.field}', which is not one of the columns`, {\n field: unknown.field,\n availableColumns: data.columns,\n });\n }\n }\n\n return new QvdDataFrame(data.data, data.columns, metadata, null, record);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\nimport {INT32_MAX, INT32_MIN, asDual, checkNumber, checkText, describeType, isStoredAsInt} from './util/cellRules.js';\nimport {symbolByteLength, writeSymbol} from './util/symbolBytes.js';\n\n/**\n * Throws unless a value can be stored as the integer of a symbol.\n *\n * @param {any} value The value.\n * @param {Object} context Merged into the error's context.\n * @throws {QvdValidationError} If the value is not an integer inside the int32 range.\n */\nfunction checkInteger(value, context) {\n if (typeof value === 'number' && isStoredAsInt(value)) {\n return;\n }\n\n throw new QvdValidationError(\n `The integer of a symbol must be an integer from ${INT32_MIN} to ${INT32_MAX}; got ` +\n (typeof value === 'number' ? String(value) : describeType(value)),\n {...context, half: 'integer', type: typeof value},\n );\n}\n\n/**\n * One stored symbol, as the symbol table holds it: an int, a double, a string, or a dual of an int or\n * a double with its text.\n *\n * A low-level record of the file's contents rather than a cell. A read never puts one in a data frame\n * - a cell is a number, a string, a `QvdDual` or null - and the writer refuses one as a cell, pointing\n * at `QvdDual`, because a symbol carries a storage kind the writer derives from the value itself.\n *\n * The factories validate what they are given and throw `QvdValidationError` naming the half, so a\n * symbol built through them can be encoded. The constructor checks nothing, and\n * `toByteRepresentation` refuses whatever it cannot encode.\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 * The kind is the one the symbol carries - an int, a double, a string, or a dual of an int or a\n * double with its text - so a symbol built with `fromDoubleValue(4)` stays a double. Each half is\n * checked before a byte is written, because `QvdSymbol`'s constructor checks nothing: an integer\n * outside int32 used to surface as a bare `RangeError` from `writeInt32LE`, a symbol holding an\n * integer and a double silently lost the double, a text with a NUL produced a symbol that ends\n * early, and a text with an unpaired surrogate was written with U+FFFD in its place.\n *\n * A half left `undefined` - `new QvdSymbol()`, or `new QvdSymbol(7)` - is absent, as it is to\n * `toPrimaryValue`. It used to be read as present: `new QvdSymbol(7)` threw a bare `TypeError` from\n * `Buffer.from`, and `new QvdSymbol(undefined, 4.5, '4.50')` was written as a dual of the integer 0.\n *\n * @return {Buffer} The byte representation of the symbol.\n * @throws {QvdValidationError} If the symbol holds both an integer and a double, holds nothing, or\n * holds a half no symbol can store. The message names the half.\n */\n toByteRepresentation() {\n const intValue = this._intValue ?? null;\n const doubleValue = this._doubleValue ?? null;\n const stringValue = this._stringValue ?? null;\n\n if (intValue !== null && doubleValue !== null) {\n throw new QvdValidationError('A symbol holds an integer or a double, not both', {\n intValue,\n doubleValue,\n });\n }\n\n if (intValue === null && doubleValue === null && stringValue === null) {\n throw new QvdValidationError('The symbol does not contain any value.', {\n intValue,\n doubleValue,\n stringValue,\n });\n }\n\n if (intValue !== null) {\n checkInteger(intValue, {});\n }\n\n if (doubleValue !== null) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n }\n\n if (stringValue !== null) {\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n }\n\n const number = intValue ?? doubleValue;\n const kind = number === null ? 4 : (intValue !== null ? 1 : 2) + (stringValue !== null ? 4 : 0);\n const buffer = Buffer.allocUnsafe(symbolByteLength(kind, number, stringValue));\n\n writeSymbol(buffer, 0, kind, number, stringValue);\n\n return buffer;\n }\n\n /**\n * Checks if this symbol is equal to another symbol.\n *\n * By shape rather than by class: another value is equal when its `intValue`, `doubleValue` and\n * `stringValue` are, compared with `===`, whichever copy of this library built it - `instanceof`\n * answers false for a symbol from the CommonJS build tested by the ESM one. A dual value, a `QvdDual`\n * or `{number, text}`, is equal to a dual symbol with the same number and text: a dual carries no\n * storage kind, so either kind matches.\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 === null || typeof value !== 'object') {\n return false;\n }\n\n const intValue = this._intValue ?? null;\n const doubleValue = this._doubleValue ?? null;\n const stringValue = this._stringValue ?? null;\n const dual = asDual(value);\n\n if (dual !== null) {\n return (\n stringValue !== null &&\n stringValue === dual.text &&\n (intValue === null) !== (doubleValue === null) &&\n (intValue ?? doubleValue) === dual.number\n );\n }\n\n if (!('intValue' in value && 'doubleValue' in value && 'stringValue' in value)) {\n return false;\n }\n\n return (\n intValue === (value.intValue ?? null) &&\n doubleValue === (value.doubleValue ?? null) &&\n stringValue === (value.stringValue ?? null)\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 * @throws {QvdValidationError} If the integer is not an integer inside the int32 range.\n */\n static fromIntValue(intValue) {\n checkInteger(intValue, {});\n\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 * @throws {QvdValidationError} If the double is not a finite number.\n */\n static fromDoubleValue(doubleValue) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n\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 * @throws {QvdValidationError} If the string is not a string, or holds a NUL or an unpaired surrogate.\n */\n static fromStringValue(stringValue) {\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\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 * @throws {QvdValidationError} If the integer is not an integer inside the int32 range, or the text\n * is not a string, or holds a NUL or an unpaired surrogate.\n */\n static fromDualIntValue(intValue, stringValue) {\n checkInteger(intValue, {});\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\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 * @throws {QvdValidationError} If the double is not a finite number, or the text is not a string,\n * or holds a NUL or an unpaired surrogate.\n */\n static fromDualDoubleValue(doubleValue, stringValue) {\n checkNumber(doubleValue, 'The double of a symbol', {half: 'double'});\n checkText(stringValue, 'The text of a symbol', {half: 'text'});\n\n return new QvdSymbol(null, doubleValue, stringValue);\n }\n}\n","// @ts-check\n\nexport {QvdSymbol} from './QvdSymbol.js';\nexport {QvdDual} from './QvdDual.js';\nexport {qlikSerialToDate, dateToQlikSerial} from './util/qlikDate.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","// @ts-check\n\nimport {types} from 'util';\nimport {QvdValidationError} from '../QvdErrors.js';\nimport {asDual, describeType} from './cellRules.js';\n\n/** Qlik's day 0: 30 December 1899, so that 1 January 1900 is day 2, as in Excel and Lotus 1-2-3. */\nconst QLIK_EPOCH_MS = Date.UTC(1899, 11, 30);\n\nconst MS_PER_DAY = 86400000;\n\n/** The furthest a JavaScript `Date` reaches either side of 1970, in milliseconds. */\nconst MAX_DATE_MS = 8.64e15;\n\n/** The serials of the first and last days a `Date` can hold: -99974431 and 100025569. */\nconst MIN_SERIAL = (-MAX_DATE_MS - QLIK_EPOCH_MS) / MS_PER_DAY;\nconst MAX_SERIAL = (MAX_DATE_MS - QLIK_EPOCH_MS) / MS_PER_DAY;\n\n/**\n * Converts a Qlik date or timestamp serial to a JavaScript `Date`.\n *\n * Qlik stores a date as the number of days since 30 December 1899, with the time of day as the\n * fraction: 42382.260416666664 is 13 January 2016 at 06:15. That number is what a date field's cell\n * reads as, whether Qlik stored it as a dual with the date's text or as a pure number with a `DATE`\n * format - and it is the `number` of a dual value read with `{duals: 'both'}`.\n *\n * **The serial has no time zone, and the result is read in UTC.** Qlik's serial means \"this wall-clock\n * date and time\", not an instant. The `Date` returned carries those wall-clock fields in its UTC\n * getters, so `toISOString()` and `getUTCHours()` show what Qlik shows. The local-time getters apply\n * the machine's own offset, which is almost never what you want here.\n *\n * Checked against the text Qlik stored beside every date in stockholm_temp and every trip start\n * timestamp in a chicago_taxi_rides file, and rounded to the millisecond, which is finer than any Qlik\n * timestamp text shows.\n *\n * ```js\n * qlikSerialToDate(-52593).toISOString(); // '1756-01-01T00:00:00.000Z'\n * qlikSerialToDate(new QvdDual(-52593, '1756-01-01')).toISOString(); // a dual works too, through its number\n * ```\n *\n * @param {number|import('../QvdDual.js').QvdDual|{number: number, text: string}} serial The serial, or a dual whose number is one.\n * @return {Date} The date, with Qlik's wall-clock fields in its UTC getters.\n * @throws {QvdValidationError} If the serial is not a finite number, or is a day a `Date` cannot hold.\n */\nexport function qlikSerialToDate(serial) {\n const dual = asDual(serial);\n const number = dual === null ? serial : dual.number;\n\n if (typeof number !== 'number' || !Number.isFinite(number)) {\n throw new QvdValidationError('A Qlik date serial must be a finite number', {\n provided: describeType(number),\n type: typeof serial,\n });\n }\n\n const ms = Math.round(QLIK_EPOCH_MS + number * MS_PER_DAY);\n\n // Past this a Date is Invalid Date, which fails later and somewhere else - in toISOString(), say.\n if (!(Math.abs(ms) <= MAX_DATE_MS)) {\n throw new QvdValidationError(`A Qlik date serial of ${number} is outside the range a JavaScript Date can hold`, {\n serial: number,\n minSerial: MIN_SERIAL,\n maxSerial: MAX_SERIAL,\n });\n }\n\n return new Date(ms);\n}\n\n/**\n * Converts a JavaScript `Date` to a Qlik date or timestamp serial.\n *\n * The inverse of `qlikSerialToDate`, and it reads the date's UTC fields for the same reason: a\n * serial is a wall-clock value. Build the `Date` from UTC parts - `new Date(Date.UTC(2016, 0, 13, 6,\n * 15))`, or an ISO string ending in `Z` - to get the serial Qlik would store for that date and time.\n *\n * For every date and timestamp checked against `qlikSerialToDate`, converting Qlik's serial to a\n * `Date` and back returns Qlik's stored double exactly.\n *\n * A `Date` from another realm - a `vm` context, or a Node core module under Jest - is accepted: the\n * check is on what the value is, not on which `Date` constructor made it.\n *\n * To write a date Qlik will treat as a date, pair the serial with the text to display:\n *\n * ```js\n * const when = new Date(Date.UTC(2016, 0, 13, 6, 15));\n * const cell = new QvdDual(dateToQlikSerial(when), '2016-01-13 06:15:00');\n * ```\n *\n * @param {Date} date The date.\n * @return {number} The serial: whole days since 30 December 1899, with the time of day as the fraction.\n * @throws {QvdValidationError} If the argument is not a valid `Date`.\n */\nexport function dateToQlikSerial(date) {\n const ms = types.isDate(date) ? Date.prototype.getTime.call(date) : Number.NaN;\n\n if (Number.isNaN(ms)) {\n throw new QvdValidationError('dateToQlikSerial needs a valid Date', {\n provided: describeType(date),\n type: typeof date,\n });\n }\n\n return (ms - QLIK_EPOCH_MS) / MS_PER_DAY;\n}\n"]}
|