qvdjs 0.9.4 → 0.10.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/README.md +175 -17
- package/dist/index.cjs +869 -321
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +869 -321
- package/dist/index.js.map +1 -1
- package/package.json +15 -15
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/QvdErrors.js","../src/QvdSymbol.js","../src/util/validatePath.js","../src/QvdFileWriter.js","../src/util/bitUtils.js","../src/util/memoryUtils.js","../src/util/validationUtils.js","../src/util/symbolParser.js","../src/QvdFileReader.js","../src/QvdDataFrame.js","../src/index.js"],"names":["QvdError","QvdParseError","QvdValidationError","QvdIOError","QvdCorruptedError","QvdSecurityError","QvdSymbol","path","fs","QvdFileWriter","assert","crypto","xml","v8","os","QvdFileReader","QvdDataFrame"],"mappings":"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","file":"index.cjs","sourcesContent":["// @ts-check\n\n/**\n * Base error class for all QVD-related errors.\n * Provides structured error information with error codes and context.\n */\nexport class QvdError extends Error {\n /**\n * Constructs a new QVD error.\n *\n * @param {string} message The error message.\n * @param {string} code The error code.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, code, context = {}) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n this.context = context;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when parsing a QVD file fails.\n * Used for issues during XML header parsing, symbol table parsing, or index table parsing.\n */\nexport class QvdParseError extends QvdError {\n /**\n * Constructs a new QVD parse error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_PARSE_ERROR', context);\n }\n}\n\n/**\n * Error thrown when input validation fails.\n * Used for invalid parameters, out of bounds access, or missing required data.\n */\nexport class QvdValidationError extends QvdError {\n /**\n * Constructs a new QVD validation error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_VALIDATION_ERROR', context);\n }\n}\n\n/**\n * Error thrown when file system operations fail.\n * Used for issues reading or writing QVD files.\n */\nexport class QvdIOError extends QvdError {\n /**\n * Constructs a new QVD IO error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_IO_ERROR', context);\n }\n}\n\n/**\n * Error thrown when a QVD file is corrupted or malformed.\n * Used for missing headers, invalid data structures, or corrupted data.\n */\nexport class QvdCorruptedError extends QvdError {\n /**\n * Constructs a new QVD corrupted error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_CORRUPTED_ERROR', context);\n }\n}\n\n/**\n * Error thrown when security violations occur.\n * Used for path traversal attempts, XXE attacks, or other security issues.\n */\nexport class QvdSecurityError extends QvdError {\n /**\n * Constructs a new QVD security error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_SECURITY_ERROR', context);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * Represents a Qlik symbol/value, stored in a QVD file.\n */\nexport class QvdSymbol {\n /**\n * Constructs a new QVD symbol.\n *\n * @param {number|null} intValue The integer value.\n * @param {number|null} doubleValue The double value.\n * @param {string|null} stringValue The string value.\n */\n constructor(intValue, doubleValue, stringValue) {\n this._intValue = intValue;\n\n this._doubleValue = doubleValue;\n\n this._stringValue = stringValue;\n }\n\n /**\n * Returns the integer value of this symbol.\n *\n * @return {number|null} The integer value.\n */\n get intValue() {\n return this._intValue;\n }\n\n /**\n * Returns the double value of this symbol.\n *\n * @return {number|null} The double value.\n */\n get doubleValue() {\n return this._doubleValue;\n }\n\n /**\n * Returns the string value of this symbol.\n *\n * @return {string|null} The string value.\n */\n get stringValue() {\n return this._stringValue;\n }\n\n /**\n * Retrieves the primary value of this symbol. The primary value is descriptive raw value.\n * It is either the string value, the integer value or the double value, prioritized in this order.\n *\n * @return {number|string|null} The primary value.\n */\n toPrimaryValue() {\n if (null != this._stringValue) {\n return this._stringValue;\n } else if (null != this._intValue) {\n return this._intValue;\n } else if (null != this._doubleValue) {\n return this._doubleValue;\n } else {\n return null;\n }\n }\n\n /**\n * Converts the symbol to its byte representation.\n *\n * @return {Buffer} The byte representation of the symbol.\n */\n toByteRepresentation() {\n if (this._intValue !== null && this._stringValue !== null) {\n const intBuffer = Buffer.alloc(4);\n intBuffer.writeInt32LE(this._intValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n const stringBuffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([5]), intBuffer, stringBuffer]);\n } else if (this._doubleValue !== null && this._stringValue !== null) {\n const floatBuffer = Buffer.alloc(8);\n floatBuffer.writeDoubleLE(this._doubleValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n const stringBuffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([6]), floatBuffer, stringBuffer]);\n } else if (this._intValue !== null) {\n const buffer = Buffer.alloc(4);\n buffer.writeInt32LE(this._intValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([1]), buffer]);\n } else if (this._doubleValue !== null) {\n const buffer = Buffer.alloc(8);\n buffer.writeDoubleLE(this._doubleValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([2]), buffer]);\n } else if (this._stringValue !== null) {\n // @ts-ignore - Buffer.concat type compatibility\n const buffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([4]), buffer]);\n } else {\n throw new QvdValidationError('The symbol does not contain any value.', {\n intValue: this._intValue,\n doubleValue: this._doubleValue,\n stringValue: this._stringValue,\n });\n }\n }\n\n /**\n * Checks if this symbol is equal to another symbol.\n *\n * @param {*} value The object to compare with.\n * @return {boolean} True if the objects are equal, false otherwise.\n */\n equals(value) {\n if (!(value instanceof QvdSymbol)) {\n return false;\n }\n\n return (\n this._intValue === value.intValue &&\n this._doubleValue === value.doubleValue &&\n this._stringValue === value.stringValue\n );\n }\n\n /**\n * Constructs a pure integer value symbol.\n *\n * @param {number} intValue The integer value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromIntValue(intValue) {\n return new QvdSymbol(intValue, null, null);\n }\n\n /**\n * Constructs a pure double value symbol.\n *\n * @param {number} doubleValue The double value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDoubleValue(doubleValue) {\n return new QvdSymbol(null, doubleValue, null);\n }\n\n /**\n * Constructs a pure string value symbol.\n *\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromStringValue(stringValue) {\n return new QvdSymbol(null, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from an integer and a string value.\n *\n * @param {number} intValue The integer value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDualIntValue(intValue, stringValue) {\n return new QvdSymbol(intValue, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from a double and a string value.\n *\n * @param {number} doubleValue The double value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDualDoubleValue(doubleValue, stringValue) {\n return new QvdSymbol(null, doubleValue, stringValue);\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport {QvdSecurityError, QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Determines whether a resolved path is contained within a resolved base directory, using only\n * string comparison.\n *\n * This is the fallback for when the filesystem cannot answer the question - in practice, when\n * allowedDir does not exist. It cannot see through symlinks and has to guess at case\n * sensitivity, which is exactly why it is not the primary check.\n *\n * Uses path.relative() rather than a string prefix test, so that filesystem roots\n * ('/', 'C:\\', '\\\\server\\share\\') and base directories with a trailing separator are\n * handled correctly. A prefix test appends path.sep to the base, which produces '//'\n * for a root and therefore matches nothing.\n *\n * @param {string} resolvedBaseDir Absolute, resolved base directory.\n * @param {string} resolvedPath Absolute, resolved candidate path.\n * @return {boolean} True if the path is the base directory itself or lies beneath it.\n */\nfunction isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) {\n // Folding is applied on Windows only. It used to cover darwin as well, on the assumption that\n // macOS is always case-insensitive, but macOS supports case-sensitive APFS and HFS+ volumes on\n // which two names differing only in case are genuinely different directories - so folding there\n // let a sibling directory pass the check. The on-disk comparison below settles case correctly\n // by asking the filesystem, which is why this fallback no longer needs to guess for darwin.\n const isCaseInsensitiveFS = process.platform === 'win32';\n const base = isCaseInsensitiveFS ? resolvedBaseDir.toLowerCase() : resolvedBaseDir;\n const target = isCaseInsensitiveFS ? resolvedPath.toLowerCase() : resolvedPath;\n\n const relative = path.relative(base, target);\n\n // '' means the path IS the base directory. A relative path that starts with '..' escapes\n // the base, and an absolute result means the two are on different roots/drives.\n if (relative === '') {\n return true;\n }\n if (path.isAbsolute(relative)) {\n return false;\n }\n return relative !== '..' && !relative.startsWith(`..${path.sep}`);\n}\n\n/**\n * Resolves the deepest ancestor of a path that actually exists, following symlinks.\n *\n * A path being written to does not exist yet, and neither may some of its parent directories, so\n * realpath() on the full path would simply fail. Walking up to the first component that does\n * exist gives the deepest point the filesystem can vouch for; anything below it is a name that\n * will be created inside that directory.\n *\n * @param {string} target Absolute, lexically resolved path.\n * @return {string|null} Canonical path of the deepest existing ancestor, or null if it could not\n * be determined.\n */\nfunction resolveDeepestExisting(target) {\n let current = target;\n\n for (;;) {\n try {\n return fs.realpathSync(current);\n } catch (error) {\n const code = /** @type {{code?: string}} */ (error)?.code;\n\n // ENOENT: this component does not exist. ENOTDIR: an ancestor is a file, so nothing below\n // it can exist either. Both mean \"keep walking up\". Anything else (EACCES, ELOOP) means the\n // filesystem cannot answer, and the caller falls back to the lexical test - which is safe,\n // because an open() on the same path is about to fail for the same reason.\n if (code !== 'ENOENT' && code !== 'ENOTDIR') {\n return null;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n }\n}\n\n/**\n * Determines whether a path is contained within a base directory by asking the filesystem.\n *\n * Both sides are resolved through symlinks and then compared by identity - device and inode -\n * rather than by name, walking up from the target until the base is found or the root is reached.\n * That settles two questions a string comparison cannot:\n *\n * - Symlinks. A link inside allowedDir pointing outside it resolves to its target, so it is\n * rejected. A lexical check sees only the link's own name, still under allowedDir, and lets it\n * through - which meant arbitrary read via the reader and arbitrary overwrite via the writer.\n * - Case. On a case-insensitive volume 'Qvd' and 'qvd' are one directory and share an inode; on a\n * case-sensitive volume they are two directories with different inodes. Comparing identity gets\n * both right without inferring anything from process.platform, which is what the old code did\n * and got wrong on case-sensitive macOS volumes.\n *\n * This is a check on the path, so it is inherently subject to a race: a symlink swapped in\n * between this call and the subsequent open would defeat it. Closing that would require opening\n * with O_NOFOLLOW and verifying the descriptor, which is a larger change to the reader and\n * writer than this function can make on its own.\n *\n * @param {string} resolvedBaseDir Absolute, lexically resolved base directory.\n * @param {string} resolvedPath Absolute, lexically resolved candidate path.\n * @return {boolean|null} True or false when the filesystem could answer, null when it could not.\n */\nfunction isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {\n /** @type {import('fs').Stats} */\n let baseStat;\n\n try {\n // The base has to exist to be identified. If it does not, there is nothing on disk to compare\n // against and the lexical fallback is all that is left.\n baseStat = fs.statSync(fs.realpathSync(resolvedBaseDir));\n } catch {\n return null;\n }\n\n let current = resolveDeepestExisting(resolvedPath);\n if (current === null) {\n return null;\n }\n\n // realpathSync() returns a fully canonical path, so every ancestor of it is canonical too and\n // walking up with dirname() cannot step through a symlink.\n for (;;) {\n let stat;\n try {\n stat = fs.statSync(current);\n } catch {\n return null;\n }\n\n if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {\n return true;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return false;\n }\n current = parent;\n }\n}\n\n/**\n * Validates that a file path stays inside the allowed directory.\n *\n * Containment is decided by the filesystem wherever it can be: both paths are resolved through\n * symlinks and compared by device and inode. That covers symlink escapes and case sensitivity,\n * neither of which a string comparison can get right. When the base directory does not exist,\n * there is nothing to compare against and a lexical check is used instead.\n *\n * To permit access to an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on\n * Windows). There is deliberately no separate \"disable the check\" value: a null or empty\n * allowedDir falls back to the current working directory, so a caller that accidentally\n * passes one still gets the restriction rather than silently losing it.\n *\n * @param {string} filePath The path to validate.\n * @param {string|null} [allowedDir] Optional allowed directory path. Defaults to the current\n * working directory to prevent path traversal attacks.\n * @throws {QvdValidationError} If filePath is not a non-empty string, or allowedDir is not a\n * string, null or undefined.\n * @throws {QvdSecurityError} If path traversal is detected.\n * @return {string} The resolved absolute path. This is the lexically resolved path, not the\n * canonical one, so callers see the path they asked for.\n */\nexport function validatePath(filePath, allowedDir) {\n // Validate argument types up front, so callers get a typed error instead of a bare TypeError\n // from deep inside the function (e.g. 'filePath.includes is not a function').\n if (typeof filePath !== 'string' || filePath.length === 0) {\n throw new QvdValidationError('filePath must be a non-empty string', {\n provided: filePath,\n type: typeof filePath,\n });\n }\n\n if (allowedDir !== undefined && allowedDir !== null && typeof allowedDir !== 'string') {\n throw new QvdValidationError('allowedDir must be a string, null or undefined', {\n provided: allowedDir,\n type: typeof allowedDir,\n });\n }\n\n // Check for null bytes which can be used in path traversal attacks\n if (filePath.includes('\\0')) {\n throw new QvdSecurityError('Path traversal detected: Null byte in path', {\n path: filePath,\n reason: 'null_byte',\n });\n }\n\n const resolvedPath = path.resolve(filePath);\n\n // Default to the current working directory when no allowed directory is specified. This\n // prevents path traversal attacks by ensuring files can only be accessed within the CWD\n // or a more restrictive allowed directory.\n //\n // null and '' deliberately fall back to the CWD rather than meaning \"no restriction\":\n // callers routinely produce them from optional config or a JSON round trip, and silently\n // dropping the sandbox in that case would be a security hole. A caller that genuinely wants\n // an entire volume passes its root ('/' or 'C:\\\\'), which the containment test supports.\n const baseDir = allowedDir || process.cwd();\n const resolvedBaseDir = path.resolve(baseDir);\n\n const onDisk = isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath);\n const contained = onDisk === null ? isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) : onDisk;\n\n if (!contained) {\n throw new QvdSecurityError('Path traversal detected: Access denied', {\n path: filePath,\n resolvedPath,\n allowedDir: resolvedBaseDir,\n reason: 'outside_allowed_directory',\n // Says which check refused, so a rejection of a path that looks contained is traceable to\n // a symlink or a case difference rather than looking like a bug.\n check: onDisk === null ? 'lexical' : 'filesystem',\n });\n }\n\n return resolvedPath;\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\nimport xml from 'xml2js';\nimport assert from 'assert';\nimport {QvdSymbol} from './QvdSymbol.js';\nimport {validatePath} from './util/validatePath.js';\n\n/**\n * @typedef {import('./QvdDataFrame.js').QvdDataFrame} QvdDataFrame\n */\n\n/**\n * Persists a QVD file to disk.\n */\nexport class QvdFileWriter {\n /**\n * Constructs a new QVD file writer.\n *\n * @param {string} filePath The path to the QVD file to write.\n * @param {QvdDataFrame} df The data frame to write to the QVD file.\n * @param {Object} [options={}] Options for the writer.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function.\n */\n constructor(filePath, df, options = {}) {\n const {allowedDir, onProgress} = options;\n this._path = validatePath(filePath, allowedDir);\n this._df = df;\n this._onProgress = onProgress;\n this._header = null;\n this._symbolBuffer = null;\n /** @type {Array<Array<import('./QvdSymbol.js').QvdSymbol>>|null} */\n this._symbolTable = null;\n /** @type {Array<any>|null} */\n this._symbolTableMetadata = null;\n this._indexBuffer = null;\n /** @type {Array<any>|null} */\n this._indexTable = null;\n /** @type {Array<any>|null} */\n this._indexTableMetadata = null;\n this._recordByteSize = null;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * @param {string} stage The current stage of the operation.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n this._onProgress({\n stage,\n current,\n total,\n percent,\n });\n }\n }\n\n /**\n * Writes the data to the QVD file.\n */\n async _writeData() {\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolBuffer, 'The QVD file symbol table has not been parsed.');\n assert(this._indexBuffer, 'The QVD file index table has not been parsed.');\n\n this._emitProgress('write', 0, 1);\n\n // @ts-ignore - Buffer.concat type compatibility\n const headerBuffer = Buffer.concat([Buffer.from(this._header, 'utf-8'), Buffer.from([0])]);\n\n let fd;\n try {\n fd = await fs.promises.open(this._path, 'w');\n await fd.write(headerBuffer, 0, headerBuffer.length, 0);\n await fd.write(this._symbolBuffer, 0, this._symbolBuffer.length, headerBuffer.length);\n await fd.write(this._indexBuffer, 0, this._indexBuffer.length, headerBuffer.length + this._symbolBuffer.length);\n this._emitProgress('write', 1, 1);\n } finally {\n if (fd) {\n await fd.close();\n }\n }\n }\n\n /**\n * Builds the XML header of the QVD file.\n */\n _buildHeader() {\n this._emitProgress('header', 0, 1);\n const creationDate = new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '');\n /** @type {import('./QvdDataFrame.js').QvdMetadata|null} */\n const existingMetadata = this._df.metadata;\n\n // Use existing metadata if available, otherwise create default values\n const baseMetadata = existingMetadata\n ? {\n QvBuildNo: existingMetadata.QvBuildNo || 50667,\n CreatorDoc: existingMetadata.CreatorDoc || crypto.randomUUID(),\n CreateUtcTime: existingMetadata.CreateUtcTime || creationDate,\n SourceCreateUtcTime: existingMetadata.SourceCreateUtcTime || '',\n SourceFileUtcTime: existingMetadata.SourceFileUtcTime || '',\n SourceFileSize: existingMetadata.SourceFileSize || -1,\n StaleUtcTime: existingMetadata.StaleUtcTime || '',\n TableName: existingMetadata.TableName || path.basename(this._path, path.extname(this._path)),\n Compression: existingMetadata.Compression || '',\n Comment: existingMetadata.Comment || '',\n EncryptionInfo: existingMetadata.EncryptionInfo || '',\n TableTags: existingMetadata.TableTags || '',\n ProfilingData: existingMetadata.ProfilingData || '',\n Lineage: existingMetadata.Lineage || {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n }\n : {\n QvBuildNo: 50667,\n CreatorDoc: crypto.randomUUID(),\n CreateUtcTime: creationDate,\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: path.basename(this._path, path.extname(this._path)),\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n };\n\n // Get existing field metadata if available\n /** @type {any[]} */\n let existingFields = [];\n if (existingMetadata && existingMetadata.Fields && existingMetadata.Fields.QvdFieldHeader) {\n existingFields = Array.isArray(existingMetadata.Fields.QvdFieldHeader)\n ? existingMetadata.Fields.QvdFieldHeader\n : [existingMetadata.Fields.QvdFieldHeader];\n }\n\n const xmlObject = {\n QvdTableHeader: {\n ...baseMetadata,\n Fields: {\n QvdFieldHeader: this._df.columns.map((/** @type {any} */ column, /** @type {number} */ index) => {\n // Find existing field metadata for this column\n const existingField = existingFields.find((/** @type {any} */ f) => f.FieldName === column);\n\n return {\n FieldName: column,\n BitOffset: this._indexTableMetadata?.[index][0],\n BitWidth: this._indexTableMetadata?.[index][1],\n Bias: this._indexTableMetadata?.[index][2],\n NoOfSymbols: this._symbolTable?.[index].length,\n Offset: this._symbolTableMetadata?.[index][0],\n Length: this._symbolTableMetadata?.[index][1],\n Comment: existingField?.Comment || '',\n NumberFormat: existingField?.NumberFormat || {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: existingField?.Tags || {},\n };\n }),\n },\n NoOfRecords: this._indexTable?.length,\n RecordByteSize: this._recordByteSize,\n Offset:\n this._symbolTableMetadata && this._symbolTableMetadata.length > 0\n ? this._symbolTableMetadata[this._symbolTableMetadata.length - 1][0] +\n this._symbolTableMetadata[this._symbolTableMetadata.length - 1][1]\n : 0,\n Length: this._indexBuffer?.length,\n },\n };\n\n const builder = new xml.Builder({\n renderOpts: {\n pretty: true,\n newline: '\\r\\n',\n indent: ' ',\n },\n });\n this._header = builder.buildObject(xmlObject) + '\\r\\n';\n this._emitProgress('header', 1, 1);\n }\n\n /**\n * Builds the symbol table of the QVD file.\n *\n * PERFORMANCE OPTIMIZATION: This method uses a single-pass algorithm to build\n * symbol tables for all columns simultaneously. This reduces time complexity from\n * O(n×m×s) to O(n×m) where n=rows, m=columns, s=symbols per column.\n *\n * Algorithm:\n * 1. Initialize a Set for each column to collect unique values\n * 2. Single pass through all data rows, adding values to corresponding Sets\n * 3. Convert Sets to arrays and create QvdSymbol instances\n * 4. Serialize symbols to binary format and update metadata\n *\n * This approach provides:\n * - 80-90% performance improvement for large datasets (100K+ rows)\n * - Better cache locality (process all columns in one data traversal)\n * - Lower memory pressure (no intermediate arrays per column)\n *\n * @private\n */\n _buildSymbolTable() {\n this._symbolTable = [];\n this._symbolTableMetadata = [];\n this._symbolBuffer = Buffer.alloc(0);\n\n const numColumns = this._df.columns.length;\n\n this._emitProgress('symbol-table', 0, numColumns);\n\n // Initialize a Set for each column to track unique values\n // Sets provide O(1) add and automatic deduplication\n const uniqueValuesSets = this._df.columns.map(() => new Set());\n\n // Single pass through all data to collect unique values for all columns\n // This is the key optimization: process all columns together instead of\n // iterating through data once per column\n this._df.data.forEach((row) => {\n this._df.columns.forEach((column, columnIndex) => {\n const value = row[columnIndex];\n uniqueValuesSets[columnIndex].add(value);\n });\n });\n\n // Process each column's unique values\n this._df.columns.forEach((column, columnIndex) => {\n const uniqueValuesSet = uniqueValuesSets[columnIndex];\n const uniqueValues = Array.from(uniqueValuesSet);\n const containsNull = uniqueValues.includes(null) || uniqueValues.includes(undefined);\n const symbols = uniqueValues\n .filter((value) => value !== null && value !== undefined)\n .map((value) => QvdFileWriter._convertRawToSymbol(value));\n\n // @ts-ignore:next-line sd\n const currentSymbolBuffer = Buffer.concat(symbols.map((symbol) => symbol.toByteRepresentation()));\n this._symbolBuffer = this._symbolBuffer\n ? Buffer.concat([this._symbolBuffer, currentSymbolBuffer])\n : currentSymbolBuffer;\n\n const symbolsLength = currentSymbolBuffer.length;\n const symbolsOffset = this._symbolBuffer.length - symbolsLength;\n\n this._symbolTableMetadata?.push([symbolsOffset, symbolsLength, containsNull]);\n // @ts-ignore - Symbol array type compatibility\n this._symbolTable?.push(symbols);\n\n this._emitProgress('symbol-table', columnIndex + 1, numColumns);\n });\n }\n\n /**\n * Builds the index table of the QVD file.\n *\n * PERFORMANCE OPTIMIZATION: Uses Map-based lookups for O(1) symbol index retrieval\n * instead of Array.findIndex() which is O(n). For columns with many unique values,\n * this provides significant performance improvements.\n *\n * Algorithm:\n * 1. Build Map<symbol, index> for each column (O(m) where m=unique values)\n * 2. For each data row, lookup indices in maps (O(1) per value)\n * 3. Convert indices to bit-packed binary format\n *\n * Bit Packing:\n * - Calculates minimum bits needed: ceil(log2(numSymbols))\n * - Packs indices into binary string, then converts to bytes\n * - Reduces file size significantly for columns with few unique values\n *\n * Example: Column with 10 unique values needs only 4 bits per value\n * instead of 32 bits (full integer), saving 87.5% space.\n *\n * @private\n */\n _buildIndexTable() {\n this._indexTable = [];\n this._indexTableMetadata = [];\n this._indexBuffer = Buffer.alloc(0);\n\n const numRows = this._df.data.length;\n this._emitProgress('index-table', 0, numRows);\n\n // Build symbol-to-index lookup maps for O(1) lookups\n // This is crucial for performance: findIndex() on large arrays is O(n)\n // while Map.get() is O(1)\n // This converts the O(n×m×s) findIndex operations to O(n×m)\n const symbolIndexMaps = this._symbolTable?.map((symbols) => {\n const map = new Map();\n symbols.forEach((symbol, idx) => {\n // Create a unique key for each symbol based on its values\n const key = `${symbol.intValue}|${symbol.doubleValue}|${symbol.stringValue}`;\n map.set(key, idx);\n });\n return map;\n });\n\n let processedRows = 0;\n const progressInterval = Math.max(1, Math.floor(numRows / 100)); // Report progress every 1%\n\n this._df.data.forEach((/** @type {any} */ row) => {\n // Convert the raw values to indices referring to the symbol table\n const indices = this._df.columns.map((/** @type {any} */ column, columnIndex) => {\n const value = row[columnIndex];\n const symbol = QvdFileWriter._convertRawToSymbol(value);\n const fieldContainsNull = this._symbolTableMetadata?.[columnIndex][2];\n\n // None values are represented by bias shifted negative indices\n if (symbol === null) {\n return 0;\n } else {\n // Use the Map for O(1) lookup instead of findIndex\n const key = `${symbol.intValue}|${symbol.doubleValue}|${symbol.stringValue}`;\n const symbolIndex = symbolIndexMaps?.[columnIndex].get(key);\n // In order to represent None values, the indices are shifted by the bias value of the column\n return fieldContainsNull ? (symbolIndex ?? 0) + 2 : (symbolIndex ?? 0);\n }\n });\n\n // Convert the integer indices to binary representation\n /** @type {string[]} */\n const stringIndices = indices.map((/** @type {number} */ index) => {\n const bits = QvdFileWriter._convertInt32ToBits(index, 32);\n let bitString = bits.join('');\n bitString = bitString.replace(/^0+/, '') || '0';\n return bitString;\n });\n\n // @ts-ignore - Index array type compatibility\n this._indexTable?.push(stringIndices);\n\n // Report progress periodically\n processedRows++;\n if (processedRows % progressInterval === 0 || processedRows === numRows) {\n this._emitProgress('index-table', processedRows, numRows);\n }\n });\n\n // Normalize the bit representation of the indices by padding with zeros\n this._df.columns.forEach((column, columnIndex) => {\n // Bit offset is the sum of the bit widths of all previous columns\n const bitOffset = this._indexTableMetadata?.slice(0, columnIndex).reduce((sum, metadata) => sum + metadata[1], 0);\n\n assert(this._indexTable, 'The QVD file header has not been parsed.');\n\n const fieldContainsNull = this._symbolTableMetadata?.[columnIndex][2];\n const bias = fieldContainsNull ? -2 : 0;\n\n // Bit width is derived from the number of symbols rather than by scanning every row.\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 it 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 symbolCount = this._symbolTable?.[columnIndex].length ?? 0;\n const maxStoredIndex = symbolCount === 0 ? 0 : symbolCount - 1 + (fieldContainsNull ? 2 : 0);\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 this._indexTableMetadata?.push([bitOffset, bitWidth, bias]);\n\n // Pad the bit representation of the indices with zeros to match the bit width.\n //\n // The assertion restores the self-correcting property of the old Math.max() approach,\n // which measured the actual bit strings and so absorbed any mismatch between the symbol\n // table and the indices built from it. Deriving the width instead makes such a mismatch\n // silent: padStart() never truncates, so an over-wide index would make the record wider\n // than BitWidth declares and misalign every field after it in every subsequent row.\n this._indexTable.forEach((/** @type{string[]} */ indices) => {\n const bitString = indices[columnIndex];\n // '0' is the stored index 0, which needs no bits and is written as an empty string\n // when bitWidth is 0; every other value must fit inside the derived width.\n assert(\n bitString === '0' || bitString.length <= bitWidth,\n `Stored index for column '${column}' needs ${bitString.length} bits, ` +\n `but BitWidth was derived as ${bitWidth} from ${symbolCount} symbols. ` +\n `The symbol table and the index table are out of sync.`,\n );\n indices[columnIndex] = bitWidth === 0 ? '' : bitString.padStart(bitWidth, '0');\n });\n });\n\n // Concatenate the bit representation of the indices of each row to a single binary string per row\n // @ts-ignore - Buffer.concat type compatibility\n this._indexBuffer = Buffer.concat(\n // @ts-ignore - Buffer array type compatibility\n this._indexTable.map((/** @type{string[]} */ indices) => {\n indices.reverse();\n const bits = indices.join('');\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,\n // and a zero-byte record would be rejected on read, so emit a single zero byte.\n if (bits.length === 0) {\n return Buffer.from(Uint8Array.from([0]));\n }\n\n const paddingWidth = (8 - (bits.length % 8)) % 8;\n const paddedBits = bits.padStart(bits.length + paddingWidth, '0');\n const bytes = paddedBits.match(/.{1,8}/g)?.map((byte) => parseInt(byte, 2));\n bytes?.reverse();\n\n assert(bytes, 'Byte conversion of bit indices failed.');\n\n return Buffer.from(Uint8Array.from(bytes));\n }),\n );\n\n // For empty data, set record byte size to 1 (matching Qlik Sense behavior)\n // instead of 0 or NaN/Infinity\n this._recordByteSize = this._indexTable.length > 0 ? this._indexBuffer.length / this._indexTable.length : 1;\n }\n\n /**\n * Converts a raw value/literal to a QVD symbol.\n *\n * @param {any} raw The raw value/literal to convert.\n * @return {QvdSymbol|null} The converted QVD symbol.\n */\n static _convertRawToSymbol(raw) {\n if (raw === null || raw === undefined) {\n return null;\n }\n\n const INT32_MIN = -2147483648;\n const INT32_MAX = 2147483647;\n\n const isInteger = typeof raw === 'number' && Number.isInteger(raw);\n const isFloat = typeof raw === 'number' && !Number.isInteger(raw);\n const isWithinInt32Range = typeof raw === 'number' && raw >= INT32_MIN && raw <= INT32_MAX;\n\n if (isInteger && isWithinInt32Range) {\n return QvdSymbol.fromDualIntValue(raw, raw.toString());\n } else if (isFloat || (isInteger && !isWithinInt32Range)) {\n return QvdSymbol.fromDualDoubleValue(raw, raw.toString());\n } else {\n return QvdSymbol.fromStringValue(raw);\n }\n }\n\n /**\n * Converts an integer to a list of bits.\n *\n * @param {number} value The integer value to convert.\n * @param {number} width The width of the bit list.\n * @return {Array<number>} The list of bits.\n */\n static _convertInt32ToBits(value, width) {\n return value\n .toString(2)\n .split('')\n .map((bit) => parseInt(bit))\n .reverse()\n .concat(new Array(width).fill(0))\n .slice(0, width)\n .reverse();\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\n/**\n * Converts a bit array to an integer value.\n *\n * @param {Array<number>} bits The bit array\n * @return {number} The integer value\n */\nexport function convertBitsToInt32(bits) {\n if (bits.length === 0) {\n return 0;\n }\n\n return bits.reduce((value, bit, index) => (value += bit * Math.pow(2, index)), 0);\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: getHeapLimit()});\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 * Estimates the memory usage for loading a QVD file with given parameters.\n * Takes into account Phase 2.5 optimization which skips parsing unused symbols.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @returns {number} Estimated memory usage in bytes\n */\nexport function estimateMemoryUsage(symbolTableSize, maxRows, totalRows) {\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 if (maxRows === null || maxRows >= totalRows) {\n // Loading all rows - need all symbols, no filtering benefit\n return symbolTableSize * FULL_PARSE_OVERHEAD;\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;\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.3] Fraction of the memory budget to use (0.0-1.0). Zero\n * disables the check entirely.\n * @throws {QvdValidationError} If insufficient memory is available\n */\nexport function validateMemoryAvailability(symbolTableSize, maxRows, totalRows, filePath, safetyFactor = 0.3) {\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 heapLimit = getHeapLimit();\n const availableMemory = budget.bytes;\n const estimatedMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows);\n const maxAllowedMemory = budget.bytes * safetyFactor;\n\n if (estimatedMemory > maxAllowedMemory) {\n // Calculate how many rows would be safe to load\n // Reverse the square root formula: symbolPercentage = sqrt(rowPercentage)\n const safeSymbolPercentage = maxAllowedMemory / (symbolTableSize * 6.0);\n const safeRowPercentage = Math.pow(safeSymbolPercentage, 2);\n const recommendedMaxRows = Math.max(1, Math.floor(totalRows * safeRowPercentage));\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 const heapLimitMB = 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 const limitingFactor = budget.limitedBy;\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 const advice =\n limitingFactor === 'container memory limit'\n ? `The binding limit is the container's, so raising --max-old-space-size would let V8 grow past it and be killed by the OOM killer instead. Set it below the container limit, raise the limit, or load fewer rows with maxRows (recommended: ${recommendedMaxRows.toLocaleString()} rows or less).`\n : `Try loading fewer rows using the maxRows parameter (recommended: ${recommendedMaxRows.toLocaleString()} rows or less), or raise the heap with --max-old-space-size.`;\n\n 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}; 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 availableRamMB,\n limitingFactor,\n memoryBudget: budget.candidates,\n memoryObserved: budget.observed,\n totalRows,\n maxRows,\n recommendedMaxRows,\n },\n );\n }\n}\n\n/**\n * Emits a warning for large symbol tables when loading all rows.\n * Warning threshold scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n */\nexport function warnLargeSymbolTable(symbolTableSize, maxRows, totalRows) {\n // Dynamic warning threshold: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n const heapLimit = getHeapLimit();\n const LARGE_SYMBOL_TABLE_WARNING = heapLimit * 0.125;\n\n if (symbolTableSize > LARGE_SYMBOL_TABLE_WARNING && (maxRows === null || maxRows >= totalRows)) {\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const warnMB = Math.round(LARGE_SYMBOL_TABLE_WARNING / 1024 / 1024);\n\n console.warn(\n `⚠️ Large symbol table detected (${sizeMB}MB > ${warnMB}MB threshold). Loading all ${totalRows.toLocaleString()} rows will use ~${estimatedMB}MB RAM. ` +\n `Consider using the maxRows parameter for better performance and lower memory usage.`,\n );\n }\n}\n","// @ts-check\n\nimport {QvdCorruptedError, QvdValidationError} from '../QvdErrors.js';\nimport {getHeapLimit} from './memoryUtils.js';\n\n/**\n * Validates symbol table size during initial file read (early check).\n * This is the first-pass validation in _readData for lazy loading.\n * Limit scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdValidationError} If symbol table exceeds dynamic limit\n */\nexport function validateSymbolTableSizeEarly(symbolTableLength, filePath) {\n // Dynamic limit: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n const heapLimit = getHeapLimit();\n const MAX_SYMBOL_TABLE_SIZE = heapLimit * 0.125;\n\n if (symbolTableLength > MAX_SYMBOL_TABLE_SIZE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(MAX_SYMBOL_TABLE_SIZE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table too large (${sizeMB}MB exceeds ${maxMB}MB limit for lazy loading). ` +\n `This QVD file contains extremely high-cardinality fields. ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 12.5% = ${maxMB}MB). ` +\n `Consider: (1) loading the full file without maxRows, (2) increasing heap size with --max-old-space-size, or (3) aggregating high-cardinality fields.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: MAX_SYMBOL_TABLE_SIZE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 12.5,\n },\n );\n }\n}\n\n/**\n * Validates symbol table size limits to prevent out-of-memory conditions.\n * This is the comprehensive validation in _parseSymbolTable.\n * Absolute ceiling scales with configured heap size (50% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} totalRows Total number of rows in the file\n * @throws {QvdValidationError} If symbol table exceeds safety limits\n */\nexport function validateSymbolTableSize(symbolTableLength, filePath, totalRows) {\n // Dynamic absolute ceiling: 50% of configured heap size\n // Examples: 4GB heap = 2GB, 8GB heap = 4GB, 16GB heap = 8GB, 32GB heap = 16GB\n const heapLimit = getHeapLimit();\n const ABSOLUTE_MAX_SYMBOL_TABLE = heapLimit * 0.5;\n\n if (symbolTableLength > ABSOLUTE_MAX_SYMBOL_TABLE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(ABSOLUTE_MAX_SYMBOL_TABLE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table exceeds absolute maximum size (${sizeMB}MB > ${maxMB}MB). ` +\n `This QVD file has pathological cardinality (likely a data modeling issue). ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 50% = ${maxMB}MB). ` +\n `Consider: (1) increasing heap size with --max-old-space-size, (2) aggregating high-cardinality fields, (3) splitting the data, or (4) using a different format.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: ABSOLUTE_MAX_SYMBOL_TABLE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 50,\n totalRows,\n },\n );\n }\n}\n\n/**\n * Validates field metadata before processing to prevent buffer overflow attacks.\n *\n * @param {any} field Field metadata object\n * @param {number} symbolBufferLength Length of the symbol buffer\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field metadata is invalid\n */\nexport function validateFieldMetadata(field, symbolBufferLength, filePath) {\n const symbolsOffset = parseInt(field['Offset'], 10);\n const symbolsLength = parseInt(field['Length'], 10);\n\n // Validate offset is a valid number and within bounds\n if (isNaN(symbolsOffset) || !Number.isSafeInteger(symbolsOffset) || symbolsOffset < 0) {\n throw new QvdCorruptedError('Invalid symbol offset', {\n field: field['FieldName'],\n offset: symbolsOffset,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate length is a valid number and non-negative\n if (isNaN(symbolsLength) || !Number.isSafeInteger(symbolsLength) || symbolsLength < 0) {\n throw new QvdCorruptedError('Invalid symbol length', {\n field: field['FieldName'],\n length: symbolsLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate that offset + length doesn't exceed buffer size\n if (symbolsOffset + symbolsLength > symbolBufferLength) {\n throw new QvdCorruptedError('Symbol data extends beyond buffer', {\n field: field['FieldName'],\n offset: symbolsOffset,\n length: symbolsLength,\n bufferSize: symbolBufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n}\n\n/**\n * Validates index table metadata and bounds.\n *\n * @param {number} recordSize Size of a single record in bytes\n * @param {number} totalRows Total number of rows\n * @param {number} indexTableLength Length of the index table\n * @param {number} indexTableOffset Offset to the index table\n * @param {number} bufferLength Length of the buffer\n * @param {number} rowsToLoad Number of rows to load\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number|null} [fileSize] Actual size of the file on disk, when known. Used to detect a\n * header that describes more data than the file contains.\n * @throws {QvdCorruptedError} If index table metadata is invalid\n */\nexport function validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n indexTableOffset,\n bufferLength,\n rowsToLoad,\n filePath,\n fileSize = null,\n) {\n // Validate recordSize\n if (isNaN(recordSize) || !Number.isSafeInteger(recordSize) || recordSize < 0) {\n throw new QvdCorruptedError('Invalid record byte size', {\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate totalRows\n if (isNaN(totalRows) || !Number.isSafeInteger(totalRows) || totalRows < 0) {\n throw new QvdCorruptedError('Invalid number of records', {\n totalRows,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Allow recordSize of 0 or 1 only when there are no records (empty QVD)\n // Qlik Sense uses recordSize=1 for empty QVDs\n if (recordSize === 0 && totalRows > 0) {\n throw new QvdCorruptedError('Record byte size cannot be zero when records exist', {\n recordSize,\n totalRows,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate recordSize is reasonable (max 1MB per record)\n if (recordSize > 1048576) {\n throw new QvdCorruptedError('Record byte size exceeds maximum', {\n recordSize,\n maxSize: 1048576,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table length\n if (isNaN(indexTableLength) || !Number.isSafeInteger(indexTableLength) || indexTableLength < 0) {\n throw new QvdCorruptedError('Invalid index table length', {\n length: indexTableLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table start offset doesn't extend beyond buffer\n if (indexTableOffset > bufferLength) {\n throw new QvdCorruptedError('Index table offset beyond buffer', {\n indexTableOffset,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // The index table must be exactly as long as the record count implies. Every QVD produced by\n // Qlik or by this library satisfies this, so a mismatch means the header is inconsistent.\n // Checking it catches corrupt headers that would otherwise decode misaligned rows.\n if (indexTableLength !== totalRows * recordSize) {\n throw new QvdCorruptedError('Index table length inconsistent with record count', {\n indexTableLength,\n expectedLength: totalRows * recordSize,\n totalRows,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate the index table against the actual file when its size is known.\n //\n // Comparing against the in-memory buffer instead is wrong in both directions: during a lazy\n // load the buffer is deliberately truncated, so valid large files were rejected as corrupt,\n // while a truncated file whose header claims more data was accepted and silently returned\n // fewer rows than the header declares.\n if (fileSize !== null) {\n if (indexTableOffset + indexTableLength > fileSize) {\n throw new QvdCorruptedError('Index table extends beyond the end of the file', {\n indexTableOffset,\n indexTableLength,\n fileSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n }\n\n // Ensure the loaded buffer actually holds the rows we were asked to parse.\n const requiredIndexBytes = rowsToLoad * recordSize;\n if (indexTableOffset + requiredIndexBytes > bufferLength) {\n throw new QvdCorruptedError('Index table truncated', {\n indexTableOffset,\n requiredBytes: requiredIndexBytes,\n availableBytes: Math.max(0, bufferLength - indexTableOffset),\n rowsToLoad,\n recordSize,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Ensure the index table length is sufficient for the number of rows to load\n if (indexTableLength < requiredIndexBytes) {\n throw new QvdCorruptedError('Index table length smaller than required', {\n indexTableLength,\n requiredBytes: requiredIndexBytes,\n rowsToLoad,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n\n/**\n * Validates field bit offset and bit width for index table parsing.\n *\n * @param {any} field Field metadata object\n * @param {number} recordSize Size of a single record in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field bit metadata is invalid\n */\nexport function validateFieldBitMetadata(field, recordSize, filePath) {\n const bitOffset = parseInt(field['BitOffset'], 10);\n const bitWidth = parseInt(field['BitWidth'], 10);\n\n // Validate bitOffset\n if (isNaN(bitOffset) || !Number.isSafeInteger(bitOffset) || bitOffset < 0) {\n throw new QvdCorruptedError('Invalid bit offset', {\n field: field['FieldName'],\n bitOffset,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth\n if (isNaN(bitWidth) || !Number.isSafeInteger(bitWidth) || bitWidth < 0) {\n throw new QvdCorruptedError('Invalid bit width', {\n field: field['FieldName'],\n bitWidth,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitOffset + bitWidth doesn't exceed record size in bits\n const recordSizeInBits = recordSize * 8;\n if (bitOffset + bitWidth > recordSizeInBits) {\n throw new QvdCorruptedError('Bit field extends beyond record size', {\n field: field['FieldName'],\n bitOffset,\n bitWidth,\n recordSizeInBits,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n","// @ts-check\n\nimport {QvdSymbol} from '../QvdSymbol.js';\nimport {QvdCorruptedError, QvdParseError} from '../QvdErrors.js';\n\n/**\n * Parses an integer symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for an integer\n if (pointer + 4 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading integer symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const byteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 4));\n const value = Buffer.from(byteData).readIntLE(0, byteData.length);\n return {symbol: QvdSymbol.fromIntValue(value), bytesRead: 4};\n}\n\n/**\n * Parses a double symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for a double\n if (pointer + 8 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading double symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const byteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 8));\n const value = Buffer.from(byteData).readDoubleLE(0);\n return {symbol: QvdSymbol.fromDoubleValue(value), bytesRead: 8};\n}\n\n/**\n * Parses a string symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n const startPointer = pointer;\n const maxStringLength = 1048576; // 1MB max string size to prevent memory exhaustion\n let stringLength = 0;\n\n // Find the null terminator\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('String symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n // Ensure we found the null terminator\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('String symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const value = symbolBuffer.subarray(startPointer, pointer).toString('utf-8');\n return {symbol: QvdSymbol.fromStringValue(value), bytesRead: pointer - startPointer + 1};\n}\n\n/**\n * Skips a string symbol in the buffer without parsing it.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {number} Bytes to skip\n */\nexport function skipStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n const startPointer = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('String symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('String symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return pointer - startPointer + 1;\n}\n\n/**\n * Parses a dual integer symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDualIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for an integer\n if (pointer + 4 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading dual integer symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const intByteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 4));\n const intValue = Buffer.from(intByteData).readIntLE(0, intByteData.length);\n pointer += 4;\n\n // Parse the string portion\n const stringStart = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const stringValue = symbolBuffer.subarray(stringStart, pointer).toString('utf-8');\n return {symbol: QvdSymbol.fromDualIntValue(intValue, stringValue), bytesRead: pointer - (stringStart - 4) + 1};\n}\n\n/**\n * Parses a dual double symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDualDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for a double\n if (pointer + 8 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading dual double symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const doubleByteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 8));\n const doubleValue = Buffer.from(doubleByteData).readDoubleLE(0);\n pointer += 8;\n\n // Parse the string portion\n const stringStart = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const stringValue = symbolBuffer.subarray(stringStart, pointer).toString('utf-8');\n return {\n symbol: QvdSymbol.fromDualDoubleValue(doubleValue, stringValue),\n bytesRead: pointer - (stringStart - 8) + 1,\n };\n}\n\n/**\n * Skips a dual symbol (integer or double) in the buffer without parsing it.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {number} numericBytes Number of bytes for the numeric portion (4 for int, 8 for double)\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {number} Bytes to skip\n */\nexport function skipDualSymbol(symbolBuffer, pointer, bufferLength, numericBytes, fieldName, filePath) {\n if (pointer + numericBytes > bufferLength) {\n throw new QvdCorruptedError(`Buffer overflow reading dual symbol`, {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const startPointer = pointer;\n pointer += numericBytes;\n\n // Skip the string portion\n const maxStringLength = 1048576;\n let stringLength = 0;\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return pointer - startPointer + 1;\n}\n\n/**\n * Parses a symbol based on the type byte.\n *\n * @param {number} typeByte The type byte\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position (after type byte)\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {boolean} shouldParse Whether to parse the symbol (true) or skip it (false)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol (or null if skipped) and bytes read\n */\nexport function parseSymbol(typeByte, symbolBuffer, pointer, bufferLength, fieldName, filePath, shouldParse) {\n switch (typeByte) {\n case 1: {\n // Integer value (4 Bytes)\n if (shouldParse) {\n return parseIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n return {symbol: null, bytesRead: 4};\n }\n case 2: {\n // Double value (8 Bytes)\n if (shouldParse) {\n return parseDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n return {symbol: null, bytesRead: 8};\n }\n case 4: {\n // String value (0 terminated)\n if (shouldParse) {\n return parseStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n case 5: {\n // Dual (Integer format) value (4 bytes), followed by string format\n if (shouldParse) {\n return parseDualIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipDualSymbol(symbolBuffer, pointer, bufferLength, 4, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n case 6: {\n // Dual (Double format) value (8 bytes), followed by string format\n if (shouldParse) {\n return parseDualDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipDualSymbol(symbolBuffer, pointer, bufferLength, 8, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n default: {\n throw new QvdParseError('Unknown symbol type byte', {\n typeByte: typeByte.toString(16),\n offset: pointer - 1,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport xml from 'xml2js';\nimport assert from 'assert';\nimport {QvdDataFrame} from './QvdDataFrame.js';\nimport {QvdParseError, QvdValidationError, QvdCorruptedError} from './QvdErrors.js';\nimport {validatePath} from './util/validatePath.js';\nimport {convertBitsToInt32} from './util/bitUtils.js';\nimport {estimateMemoryUsage, validateMemoryAvailability, warnLargeSymbolTable} from './util/memoryUtils.js';\nimport {\n validateSymbolTableSize,\n validateSymbolTableSizeEarly,\n validateFieldMetadata,\n validateIndexTableMetadata,\n validateFieldBitMetadata,\n} from './util/validationUtils.js';\nimport {parseSymbol} from './util/symbolParser.js';\n\n/**\n * Maximum number of bytes searched for the XML header delimiter before giving up.\n * Real QVD headers are a few kilobytes; the largest observed is well under 100KB.\n */\nconst MAX_HEADER_SIZE = 16 * 1024 * 1024;\n\n/**\n * Maximum length of a single fs.read call. Node's fs.read binding requires the length to fit\n * in an Int32: a larger value aborts the process via a C++ assertion instead of throwing.\n */\nconst READ_CHUNK_SIZE = 512 * 1024 * 1024;\n\n/**\n * Parses a QVD file and loads it into memory.\n */\nexport class QvdFileReader {\n /**\n * Constructs a new QVD file parser.\n *\n * @param {string} filePath The path to the QVD file to load.\n * @param {Object} [options={}] Options for the reader.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.3] Fraction (0.0-1.0) of the memory budget a\n * load may use. The budget is the smallest of the V8 heap limit, any container memory limit,\n * and the memory the OS reports as available. Default is 0.3. **Zero disables the memory\n * check entirely**, which is the escape hatch for runtimes whose limits cannot be measured -\n * Bun reports its current heap as its heap limit - and for callers who would rather manage\n * memory themselves than trust the estimate.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes,\n * above which a lazy load switches to the two-pass filtering path. The default of 50MB is\n * the point where the extra analysis pass pays for itself; lower it to use filtering on\n * smaller files, raise it to keep the simpler single-pass read for longer.\n */\n constructor(filePath, options = {}) {\n const {allowedDir, memorySafetyFactor = 0.3, symbolFilteringThreshold = 50 * 1024 * 1024} = options;\n this._path = validatePath(filePath, allowedDir);\n this._memorySafetyFactor = memorySafetyFactor;\n this._symbolFilteringThreshold = symbolFilteringThreshold;\n this._buffer = null;\n this._headerOffset = null;\n this._symbolTableOffset = null;\n this._indexTableOffset = null;\n this._header = null;\n /** @type {Array<Array<import('./QvdSymbol.js').QvdSymbol>>|null} */\n this._symbolTable = null;\n /** @type {Array<Array<number>>|null} */\n this._indexTable = null;\n /** @type {number|null} */\n this._fileSize = null;\n }\n\n /**\n * Reads the binary data of the QVD file.\n *\n * LAZY LOADING OPTIMIZATION: When maxRows is specified, this method implements\n * true lazy loading by reading only the necessary portions of the file from disk.\n *\n * For large files (e.g., 5GB), loading only the first 1000 rows can save significant\n * memory and time:\n * - Full load: 5GB in memory, ~30-60s load time\n * - Lazy load (maxRows=1000): ~1.75-2GB in memory, ~2-5s load time\n *\n * Algorithm for Lazy Loading:\n * 1. Stream-read the file until XML header delimiter is found\n * 2. Parse header to determine symbol table and index table locations\n * 3. Calculate bytes needed: header + full symbol table + partial index table\n * 4. Read only those calculated bytes using fs.open/read\n * 5. Rest of parsing proceeds normally with limited data\n *\n * WHY THIS APPROACH:\n * - Symbol table must be fully loaded (contains all unique values)\n * - Index table can be partially loaded (only rows we need)\n * - Streaming for header finding is efficient for unknown header sizes\n * - Direct byte-range reading for remaining data is fastest\n *\n * @param {number|null} maxRows The maximum number of rows to load. If null, all data is loaded.\n * @private\n */\n async _readData(maxRows = null) {\n if (maxRows === null) {\n // Load entire file into memory (original behavior)\n // This is simple and fast for small to medium files\n this._buffer = await fs.promises.readFile(this._path);\n this._fileSize = this._buffer.length;\n return;\n }\n\n const 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 headerBuffer = Buffer.alloc(0);\n let headerDelimiterIndex = -1;\n\n try {\n // Read chunks until we find the delimiter.\n //\n // Chunks are collected and concatenated once, and each chunk is searched individually\n // (with a small carry-over so a delimiter straddling a chunk boundary is still found).\n // Concatenating the whole accumulated buffer on every chunk and re-scanning it from the\n // start is quadratic: a 200 MB delimiter-less file cost 43 s and 13 GB of memory.\n for await (const chunk of stream) {\n // Search the new chunk prefixed by the bytes already seen, so a delimiter spanning a\n // chunk boundary is not missed.\n //\n // The carry is kept in `tail` across iterations rather than read back off the previous\n // chunk, because a chunk may be shorter than the delimiter. Taking min(bytesSoFar, 2)\n // bytes from a 1-byte previous chunk yields only 1 byte, which both misses a delimiter\n // spread over three chunks and leaves the reported offset short by the difference.\n const chunkStart = headerBytes;\n const searchBuffer = tail.length > 0 ? Buffer.concat([tail, chunk]) : chunk;\n const foundInSearch = searchBuffer.indexOf(HEADER_DELIMITER);\n\n headerChunks.push(chunk);\n headerBytes += chunk.length;\n\n if (foundInSearch !== -1) {\n // searchBuffer starts tail.length bytes before this chunk does.\n headerDelimiterIndex = chunkStart - tail.length + foundInSearch;\n stream.destroy();\n break;\n }\n\n // Copy the carry instead of keeping a subarray view, which would pin the whole chunk.\n tail = Buffer.from(searchBuffer.subarray(-(HEADER_DELIMITER.length - 1)));\n\n // Real QVD headers are a few kilobytes. Without a cap, a non-QVD or corrupt file is\n // read to its end before the error below is raised, which is a denial-of-service\n // vector for any service that accepts uploaded files.\n if (headerBytes > MAX_HEADER_SIZE) {\n stream.destroy();\n throw new QvdCorruptedError(\n `The XML header delimiter was not found within the first ${MAX_HEADER_SIZE / (1024 * 1024)}MB of the file.`,\n {\n file: this._path,\n bytesSearched: headerBytes,\n maxHeaderSize: MAX_HEADER_SIZE,\n stage: 'readData',\n },\n );\n }\n }\n } catch (error) {\n // Destroying the stream once the delimiter is found surfaces as ERR_STREAM_PREMATURE_CLOSE.\n // That one case is expected and ignored; everything else must propagate.\n //\n // The previous condition also required a 'code' property, so any error without one — a\n // TypeError or RangeError raised in the loop body, or a stream error from a source that\n // does not set a code — was swallowed. Execution then fell through to the generic\n // 'header not properly delimited' error below, reporting file corruption for what was\n // actually a bug or an I/O failure.\n const isExpectedEarlyClose =\n headerDelimiterIndex !== -1 &&\n error !== null &&\n typeof error === 'object' &&\n /** @type {{code?: unknown}} */ (error).code === 'ERR_STREAM_PREMATURE_CLOSE';\n\n if (!isExpectedEarlyClose) {\n throw error;\n }\n }\n\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'readData',\n },\n );\n }\n\n headerBuffer = Buffer.concat(headerChunks);\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n\n // Parse header to get metadata about symbol and index table locations\n const headerXml = headerBuffer.subarray(0, headerEndIndex).toString();\n const headerObj = await xml.parseStringPromise(headerXml, {explicitArray: false});\n\n if (!headerObj) {\n throw new QvdParseError('The XML header could not be parsed.', {\n file: this._path,\n stage: 'readData',\n });\n }\n\n const symbolTableOffset = headerEndIndex;\n const symbolTableLength = parseInt(headerObj['QvdTableHeader']['Offset'], 10);\n const indexTableOffset = symbolTableOffset + symbolTableLength;\n const recordSize = parseInt(headerObj['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(headerObj['QvdTableHeader']['NoOfRecords'], 10);\n const rowsToLoad = Math.min(maxRows, totalRows);\n\n // SAFETY CHECK: Very large symbol tables (>500MB) are still blocked to prevent OOM\n // Phase 2 filtering can handle up to ~500MB symbol tables efficiently\n validateSymbolTableSizeEarly(symbolTableLength, this._path);\n\n // Validate the header numbers before they are used to size an allocation. Without this,\n // a NaN or negative value reaches Buffer.alloc and surfaces as a raw Node RangeError.\n for (const [name, value] of [\n ['Offset', symbolTableLength],\n ['RecordByteSize', recordSize],\n ['NoOfRecords', totalRows],\n ]) {\n if (!Number.isSafeInteger(value) || Number(value) < 0) {\n throw new QvdCorruptedError(`Invalid header value: ${name}`, {\n name,\n value,\n file: this._path,\n stage: 'readData',\n });\n }\n }\n\n // Calculate how much of the index table we need to read\n const indexTableBytesToRead = rowsToLoad * recordSize;\n\n // Calculate total bytes needed: header + symbol table + partial index table\n const totalBytesToRead = indexTableOffset + indexTableBytesToRead;\n\n // Now read the exact portion we need from the file\n const fd = await fs.promises.open(this._path, 'r');\n try {\n const {size: fileSize} = await fd.stat();\n this._fileSize = fileSize;\n\n // The buffer size is derived entirely from header values, which may not describe the\n // file on disk (truncated download, interrupted copy, file still being written, or a\n // deliberately crafted header). Reading past the end would otherwise leave the tail of\n // the buffer holding whatever memory the allocator handed out, and that memory is then\n // parsed as symbol and index data.\n if (totalBytesToRead > fileSize) {\n throw new QvdCorruptedError('The file is shorter than its header claims.', {\n file: this._path,\n fileSize,\n requiredBytes: totalBytesToRead,\n stage: 'readData',\n });\n }\n\n // Zero-filled rather than allocUnsafe: if any path ever fails to overwrite part of this\n // buffer, the result is zeros instead of leaked process memory.\n this._buffer = Buffer.alloc(totalBytesToRead);\n\n // Read in bounded chunks, checking bytesRead each time. A single fs.read call with a\n // length of 2^31 or more does not throw - it trips a C++ assertion and aborts the whole\n // process, which no try/catch can intercept.\n let position = 0;\n while (position < totalBytesToRead) {\n const length = Math.min(READ_CHUNK_SIZE, totalBytesToRead - position);\n // @ts-ignore - Buffer type compatibility\n const {bytesRead} = await fd.read(this._buffer, position, length, position);\n\n if (bytesRead === 0) {\n throw new QvdCorruptedError('Unexpected end of file while reading QVD data.', {\n file: this._path,\n fileSize,\n bytesRead: position,\n requiredBytes: totalBytesToRead,\n stage: 'readData',\n });\n }\n\n position += bytesRead;\n }\n } finally {\n await fd.close();\n }\n }\n\n /**\n * Parses the XML header of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n */\n async _parseHeader() {\n if (!this._buffer) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const HEADER_DELIMITER = '\\r\\n\\0';\n\n const headerBeginIndex = 0;\n const headerDelimiterIndex = this._buffer.indexOf(HEADER_DELIMITER, headerBeginIndex);\n\n // Check explicitly for -1 (not found) rather than using falsy check (!headerDelimiterIndex)\n // because indexOf() returns 0 when the delimiter is at position 0, which is a valid buffer index.\n // Using !0 would incorrectly treat position 0 as an error.\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n const headerBuffer = this._buffer.subarray(headerBeginIndex, headerEndIndex);\n\n /*\n * The following instruction parses the XML header into a JSON object. It is important to\n * note that the object is a plain JavaScript object and not an instance of representative\n * class. Hence, types are not casted, therefore all raw values are strings, and child nodes\n * that contain an array of objects are not represented directly as an array but as an object\n * with a property, named like the array item tag, that is an array of the actual objects. The\n * same applies to child nodes that contain a single object and the root node.\n *\n * The following XML representation of the QVD header for example...\n *\n * <QvdTableHeader>\n * ...\n * <Fields>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * </Fields>\n * </QvdTableHeader>\n *\n * ...is parsed into the following object:\n *\n * {\n * QvdTableHeader: {\n * ...,\n * Fields: {\n * QvdFieldHeader: [\n * { FieldName: 'Field1', ...},\n * { FieldName: 'Field2', ...}\n * ]\n * }\n * }\n * }\n */\n\n // Note: xml2js (via sax-js) does not support external entity resolution\n // by default, providing inherent protection against XXE attacks.\n this._header = await xml.parseStringPromise(headerBuffer.toString(), {explicitArray: false});\n\n if (!this._header) {\n throw new QvdParseError('The XML header could not be parsed.', {\n file: this._path,\n stage: 'parseHeader',\n });\n }\n\n /*\n * Because the three parts of the QVD file, header, symbol and index table, are seamlessly concatenated,\n * the end of the respective previous part is the beginning of the next part.\n */\n\n this._headerOffset = headerBeginIndex;\n this._symbolTableOffset = headerEndIndex;\n this._indexTableOffset = this._symbolTableOffset + parseInt(this._header['QvdTableHeader']['Offset'], 10);\n }\n\n /**\n * Estimates the memory usage for loading a QVD file with given parameters.\n * Takes into account Phase 2.5 optimization which skips parsing unused symbols.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @returns {number} Estimated memory usage in bytes\n * @private\n */\n _estimateMemoryUsage(symbolTableSize, maxRows, totalRows) {\n return estimateMemoryUsage(symbolTableSize, maxRows, totalRows);\n }\n\n /**\n * Analyzes the index table to determine which symbols are actually needed.\n * This is used for two-pass symbol filtering optimization.\n *\n * @param {number} maxRows The maximum number of rows to analyze.\n * @returns {Promise<Map<string, Set<number>>>} Map of field names to Set of needed symbol indices.\n * @private\n */\n async _analyzeIndexTableSymbolUsage(maxRows) {\n if (!this._buffer || !this._header || !this._indexTableOffset) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'analyzeIndexTableSymbolUsage',\n },\n );\n }\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const recordSize = parseInt(this._header['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n const rowsToAnalyze = Math.min(maxRows, totalRows);\n const indexTableLength = parseInt(this._header['QvdTableHeader']['Length'], 10);\n\n const indexBuffer = this._buffer.subarray(this._indexTableOffset, this._indexTableOffset + indexTableLength + 1);\n\n // Map of field name -> Set of symbol indices needed\n /** @type {Map<string, Set<number>>} */\n const symbolUsage = new Map();\n\n // Initialize sets for each field\n fields.forEach((field) => {\n symbolUsage.set(field['FieldName'], new Set());\n });\n\n // Parse rows to collect symbol indices\n for (\n let pointer = 0, rowCount = 0;\n pointer < indexBuffer.length && rowCount < rowsToAnalyze;\n pointer += recordSize, rowCount++\n ) {\n const bytes = new Int32Array(indexBuffer.subarray(pointer, pointer + recordSize));\n bytes.reverse();\n\n const mask = bytes\n .reduce((bits, byte) => bits + ('00000000' + byte.toString(2)).slice(-8), '')\n .split('')\n .reverse()\n .map((bit) => parseInt(bit));\n\n // Extract symbol index for each field\n fields.forEach((field) => {\n const bitOffset = parseInt(field['BitOffset'], 10);\n const bitWidth = parseInt(field['BitWidth'], 10);\n const bias = parseInt(field['Bias'], 10);\n\n let symbolIndex;\n\n if (bitWidth === 0) {\n symbolIndex = 0;\n } else {\n symbolIndex = this._convertBitsToInt32(mask.slice(bitOffset, bitOffset + bitWidth));\n }\n\n // Apply bias. This MUST use the same sign as _parseIndexTable (which adds the bias),\n // otherwise the symbols recorded as \"needed\" here are not the ones the parse pass\n // looks up, and every affected cell silently reads back as undefined. Qlik encodes\n // nullable fields with Bias=-2, so getting this wrong corrupts every nullable column.\n symbolIndex += bias;\n\n // Negative indices denote NULL and reference no symbol, so they never need to be kept.\n if (symbolIndex < 0) {\n return;\n }\n\n // Add to the set of needed symbols for this field\n const fieldName = field['FieldName'];\n symbolUsage.get(fieldName)?.add(symbolIndex);\n });\n }\n\n return symbolUsage;\n }\n\n /**\n * Parses the symbol table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * @param {Map<string, Set<number>>|null} symbolsToKeep Optional map of field names to symbol indices to keep.\n * If provided, only these symbols will be parsed (two-pass filtering optimization).\n * @param {number|null} maxRows Optional maximum number of rows being loaded (for memory estimation).\n */\n async _parseSymbolTable(symbolsToKeep = null, maxRows = null) {\n if (!this._buffer || !this._header || !this._symbolTableOffset || !this._indexTableOffset) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseSymbolTable',\n },\n );\n }\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n const symbolBuffer = this._buffer.subarray(this._symbolTableOffset, this._indexTableOffset);\n const symbolTableSize = symbolBuffer.length;\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n\n // SAFETY CHECK 1: Absolute ceiling to prevent pathological cases\n // Phase 2.5 optimization allows much larger symbol tables when using maxRows,\n // but we still need an absolute maximum to prevent truly extreme cases\n validateSymbolTableSize(symbolTableSize, this._path, totalRows);\n\n // SAFETY CHECK 2: Dynamic memory validation\n // Check if we have enough available memory to load this file safely\n validateMemoryAvailability(symbolTableSize, maxRows, totalRows, this._path, this._memorySafetyFactor);\n\n // WARNING ZONE: Large files without maxRows parameter\n // Educate users about best practices but don't block\n warnLargeSymbolTable(symbolTableSize, maxRows, totalRows);\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n /*\n * The symbol table is a contiguous byte array that contains all possible symbols/values of all fields/columns.\n * The symbols/values of one field are stored consecutively in the same order as the fields/columns are defined\n * in the header. The length of the symbol area as well as it's offset, relativ to the begin of the symbol\n * table, are also defined in the header.\n */\n\n // Validate all field metadata before processing to prevent buffer overflow attacks\n for (const field of fields) {\n validateFieldMetadata(field, symbolBuffer.length, this._path);\n }\n\n // Parse all possible symbols of each field/column\n // Phase 2.5 optimization: Skip parsing entirely for symbols we don't need\n this._symbolTable = fields.map((/** @type {any} */ field) => {\n const symbolsOffset = parseInt(field['Offset'], 10); // Offset of the column's symbol area in the symbol table\n const symbolsLength = parseInt(field['Length'], 10); // Length of the column's symbol area in the symbol table\n\n const fieldName = field['FieldName'];\n const neededSymbols = symbolsToKeep ? symbolsToKeep.get(fieldName) : null;\n const filteringEnabled = neededSymbols !== null;\n\n const symbols = [];\n let symbolIndex = 0; // Track current symbol index as we parse\n\n // Parse all possible values of the current field/column\n for (let pointer = symbolsOffset; pointer < symbolsOffset + symbolsLength; pointer++) {\n // Each stored symbol consists of a type byte and the actual value, which length depends on the type\n const typeByte = symbolBuffer[pointer++];\n\n // Check if we should keep this symbol (filtering mode)\n const shouldKeepSymbol = !filteringEnabled || !!(neededSymbols && neededSymbols.has(symbolIndex));\n\n // Use utility function to parse or skip symbol\n const {symbol, bytesRead} = parseSymbol(\n typeByte,\n symbolBuffer,\n pointer,\n symbolBuffer.length,\n fieldName,\n this._path,\n shouldKeepSymbol,\n );\n\n symbols.push(symbol);\n pointer += bytesRead - 1; // -1 because the loop will increment\n symbolIndex++;\n }\n\n return symbols;\n // @ts-ignore - Symbol table type assignment\n });\n }\n\n /**\n * Utility method to convert a bit array to an integer value.\n *\n * @param {Array<number>} bits The bit array\n * @return {Number} The integer value\n */\n _convertBitsToInt32(bits) {\n return convertBitsToInt32(bits);\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 * @param {number|null} maxRows The maximum number of rows to parse. If null, all rows are parsed.\n */\n async _parseIndexTable(maxRows = null) {\n if (!this._buffer || !this._header || !this._indexTableOffset) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseIndexTable',\n },\n );\n }\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n // Size of a single row of the index table in bytes\n const recordSize = parseInt(this._header['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n const rowsToLoad = maxRows !== null ? Math.min(maxRows, totalRows) : totalRows;\n const indexTableLength = parseInt(this._header['QvdTableHeader']['Length'], 10);\n\n // Validate all index table metadata\n validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n this._indexTableOffset,\n this._buffer.length,\n rowsToLoad,\n this._path,\n this._fileSize,\n );\n\n const indexBuffer = this._buffer.subarray(this._indexTableOffset, this._indexTableOffset + indexTableLength + 1);\n\n // Validate BitOffset and BitWidth for all fields before processing\n for (const field of fields) {\n validateFieldBitMetadata(field, recordSize, this._path);\n }\n\n this._indexTable = [];\n\n // Parse rows of the index table, each row contains the indices of the symbol table for each field/column\n for (\n let pointer = 0, rowCount = 0;\n pointer < indexBuffer.length && rowCount < rowsToLoad;\n pointer += recordSize, rowCount++\n ) {\n // Validate we have enough bytes for this record\n if (pointer + recordSize > indexBuffer.length) {\n throw new QvdCorruptedError('Buffer overflow reading index table record', {\n pointer,\n recordSize,\n bufferSize: indexBuffer.length,\n file: this._path,\n stage: 'parseIndexTable',\n });\n }\n\n const bytes = new Int32Array(indexBuffer.subarray(pointer, pointer + recordSize));\n bytes.reverse();\n\n // The bit mask contains the bit stuffed indices of the symbol table of the current row\n const mask = bytes\n .reduce((bits, byte) => bits + ('00000000' + byte.toString(2)).slice(-8), '')\n .split('')\n .reverse()\n .map((bit) => parseInt(bit));\n\n /** @type {number[]} */\n const symbolIndices = [];\n\n // Extract the index from the current row's bit mask for each field/column\n fields.forEach((/** @type {any} */ field) => {\n const bitOffset = parseInt(field['BitOffset'], 10);\n const bitWidth = parseInt(field['BitWidth'], 10);\n const bias = parseInt(field['Bias'], 10);\n\n let symbolIndex;\n\n if (bitWidth === 0) {\n symbolIndex = 0;\n } else {\n symbolIndex = this._convertBitsToInt32(mask.slice(bitOffset, bitOffset + bitWidth));\n }\n\n symbolIndex += bias;\n symbolIndices.push(symbolIndex);\n });\n\n this._indexTable.push(symbolIndices);\n }\n\n // The loop is bounded by the buffer as well as by rowsToLoad, so a short buffer would\n // otherwise silently yield fewer rows than the header declares.\n if (this._indexTable.length !== rowsToLoad) {\n throw new QvdCorruptedError('Index table contains fewer records than expected', {\n expectedRows: rowsToLoad,\n actualRows: this._indexTable.length,\n totalRows,\n recordSize,\n file: this._path,\n stage: 'parseIndexTable',\n });\n }\n }\n\n /**\n * Loads the QVD file into memory and parses it.\n *\n * @param {number|null} maxRows The maximum number of rows to load. If null, all rows are loaded.\n * Must be a non-negative integer when given.\n * @throws {QvdValidationError} If maxRows is neither null nor a non-negative integer.\n * @return {Promise<QvdDataFrame>} The loaded QVD file.\n */\n async load(maxRows = null) {\n // Validate before any I/O. Every downstream use is Math.min(maxRows, totalRows), which\n // silently accepts nonsense: a negative value yields a negative row count, NaN makes every\n // comparison false, and a fractional value produces a fractional loop bound. Each of those\n // returns a wrong or empty data frame rather than an error, so reject them up front.\n // undefined never reaches here: the default parameter above turns it into null.\n if (maxRows !== null && (typeof maxRows !== 'number' || !Number.isInteger(maxRows) || maxRows < 0)) {\n throw new QvdValidationError('maxRows must be a non-negative integer, or null to load all rows', {\n provided: maxRows,\n type: typeof maxRows,\n file: this._path,\n });\n }\n\n await this._readData(maxRows);\n await this._parseHeader();\n\n // Determine if we should use two-pass symbol filtering\n // This optimization is beneficial for large symbol tables with limited row access\n let symbolsToKeep = null;\n let symbolsKept = null;\n\n if (maxRows !== null && this._header) {\n const symbolTableLength = parseInt(this._header['QvdTableHeader']['Offset'], 10);\n\n // Use two-pass filtering for symbol tables above the threshold when loading limited rows.\n // The threshold is an option rather than a constant so this path can be exercised with a\n // small fixture: it is the most intricate code in the reader, and the only files large\n // enough to reach the 50MB default are ones no repository should be carrying around.\n if (symbolTableLength > this._symbolFilteringThreshold) {\n // Pass 1: Analyze which symbols are actually needed\n symbolsToKeep = await this._analyzeIndexTableSymbolUsage(maxRows);\n\n // Recorded rather than logged. This used to be a console.log, which a library has no\n // business emitting: callers could not silence it, and it was the only way to find out\n // whether filtering had happened. It is now reported through QvdDataFrame.loadStats,\n // which callers can inspect - and tests can assert on deterministically, where the\n // previous test measured a heapUsed delta and failed on GC timing instead.\n symbolsKept = Array.from(symbolsToKeep.values()).reduce((sum, set) => sum + set.size, 0);\n }\n }\n\n // Pass 2: Parse symbol table (with filtering if enabled)\n await this._parseSymbolTable(symbolsToKeep, maxRows);\n await this._parseIndexTable(maxRows);\n\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolTable, 'The QVD file symbol table has not been parsed.');\n assert(this._indexTable, 'The QVD file index table has not been parsed.');\n\n /**\n * Retrieves the values of a specific row of the QVD file. Values are in the same order\n * as the field names.\n *\n * @param {number} index The index of the row.\n * @return {Array<any>} The values of the row.\n */\n const getRow = (index) => {\n if (!this._indexTable || index >= this._indexTable.length) {\n throw new QvdValidationError('Row index out of bounds', {\n index,\n max: this._indexTable ? this._indexTable.length - 1 : -1,\n file: this._path,\n });\n }\n\n return this._indexTable?.[index].map((/** @type {number} */ symbolIndex, /** @type {number} */ fieldIndex) => {\n if (symbolIndex < 0) {\n return null;\n }\n\n const symbol = this._symbolTable?.[fieldIndex]?.[symbolIndex];\n const value = symbol?.toPrimaryValue();\n\n if (typeof value === 'string') {\n // Number('') and Number(' ') are 0, which silently turned every blank cell Qlik\n // stored into the number zero - indistinguishable from a real zero, and persisted as\n // one on the next write. Blank strings are never numeric, so exclude them.\n if (value.trim() !== '' && !isNaN(Number(value))) {\n return Number(value);\n }\n }\n\n return value;\n });\n };\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const columns = fields.map((/** @type {any} */ field) => field['FieldName']);\n const data = this._indexTable.map((_, index) => getRow(index));\n\n // Pass the complete header metadata to the data frame\n const metadata = this._header['QvdTableHeader'];\n\n /** @type {import('./QvdDataFrame.js').QvdLoadStats} */\n const loadStats = {\n symbolTableBytes: parseInt(this._header['QvdTableHeader']['Offset'], 10),\n totalRows: parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10),\n rowsLoaded: data.length,\n symbolFiltering: symbolsToKeep !== null,\n symbolsKept,\n };\n\n return new QvdDataFrame(data, columns, metadata, loadStats);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * @typedef {Object} QvdNumberFormat\n * @property {string} Type - Number format type\n * @property {string} nDec - Number of decimals\n * @property {string} UseThou - Use thousands separator\n * @property {string} Fmt - Format string\n * @property {string} Dec - Decimal separator\n * @property {string} Thou - Thousands separator\n */\n\n/**\n * @typedef {Object} QvdFieldHeader\n * @property {string} FieldName - The name of the field\n * @property {string|number} [BitOffset] - The bit offset\n * @property {string|number} [BitWidth] - The bit width\n * @property {string|number} [Bias] - The bias value\n * @property {string|number} [NoOfSymbols] - Number of symbols\n * @property {string|number} [Offset] - The offset\n * @property {string|number} [Length] - The length\n * @property {string} [Comment] - Field comment\n * @property {QvdNumberFormat|string} [NumberFormat] - Number format\n * @property {Object|string} [Tags] - Field tags\n */\n\n/**\n * @typedef {Object} QvdFields\n * @property {QvdFieldHeader|QvdFieldHeader[]} QvdFieldHeader - Field header(s)\n */\n\n/**\n * @typedef {Object} QvdMetadata\n * @property {string|number} [QvBuildNo] - QlikView build number\n * @property {string} [CreatorDoc] - Creator document\n * @property {string} [CreateUtcTime] - Creation UTC time\n * @property {string} [SourceCreateUtcTime] - Source creation UTC time\n * @property {string} [SourceFileUtcTime] - Source file UTC time\n * @property {string|number} [SourceFileSize] - Source file size\n * @property {string} [StaleUtcTime] - Stale UTC time\n * @property {string} [TableName] - Table name\n * @property {string|number} [NoOfRecords] - Number of records\n * @property {string|number} [RecordByteSize] - Record byte size\n * @property {string|number} [Offset] - Offset\n * @property {string|number} [Length] - Length\n * @property {string} [Compression] - Compression type\n * @property {string} [Comment] - Comment\n * @property {string} [EncryptionInfo] - Encryption info\n * @property {string} [TableTags] - Table tags\n * @property {string} [ProfilingData] - Profiling data\n * @property {Object|string} [Lineage] - Lineage\n * @property {QvdFields} [Fields] - Fields information\n */\n\n/**\n * Statistics describing the read that produced a data frame.\n *\n * @typedef {Object} QvdLoadStats\n * @property {number} symbolTableBytes Size of the file's symbol table, in bytes.\n * @property {number} totalRows Rows the file declares in its header.\n * @property {number} rowsLoaded Rows actually materialised.\n * @property {boolean} symbolFiltering Whether the two-pass symbol-filtering path was used.\n * @property {number|null} symbolsKept Symbols retained by that path, or null when it did not run.\n */\n\n/**\n * Represents a loaded QVD file.\n */\nexport class QvdDataFrame {\n /**\n * Represents the data frame stored inside a QVD file.\n * @param {Array<Array<any>>} data The data of the data frame.\n * @param {Array<string>} columns The columns of the data frame.\n * @param {QvdMetadata|null} metadata The metadata from the QVD file header (optional).\n * @param {QvdLoadStats|null} loadStats Statistics about the read (optional).\n */\n constructor(data, columns, metadata = null, loadStats = null) {\n this._data = data;\n this._columns = columns;\n this._metadata = metadata;\n this._loadStats = loadStats;\n }\n\n /**\n * Returns the data of the data frame.\n */\n get data() {\n return this._data;\n }\n\n /**\n * Returns the columns of the data frame.\n */\n get columns() {\n return this._columns;\n }\n\n /**\n * Returns the shape of the data frame.\n */\n get shape() {\n return [this._data.length, this._columns.length];\n }\n\n /**\n * Returns the complete metadata object from the QVD file header.\n * @return {Object|null} The complete metadata object or null if not available.\n */\n get metadata() {\n return this._metadata;\n }\n\n /**\n * Returns statistics about the read that produced this data frame.\n *\n * Only a frame returned by fromQvd() carries these; fromDict(), head() and tail() produce\n * frames that describe no particular read, and report null rather than a stale figure.\n *\n * The main use is confirming that a lazy load actually filtered the symbol table:\n * `symbolFiltering` says whether the two-pass path ran, and `symbolsKept` how many symbols\n * survived it, which for a small maxRows should be a tiny fraction of the file's total.\n *\n * @return {QvdLoadStats|null} Load statistics, or null if this frame did not come from a file.\n */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * Returns file-level metadata from the QVD header.\n * @return {Object} File-level metadata properties.\n */\n get fileMetadata() {\n if (!this._metadata) {\n return {};\n }\n\n const header = this._metadata;\n return {\n qvBuildNo: header.QvBuildNo,\n creatorDoc: header.CreatorDoc,\n createUtcTime: header.CreateUtcTime,\n sourceCreateUtcTime: header.SourceCreateUtcTime,\n sourceFileUtcTime: header.SourceFileUtcTime,\n sourceFileSize: header.SourceFileSize,\n staleUtcTime: header.StaleUtcTime,\n tableName: header.TableName,\n noOfRecords: header.NoOfRecords,\n recordByteSize: header.RecordByteSize,\n offset: header.Offset,\n length: header.Length,\n compression: header.Compression,\n comment: header.Comment,\n encryptionInfo: header.EncryptionInfo,\n tableTags: header.TableTags,\n profilingData: header.ProfilingData,\n lineage: header.Lineage,\n };\n }\n\n /**\n * Returns field-level metadata for a specific field/column.\n * @param {string} fieldName The name of the field.\n * @return {Object|null} Field metadata or null if field not found.\n */\n getFieldMetadata(fieldName) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return null;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const field = fields.find((f) => f.FieldName === fieldName);\n if (!field) {\n return null;\n }\n\n return {\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n };\n }\n\n /**\n * Returns field-level metadata for all fields.\n * @return {Array<Object>} Array of field metadata objects.\n */\n getAllFieldMetadata() {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return [];\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n return fields.map((field) => ({\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n }));\n }\n\n /**\n * @typedef {Object} FileMetadataUpdate\n * @property {string|number} [qvBuildNo] - QlikView build number\n * @property {string} [creatorDoc] - Creator document\n * @property {string} [createUtcTime] - Creation UTC time\n * @property {string} [sourceCreateUtcTime] - Source creation UTC time\n * @property {string} [sourceFileUtcTime] - Source file UTC time\n * @property {string|number} [sourceFileSize] - Source file size\n * @property {string} [staleUtcTime] - Stale UTC time\n * @property {string} [tableName] - Table name\n * @property {string} [compression] - Compression type\n * @property {string} [comment] - Comment\n * @property {string} [encryptionInfo] - Encryption info\n * @property {string} [tableTags] - Table tags\n * @property {string} [profilingData] - Profiling data\n * @property {Object|string} [lineage] - Lineage\n */\n\n /**\n * Sets modifiable file-level metadata. Immutable properties related to data storage are ignored.\n * @param {FileMetadataUpdate} metadata Object containing metadata properties to update.\n */\n setFileMetadata(metadata) {\n if (!this._metadata) {\n // Initialize metadata structure if it doesn't exist\n this._metadata = {\n QvBuildNo: 50667,\n CreatorDoc: '',\n CreateUtcTime: '',\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: '',\n Fields: {\n QvdFieldHeader: this._columns.map((column) => ({\n FieldName: column,\n BitOffset: 0,\n BitWidth: 0,\n Bias: 0,\n NoOfSymbols: 0,\n Offset: 0,\n Length: 0,\n Comment: '',\n NumberFormat: {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: {},\n })),\n },\n NoOfRecords: 0,\n RecordByteSize: 0,\n Offset: 0,\n Length: 0,\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {},\n };\n }\n\n // Only allow modification of certain fields (not Offset, Length, NoOfRecords, RecordByteSize)\n const modifiableFields = [\n 'qvBuildNo',\n 'creatorDoc',\n 'createUtcTime',\n 'sourceCreateUtcTime',\n 'sourceFileUtcTime',\n 'sourceFileSize',\n 'staleUtcTime',\n 'tableName',\n 'compression',\n 'comment',\n 'encryptionInfo',\n 'tableTags',\n 'profilingData',\n 'lineage',\n ];\n\n // Map camelCase to XML property names\n const fieldMapping = {\n qvBuildNo: 'QvBuildNo',\n creatorDoc: 'CreatorDoc',\n createUtcTime: 'CreateUtcTime',\n sourceCreateUtcTime: 'SourceCreateUtcTime',\n sourceFileUtcTime: 'SourceFileUtcTime',\n sourceFileSize: 'SourceFileSize',\n staleUtcTime: 'StaleUtcTime',\n tableName: 'TableName',\n compression: 'Compression',\n comment: 'Comment',\n encryptionInfo: 'EncryptionInfo',\n tableTags: 'TableTags',\n profilingData: 'ProfilingData',\n lineage: 'Lineage',\n };\n\n modifiableFields.forEach((field) => {\n // @ts-ignore - Dynamic property access for metadata mapping\n if (metadata[field] !== undefined) {\n // @ts-ignore - Dynamic property access for metadata mapping\n this._metadata[fieldMapping[field]] = metadata[field];\n }\n });\n }\n\n /**\n * @typedef {Object} FieldMetadataUpdate\n * @property {string} [comment] - Field comment\n * @property {QvdNumberFormat|string} [numberFormat] - Number format\n * @property {Object|string} [tags] - Field tags\n */\n\n /**\n * Sets modifiable field-level metadata for a specific field.\n * Immutable properties related to data storage (Offset, Length, BitOffset, etc.) are ignored.\n * @param {string} fieldName The name of the field.\n * @param {FieldMetadataUpdate} metadata Object containing field metadata properties to update.\n */\n setFieldMetadata(fieldName, metadata) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n this._metadata.Fields.QvdFieldHeader = fields;\n }\n\n const fieldIndex = fields.findIndex((f) => f.FieldName === fieldName);\n if (fieldIndex === -1) {\n return;\n }\n\n // Only allow modification of Comment, NumberFormat, and Tags (not Offset, Length, BitOffset, etc.)\n if (metadata.comment !== undefined) {\n fields[fieldIndex].Comment = metadata.comment;\n }\n if (metadata.numberFormat !== undefined) {\n fields[fieldIndex].NumberFormat = metadata.numberFormat;\n }\n if (metadata.tags !== undefined) {\n fields[fieldIndex].Tags = metadata.tags;\n }\n }\n\n /**\n * Returns the first n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n head(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('head() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(this._data.slice(0, n), this._columns, this._metadata);\n }\n\n /**\n * Returns the last n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n tail(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('tail() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(n === 0 ? [] : this._data.slice(-n), this._columns, this._metadata);\n }\n\n /**\n * Returns the selected rows of the data frame.\n *\n * @param {...number} args The indices of the rows to return.\n * @return {QvdDataFrame} The selected rows of the data frame.\n * @throws {QvdValidationError} If any index is not an integer or is out of bounds.\n */\n rows(...args) {\n for (const index of args) {\n if (typeof index !== 'number' || !Number.isInteger(index)) {\n throw new QvdValidationError('rows() requires integer indices', {\n provided: index,\n type: typeof index,\n });\n }\n if (index < 0 || index >= this._data.length) {\n throw new QvdValidationError(`Row index ${index} out of bounds`, {\n index,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n }\n return new QvdDataFrame(\n args.map((index) => this._data[index]),\n this._columns,\n this._metadata,\n );\n }\n\n /**\n * Returns the value at the specified row and column.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {any} The value at the specified row and column.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n at(row, column) {\n if (typeof row !== 'number' || !Number.isInteger(row)) {\n throw new QvdValidationError('Row index must be an integer', {\n provided: row,\n type: typeof row,\n });\n }\n if (row < 0 || row >= this._data.length) {\n throw new QvdValidationError(`Row index ${row} out of bounds`, {\n index: row,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n return this._data[row][this._columns.indexOf(column)];\n }\n\n /**\n * Selects the specified columns from the data frame.\n *\n * @param {...string} args The names of the columns to select.\n * @return {QvdDataFrame} The selected columns of the data frame.\n * @throws {QvdValidationError} If any column name does not exist.\n */\n select(...args) {\n for (const column of args) {\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n }\n const indices = args.map((arg) => this._columns.indexOf(arg));\n const data = this._data.map((row) => indices.map((index) => row[index]));\n const columns = indices.map((index) => this._columns[index]);\n return new QvdDataFrame(data, columns, this._metadata);\n }\n\n /**\n * Returns the data frame as a dictionary.\n *\n * @return {Promise<{columns: Array<string>, data: Array<Array<any>>}>} The data frame as a dictionary.\n */\n async toDict() {\n return {columns: this._columns, data: this._data};\n }\n\n /**\n * Persists the data frame to a QVD file.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional writing options.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function that receives progress updates during write operations.\n */\n async toQvd(path, options = {}) {\n const {QvdFileWriter} = await import('./QvdFileWriter.js');\n const writerOptions = {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n };\n await new QvdFileWriter(path, this, writerOptions).save();\n }\n\n /**\n * Loads a QVD file and returns its data frame.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional loading options.\n * @param {number|null} [options.maxRows] The maximum number of rows to load. Must be a non-negative\n * integer; if not specified or null, all rows are loaded. Anything else throws a QvdValidationError.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.3] Fraction (0.0-1.0) of the memory budget a load\n * may use. The budget is the smallest of the V8 heap limit, any container memory limit, and the\n * memory the OS reports as available. Default is 0.3; raise it when running with a larger heap via\n * --max-old-space-size. **Zero disables the memory check entirely.**\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes, above which\n * a lazy load switches to the two-pass filtering path. Defaults to 50MB.\n * @throws {QvdValidationError} If options.maxRows is neither null/undefined nor a non-negative integer.\n * @return {Promise<QvdDataFrame>} The data frame of the QVD file.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const readerOptions = {\n allowedDir: options.allowedDir,\n memorySafetyFactor: options.memorySafetyFactor,\n symbolFilteringThreshold: options.symbolFilteringThreshold,\n };\n return await new QvdFileReader(path, readerOptions).load(options.maxRows !== undefined ? options.maxRows : null);\n }\n\n /**\n * Constructs a data frame from a dictionary.\n *\n * @param {{columns: Array<string>, data: Array<Array<any>>}} data The dictionary to construct the data frame from.\n * @return {Promise<QvdDataFrame>} The constructed data frame.\n */\n static async fromDict(data) {\n if (!data.columns) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any columns.', {\n data,\n });\n }\n if (!data.data) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any data.', {\n data,\n });\n }\n\n return new QvdDataFrame(data.data, data.columns);\n }\n}\n","// @ts-check\n\nexport {QvdSymbol} from './QvdSymbol.js';\nexport {QvdDataFrame} from './QvdDataFrame.js';\nexport {QvdFileReader} from './QvdFileReader.js';\nexport {QvdFileWriter} from './QvdFileWriter.js';\nexport {\n QvdError,\n QvdParseError,\n QvdValidationError,\n QvdIOError,\n QvdCorruptedError,\n QvdSecurityError,\n} from './QvdErrors.js';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/QvdErrors.js","../src/QvdSymbol.js","../src/util/validatePath.js","../src/util/bitUtils.js","../src/QvdFileWriter.js","../src/util/memoryUtils.js","../src/util/validationUtils.js","../src/util/symbolParser.js","../src/QvdColumnTable.js","../src/QvdFileReader.js","../src/QvdDataFrame.js","../src/index.js"],"names":["QvdError","QvdParseError","QvdValidationError","QvdIOError","QvdCorruptedError","QvdSecurityError","QvdSymbol","path","fs","QvdFileWriter","assert","crypto","xml","v8","os","QvdColumn","QvdColumnTable","QvdFileReader","QvdDataFrame"],"mappings":"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","file":"index.cjs","sourcesContent":["// @ts-check\n\n/**\n * Base error class for all QVD-related errors.\n * Provides structured error information with error codes and context.\n */\nexport class QvdError extends Error {\n /**\n * Constructs a new QVD error.\n *\n * @param {string} message The error message.\n * @param {string} code The error code.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, code, context = {}) {\n super(message);\n this.name = this.constructor.name;\n this.code = code;\n this.context = context;\n Error.captureStackTrace(this, this.constructor);\n }\n}\n\n/**\n * Error thrown when parsing a QVD file fails.\n * Used for issues during XML header parsing, symbol table parsing, or index table parsing.\n */\nexport class QvdParseError extends QvdError {\n /**\n * Constructs a new QVD parse error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_PARSE_ERROR', context);\n }\n}\n\n/**\n * Error thrown when input validation fails.\n * Used for invalid parameters, out of bounds access, or missing required data.\n */\nexport class QvdValidationError extends QvdError {\n /**\n * Constructs a new QVD validation error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_VALIDATION_ERROR', context);\n }\n}\n\n/**\n * Error thrown when file system operations fail.\n * Used for issues reading or writing QVD files.\n */\nexport class QvdIOError extends QvdError {\n /**\n * Constructs a new QVD IO error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_IO_ERROR', context);\n }\n}\n\n/**\n * Error thrown when a QVD file is corrupted or malformed.\n * Used for missing headers, invalid data structures, or corrupted data.\n */\nexport class QvdCorruptedError extends QvdError {\n /**\n * Constructs a new QVD corrupted error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_CORRUPTED_ERROR', context);\n }\n}\n\n/**\n * Error thrown when security violations occur.\n * Used for path traversal attempts, XXE attacks, or other security issues.\n */\nexport class QvdSecurityError extends QvdError {\n /**\n * Constructs a new QVD security error.\n *\n * @param {string} message The error message.\n * @param {Object} [context={}] Additional context about the error.\n */\n constructor(message, context = {}) {\n super(message, 'QVD_SECURITY_ERROR', context);\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * Represents a Qlik symbol/value, stored in a QVD file.\n */\nexport class QvdSymbol {\n /**\n * Constructs a new QVD symbol.\n *\n * @param {number|null} intValue The integer value.\n * @param {number|null} doubleValue The double value.\n * @param {string|null} stringValue The string value.\n */\n constructor(intValue, doubleValue, stringValue) {\n this._intValue = intValue;\n\n this._doubleValue = doubleValue;\n\n this._stringValue = stringValue;\n }\n\n /**\n * Returns the integer value of this symbol.\n *\n * @return {number|null} The integer value.\n */\n get intValue() {\n return this._intValue;\n }\n\n /**\n * Returns the double value of this symbol.\n *\n * @return {number|null} The double value.\n */\n get doubleValue() {\n return this._doubleValue;\n }\n\n /**\n * Returns the string value of this symbol.\n *\n * @return {string|null} The string value.\n */\n get stringValue() {\n return this._stringValue;\n }\n\n /**\n * Retrieves the primary value of this symbol. The primary value is descriptive raw value.\n * It is either the string value, the integer value or the double value, prioritized in this order.\n *\n * @return {number|string|null} The primary value.\n */\n toPrimaryValue() {\n if (null != this._stringValue) {\n return this._stringValue;\n } else if (null != this._intValue) {\n return this._intValue;\n } else if (null != this._doubleValue) {\n return this._doubleValue;\n } else {\n return null;\n }\n }\n\n /**\n * Converts the symbol to its byte representation.\n *\n * @return {Buffer} The byte representation of the symbol.\n */\n toByteRepresentation() {\n if (this._intValue !== null && this._stringValue !== null) {\n const intBuffer = Buffer.alloc(4);\n intBuffer.writeInt32LE(this._intValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n const stringBuffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([5]), intBuffer, stringBuffer]);\n } else if (this._doubleValue !== null && this._stringValue !== null) {\n const floatBuffer = Buffer.alloc(8);\n floatBuffer.writeDoubleLE(this._doubleValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n const stringBuffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([6]), floatBuffer, stringBuffer]);\n } else if (this._intValue !== null) {\n const buffer = Buffer.alloc(4);\n buffer.writeInt32LE(this._intValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([1]), buffer]);\n } else if (this._doubleValue !== null) {\n const buffer = Buffer.alloc(8);\n buffer.writeDoubleLE(this._doubleValue);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([2]), buffer]);\n } else if (this._stringValue !== null) {\n // @ts-ignore - Buffer.concat type compatibility\n const buffer = Buffer.concat([Buffer.from(this._stringValue, 'utf-8'), Buffer.from([0])]);\n\n // @ts-ignore - Buffer.concat type compatibility\n return Buffer.concat([Buffer.from([4]), buffer]);\n } else {\n throw new QvdValidationError('The symbol does not contain any value.', {\n intValue: this._intValue,\n doubleValue: this._doubleValue,\n stringValue: this._stringValue,\n });\n }\n }\n\n /**\n * Checks if this symbol is equal to another symbol.\n *\n * @param {*} value The object to compare with.\n * @return {boolean} True if the objects are equal, false otherwise.\n */\n equals(value) {\n if (!(value instanceof QvdSymbol)) {\n return false;\n }\n\n return (\n this._intValue === value.intValue &&\n this._doubleValue === value.doubleValue &&\n this._stringValue === value.stringValue\n );\n }\n\n /**\n * Constructs a pure integer value symbol.\n *\n * @param {number} intValue The integer value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromIntValue(intValue) {\n return new QvdSymbol(intValue, null, null);\n }\n\n /**\n * Constructs a pure double value symbol.\n *\n * @param {number} doubleValue The double value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDoubleValue(doubleValue) {\n return new QvdSymbol(null, doubleValue, null);\n }\n\n /**\n * Constructs a pure string value symbol.\n *\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromStringValue(stringValue) {\n return new QvdSymbol(null, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from an integer and a string value.\n *\n * @param {number} intValue The integer value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDualIntValue(intValue, stringValue) {\n return new QvdSymbol(intValue, null, stringValue);\n }\n\n /**\n * Constructs a dual value symbol from a double and a string value.\n *\n * @param {number} doubleValue The double value.\n * @param {string} stringValue The string value.\n * @return {QvdSymbol} The constructed value symbol.\n */\n static fromDualDoubleValue(doubleValue, stringValue) {\n return new QvdSymbol(null, doubleValue, stringValue);\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport {QvdSecurityError, QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Determines whether a resolved path is contained within a resolved base directory, using only\n * string comparison.\n *\n * This is the fallback for when the filesystem cannot answer the question - in practice, when\n * allowedDir does not exist. It cannot see through symlinks and has to guess at case\n * sensitivity, which is exactly why it is not the primary check.\n *\n * Uses path.relative() rather than a string prefix test, so that filesystem roots\n * ('/', 'C:\\', '\\\\server\\share\\') and base directories with a trailing separator are\n * handled correctly. A prefix test appends path.sep to the base, which produces '//'\n * for a root and therefore matches nothing.\n *\n * @param {string} resolvedBaseDir Absolute, resolved base directory.\n * @param {string} resolvedPath Absolute, resolved candidate path.\n * @return {boolean} True if the path is the base directory itself or lies beneath it.\n */\nfunction isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) {\n // Folding is applied on Windows only. It used to cover darwin as well, on the assumption that\n // macOS is always case-insensitive, but macOS supports case-sensitive APFS and HFS+ volumes on\n // which two names differing only in case are genuinely different directories - so folding there\n // let a sibling directory pass the check. The on-disk comparison below settles case correctly\n // by asking the filesystem, which is why this fallback no longer needs to guess for darwin.\n const isCaseInsensitiveFS = process.platform === 'win32';\n const base = isCaseInsensitiveFS ? resolvedBaseDir.toLowerCase() : resolvedBaseDir;\n const target = isCaseInsensitiveFS ? resolvedPath.toLowerCase() : resolvedPath;\n\n const relative = path.relative(base, target);\n\n // '' means the path IS the base directory. A relative path that starts with '..' escapes\n // the base, and an absolute result means the two are on different roots/drives.\n if (relative === '') {\n return true;\n }\n if (path.isAbsolute(relative)) {\n return false;\n }\n return relative !== '..' && !relative.startsWith(`..${path.sep}`);\n}\n\n/**\n * Resolves the deepest ancestor of a path that actually exists, following symlinks.\n *\n * A path being written to does not exist yet, and neither may some of its parent directories, so\n * realpath() on the full path would simply fail. Walking up to the first component that does\n * exist gives the deepest point the filesystem can vouch for; anything below it is a name that\n * will be created inside that directory.\n *\n * @param {string} target Absolute, lexically resolved path.\n * @return {string|null} Canonical path of the deepest existing ancestor, or null if it could not\n * be determined.\n */\nfunction resolveDeepestExisting(target) {\n let current = target;\n\n for (;;) {\n try {\n return fs.realpathSync(current);\n } catch (error) {\n const code = /** @type {{code?: string}} */ (error)?.code;\n\n // ENOENT: this component does not exist. ENOTDIR: an ancestor is a file, so nothing below\n // it can exist either. Both mean \"keep walking up\". Anything else (EACCES, ELOOP) means the\n // filesystem cannot answer, and the caller falls back to the lexical test - which is safe,\n // because an open() on the same path is about to fail for the same reason.\n if (code !== 'ENOENT' && code !== 'ENOTDIR') {\n return null;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n }\n}\n\n/**\n * Determines whether a path is contained within a base directory by asking the filesystem.\n *\n * Both sides are resolved through symlinks and then compared by identity - device and inode -\n * rather than by name, walking up from the target until the base is found or the root is reached.\n * That settles two questions a string comparison cannot:\n *\n * - Symlinks. A link inside allowedDir pointing outside it resolves to its target, so it is\n * rejected. A lexical check sees only the link's own name, still under allowedDir, and lets it\n * through - which meant arbitrary read via the reader and arbitrary overwrite via the writer.\n * - Case. On a case-insensitive volume 'Qvd' and 'qvd' are one directory and share an inode; on a\n * case-sensitive volume they are two directories with different inodes. Comparing identity gets\n * both right without inferring anything from process.platform, which is what the old code did\n * and got wrong on case-sensitive macOS volumes.\n *\n * This is a check on the path, so it is inherently subject to a race: a symlink swapped in\n * between this call and the subsequent open would defeat it. Closing that would require opening\n * with O_NOFOLLOW and verifying the descriptor, which is a larger change to the reader and\n * writer than this function can make on its own.\n *\n * @param {string} resolvedBaseDir Absolute, lexically resolved base directory.\n * @param {string} resolvedPath Absolute, lexically resolved candidate path.\n * @return {boolean|null} True or false when the filesystem could answer, null when it could not.\n */\nfunction isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {\n /** @type {import('fs').Stats} */\n let baseStat;\n\n try {\n // The base has to exist to be identified. If it does not, there is nothing on disk to compare\n // against and the lexical fallback is all that is left.\n baseStat = fs.statSync(fs.realpathSync(resolvedBaseDir));\n } catch {\n return null;\n }\n\n let current = resolveDeepestExisting(resolvedPath);\n if (current === null) {\n return null;\n }\n\n // realpathSync() returns a fully canonical path, so every ancestor of it is canonical too and\n // walking up with dirname() cannot step through a symlink.\n for (;;) {\n let stat;\n try {\n stat = fs.statSync(current);\n } catch {\n return null;\n }\n\n if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {\n return true;\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return false;\n }\n current = parent;\n }\n}\n\n/**\n * Validates that a file path stays inside the allowed directory.\n *\n * Containment is decided by the filesystem wherever it can be: both paths are resolved through\n * symlinks and compared by device and inode. That covers symlink escapes and case sensitivity,\n * neither of which a string comparison can get right. When the base directory does not exist,\n * there is nothing to compare against and a lexical check is used instead.\n *\n * To permit access to an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on\n * Windows). There is deliberately no separate \"disable the check\" value: a null or empty\n * allowedDir falls back to the current working directory, so a caller that accidentally\n * passes one still gets the restriction rather than silently losing it.\n *\n * @param {string} filePath The path to validate.\n * @param {string|null} [allowedDir] Optional allowed directory path. Defaults to the current\n * working directory to prevent path traversal attacks.\n * @throws {QvdValidationError} If filePath is not a non-empty string, or allowedDir is not a\n * string, null or undefined.\n * @throws {QvdSecurityError} If path traversal is detected.\n * @return {string} The resolved absolute path. This is the lexically resolved path, not the\n * canonical one, so callers see the path they asked for.\n */\nexport function validatePath(filePath, allowedDir) {\n // Validate argument types up front, so callers get a typed error instead of a bare TypeError\n // from deep inside the function (e.g. 'filePath.includes is not a function').\n if (typeof filePath !== 'string' || filePath.length === 0) {\n throw new QvdValidationError('filePath must be a non-empty string', {\n provided: filePath,\n type: typeof filePath,\n });\n }\n\n if (allowedDir !== undefined && allowedDir !== null && typeof allowedDir !== 'string') {\n throw new QvdValidationError('allowedDir must be a string, null or undefined', {\n provided: allowedDir,\n type: typeof allowedDir,\n });\n }\n\n // Check for null bytes which can be used in path traversal attacks\n if (filePath.includes('\\0')) {\n throw new QvdSecurityError('Path traversal detected: Null byte in path', {\n path: filePath,\n reason: 'null_byte',\n });\n }\n\n const resolvedPath = path.resolve(filePath);\n\n // Default to the current working directory when no allowed directory is specified. This\n // prevents path traversal attacks by ensuring files can only be accessed within the CWD\n // or a more restrictive allowed directory.\n //\n // null and '' deliberately fall back to the CWD rather than meaning \"no restriction\":\n // callers routinely produce them from optional config or a JSON round trip, and silently\n // dropping the sandbox in that case would be a security hole. A caller that genuinely wants\n // an entire volume passes its root ('/' or 'C:\\\\'), which the containment test supports.\n const baseDir = allowedDir || process.cwd();\n const resolvedBaseDir = path.resolve(baseDir);\n\n const onDisk = isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath);\n const contained = onDisk === null ? isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) : onDisk;\n\n if (!contained) {\n throw new QvdSecurityError('Path traversal detected: Access denied', {\n path: filePath,\n resolvedPath,\n allowedDir: resolvedBaseDir,\n reason: 'outside_allowed_directory',\n // Says which check refused, so a rejection of a path that looks contained is traceable to\n // a symlink or a case difference rather than looking like a bug.\n check: onDisk === null ? 'lexical' : 'filesystem',\n });\n }\n\n return resolvedPath;\n}\n","// @ts-check\n\n/**\n * Largest `BitWidth` a field may declare.\n *\n * A stored index is an offset into the field's symbol table, and it is kept in an `Int32Array`,\n * so it has to fit in a positive 32-bit integer. 31 bits addresses 2,147,483,647 symbols in a\n * single field - orders of magnitude beyond anything the rest of the library will load, since\n * the symbol table for that many values would be terabytes and the memory guard refuses long\n * before. A file declaring more is refused rather than decoded: at 32 bits the top of the range\n * wraps to a negative index, and a negative index means NULL, so the failure would be silently\n * wrong values instead of an error. That is the shape of bug #113 was.\n */\nexport const MAX_BIT_WIDTH = 31;\n\n/**\n * Powers of two up to 2^39, the widest window a field can span: at most 7 bits of byte\n * misalignment plus `MAX_BIT_WIDTH`. Every value here is exactly representable as a double, and\n * so is every intermediate the decoder forms, which is why the arithmetic below can use `/` and\n * `%` on Numbers rather than 32-bit bitwise operators - those would overflow at 32 bits.\n */\nconst POW2 = Array.from({length: 41}, (_, exponent) => 2 ** exponent);\n\n/**\n * Where a field's bits sit inside a record.\n *\n * Both directions need this, and they must not derive it separately. Two copies of\n * `(shift + bitWidth + 7) >> 3` that drift apart write files this library cannot read, and\n * nothing throws - the decode simply starts a byte early and every field after the first\n * straddling one is misaligned. That is #113's failure shape pointed the other way, so the\n * derivation lives here and the encoder, the decoder and their tests all call it.\n *\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits; zero means it occupies no bits at all.\n * @return {{byteStart: number, shift: number, byteCount: number}} The field's byte window:\n * where it starts, how far into that byte it begins, and how many bytes it touches (0 when\n * the width is zero, otherwise 1 to 5).\n */\nexport function fieldGeometry(bitOffset, bitWidth) {\n const shift = bitOffset & 7;\n\n return {\n byteStart: bitOffset >>> 3,\n shift,\n byteCount: bitWidth === 0 ? 0 : (shift + bitWidth + 7) >>> 3,\n };\n}\n\n/**\n * Decodes one bit-packed field out of every record of an index table.\n *\n * ## The layout\n *\n * A record is `recordSize` bytes. Numbering its bits `p = 0, 1, 2, ...`, bit `p` is\n * `(byte[p >> 3] >> (p & 7)) & 1` - little-endian, least significant bit of each byte first. A\n * field occupies `bitWidth` consecutive bits starting at `bitOffset`, least significant bit\n * first, and `Bias` is then added to the value read.\n *\n * This is the same layout the previous implementation produced, by a much longer route: it\n * reversed the record's bytes, concatenated their binary spellings into a string of\n * `recordSize * 8` characters, split that into an array of one number per bit, reversed it, then\n * sliced the array per field and summed `bit * Math.pow(2, index)`. Several arrays the length of\n * the record in *bits*, built and discarded for every row, which is where roughly 98% of a full\n * read went.\n *\n * ## Why the arithmetic is not bitwise\n *\n * JavaScript's `<<`, `>>>` and `&` coerce to 32 bits, and a field can span up to 39 bits once\n * byte misalignment is counted. `Math.floor(acc / 2**shift) % 2**bitWidth` is exact for every\n * value this can form, because the widest accumulator is under 2^40 and doubles are exact to\n * 2^53.\n *\n * @param {Buffer|Uint8Array} buffer The index table, starting at the first record.\n * @param {number} recordSize Bytes per record.\n * @param {number} rowCount Number of records to decode.\n * @param {number} bitOffset The field's first bit within a record.\n * @param {number} bitWidth The field's width in bits. Zero means the field holds a single\n * distinct value and occupies no bits at all.\n * @param {number} bias Added to every decoded value. Qlik writes -2 for a field containing\n * NULLs, where stored index 0 means NULL and real symbols start at 2.\n * @param {Int32Array} out Destination, at least `rowCount` long.\n * @return {Int32Array} `out`.\n */\nexport function decodeIndexColumn(buffer, recordSize, rowCount, bitOffset, bitWidth, bias, out) {\n // A single-distinct-value column occupies zero bits, so there is nothing to read: every row\n // holds stored index 0, which is `bias` once the bias is applied.\n if (bitWidth === 0) {\n out.fill(bias, 0, rowCount);\n return out;\n }\n\n const {byteStart, shift, byteCount} = fieldGeometry(bitOffset, bitWidth);\n\n const divisor = POW2[shift];\n const modulus = POW2[bitWidth];\n\n // byteStart + byteCount is at most recordSize - validateFieldBitMetadata has already required\n // bitOffset + bitWidth <= recordSize * 8 - so every read below is inside the record, and the\n // caller has established that `rowCount` whole records are present.\n let base = byteStart;\n\n for (let row = 0; row < rowCount; row++, base += recordSize) {\n let acc = buffer[base];\n\n if (byteCount > 1) acc += buffer[base + 1] * 0x100;\n if (byteCount > 2) acc += buffer[base + 2] * 0x10000;\n if (byteCount > 3) acc += buffer[base + 3] * 0x1000000;\n if (byteCount > 4) acc += buffer[base + 4] * 0x100000000;\n\n out[row] = (Math.floor(acc / divisor) % modulus) + bias;\n }\n\n return out;\n}\n\n/**\n * Writes one bit-packed field into one record. The inverse of `decodeIndexColumn`.\n *\n * Same layout, written the other way: bit `p` of a record is `(byte[p >> 3] >> (p & 7)) & 1`,\n * so a value is shifted left by the field's `shift` and OR-ed across the bytes it touches. The\n * buffer must start zeroed and fields must not overlap, which the caller guarantees by\n * allocating it with `Buffer.alloc` and laying columns out by prefix sum of their widths.\n *\n * Multiplication rather than `<<` for the same reason the decoder divides rather than `>>>`: a\n * field can span 39 bits once misalignment is counted, and JavaScript's bitwise operators stop\n * at 32. Every intermediate here is under 2^40, well inside what a double represents exactly.\n *\n * It takes the geometry rather than a `bitOffset`, so the caller cannot derive the byte window\n * differently from the way `decodeIndexColumn` derives it - see `fieldGeometry`. A zero-width\n * field writes nothing, matching the decoder's zero-width branch, which reads nothing; the\n * first byte used to be written unconditionally, so a `byteCount` of 0 put the value into the\n * next column's bits.\n *\n * @param {Buffer|Uint8Array} buffer The index table being built.\n * @param {number} recordBase Index of the record's first byte.\n * @param {{byteStart: number, shift: number, byteCount: number}} geometry From `fieldGeometry`.\n * @param {number} value The stored index. Must fit in the field's width; the caller checks.\n */\nexport function writeBitField(buffer, recordBase, geometry, value) {\n const {byteStart, shift, byteCount} = geometry;\n\n if (byteCount === 0) {\n return;\n }\n\n const base = recordBase + byteStart;\n const shifted = value * POW2[shift];\n\n buffer[base] |= shifted % 0x100;\n\n if (byteCount > 1) buffer[base + 1] |= Math.floor(shifted / 0x100) % 0x100;\n if (byteCount > 2) buffer[base + 2] |= Math.floor(shifted / 0x10000) % 0x100;\n if (byteCount > 3) buffer[base + 3] |= Math.floor(shifted / 0x1000000) % 0x100;\n if (byteCount > 4) buffer[base + 4] |= Math.floor(shifted / 0x100000000) % 0x100;\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport path from 'path';\nimport crypto from 'crypto';\nimport xml from 'xml2js';\nimport assert from 'assert';\nimport {QvdSymbol} from './QvdSymbol.js';\nimport {QvdValidationError} from './QvdErrors.js';\nimport {validatePath} from './util/validatePath.js';\nimport {fieldGeometry, writeBitField} from './util/bitUtils.js';\n\n/**\n * @typedef {import('./QvdDataFrame.js').QvdDataFrame} QvdDataFrame\n */\n\n/**\n * Persists a QVD file to disk.\n */\nexport class QvdFileWriter {\n /**\n * Constructs a new QVD file writer.\n *\n * @param {string} filePath The path to the QVD file to write.\n * @param {QvdDataFrame} df The data frame to write to the QVD file.\n * @param {Object} [options={}] Options for the writer.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function.\n */\n constructor(filePath, df, options = {}) {\n const {allowedDir, onProgress} = options;\n this._path = validatePath(filePath, allowedDir);\n this._df = df;\n this._onProgress = onProgress;\n this._header = null;\n this._symbolBuffer = null;\n /** @type {Array<Array<import('./QvdSymbol.js').QvdSymbol>>|null} */\n this._symbolTable = null;\n /** @type {Array<any>|null} */\n this._symbolTableMetadata = null;\n this._indexBuffer = null;\n /**\n * Stored index for each distinct value of each column, keyed by the raw value.\n *\n * Built while the symbol table is, because that pass already decides the order symbols are\n * written in and therefore what each index is. The alternative - re-deriving it here from\n * a QvdSymbol and a template-literal key per cell - meant converting every cell twice and\n * allocating 34 million strings on the taxi fixture to look up something already known.\n *\n * @type {Array<Map<any, number>>|null}\n */\n this._symbolIndexByValue = null;\n /** @type {Array<any>|null} */\n this._indexTableMetadata = null;\n /** Rows written, kept because the index table is no longer an array to count. @type {number} */\n this._recordCount = 0;\n this._recordByteSize = null;\n }\n\n /**\n * Emits a progress event if a callback is registered.\n *\n * @param {string} stage The current stage of the operation.\n * @param {number} current The current progress value.\n * @param {number} total The total progress value.\n */\n _emitProgress(stage, current, total) {\n if (this._onProgress) {\n const percent = total > 0 ? Math.round((current / total) * 100) : 100;\n this._onProgress({\n stage,\n current,\n total,\n percent,\n });\n }\n }\n\n /**\n * Writes the data to the QVD file.\n */\n async _writeData() {\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolBuffer, 'The QVD file symbol table has not been parsed.');\n assert(this._indexBuffer, 'The QVD file index table has not been parsed.');\n\n this._emitProgress('write', 0, 1);\n\n // @ts-ignore - Buffer.concat type compatibility\n const headerBuffer = Buffer.concat([Buffer.from(this._header, 'utf-8'), Buffer.from([0])]);\n\n let fd;\n try {\n fd = await fs.promises.open(this._path, 'w');\n await fd.write(headerBuffer, 0, headerBuffer.length, 0);\n await fd.write(this._symbolBuffer, 0, this._symbolBuffer.length, headerBuffer.length);\n await fd.write(this._indexBuffer, 0, this._indexBuffer.length, headerBuffer.length + this._symbolBuffer.length);\n this._emitProgress('write', 1, 1);\n } finally {\n if (fd) {\n await fd.close();\n }\n }\n }\n\n /**\n * Builds the XML header of the QVD file.\n */\n _buildHeader() {\n this._emitProgress('header', 0, 1);\n const creationDate = new Date().toISOString().replace(/T/, ' ').replace(/\\..+/, '');\n /** @type {import('./QvdDataFrame.js').QvdMetadata|null} */\n const existingMetadata = this._df.metadata;\n\n // Use existing metadata if available, otherwise create default values\n const baseMetadata = existingMetadata\n ? {\n QvBuildNo: existingMetadata.QvBuildNo || 50667,\n CreatorDoc: existingMetadata.CreatorDoc || crypto.randomUUID(),\n CreateUtcTime: existingMetadata.CreateUtcTime || creationDate,\n SourceCreateUtcTime: existingMetadata.SourceCreateUtcTime || '',\n SourceFileUtcTime: existingMetadata.SourceFileUtcTime || '',\n SourceFileSize: existingMetadata.SourceFileSize || -1,\n StaleUtcTime: existingMetadata.StaleUtcTime || '',\n TableName: existingMetadata.TableName || path.basename(this._path, path.extname(this._path)),\n Compression: existingMetadata.Compression || '',\n Comment: existingMetadata.Comment || '',\n EncryptionInfo: existingMetadata.EncryptionInfo || '',\n TableTags: existingMetadata.TableTags || '',\n ProfilingData: existingMetadata.ProfilingData || '',\n Lineage: existingMetadata.Lineage || {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n }\n : {\n QvBuildNo: 50667,\n CreatorDoc: crypto.randomUUID(),\n CreateUtcTime: creationDate,\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: path.basename(this._path, path.extname(this._path)),\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {\n LineageInfo: {\n Discriminator: 'INLINE;',\n Statement: '',\n },\n },\n };\n\n // Get existing field metadata if available\n /** @type {any[]} */\n let existingFields = [];\n if (existingMetadata && existingMetadata.Fields && existingMetadata.Fields.QvdFieldHeader) {\n existingFields = Array.isArray(existingMetadata.Fields.QvdFieldHeader)\n ? existingMetadata.Fields.QvdFieldHeader\n : [existingMetadata.Fields.QvdFieldHeader];\n }\n\n const xmlObject = {\n QvdTableHeader: {\n ...baseMetadata,\n Fields: {\n QvdFieldHeader: this._df.columns.map((/** @type {any} */ column, /** @type {number} */ index) => {\n // Find existing field metadata for this column\n const existingField = existingFields.find((/** @type {any} */ f) => f.FieldName === column);\n\n return {\n FieldName: column,\n BitOffset: this._indexTableMetadata?.[index][0],\n BitWidth: this._indexTableMetadata?.[index][1],\n Bias: this._indexTableMetadata?.[index][2],\n NoOfSymbols: this._symbolTable?.[index].length,\n Offset: this._symbolTableMetadata?.[index][0],\n Length: this._symbolTableMetadata?.[index][1],\n Comment: existingField?.Comment || '',\n NumberFormat: existingField?.NumberFormat || {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: existingField?.Tags || {},\n };\n }),\n },\n NoOfRecords: this._recordCount,\n RecordByteSize: this._recordByteSize,\n Offset:\n this._symbolTableMetadata && this._symbolTableMetadata.length > 0\n ? this._symbolTableMetadata[this._symbolTableMetadata.length - 1][0] +\n this._symbolTableMetadata[this._symbolTableMetadata.length - 1][1]\n : 0,\n Length: this._indexBuffer?.length,\n },\n };\n\n const builder = new xml.Builder({\n renderOpts: {\n pretty: true,\n newline: '\\r\\n',\n indent: ' ',\n },\n });\n this._header = builder.buildObject(xmlObject) + '\\r\\n';\n this._emitProgress('header', 1, 1);\n }\n\n /**\n * Builds the symbol table of the QVD file.\n *\n * PERFORMANCE OPTIMIZATION: This method uses a single-pass algorithm to build\n * symbol tables for all columns simultaneously. This reduces time complexity from\n * O(n×m×s) to O(n×m) where n=rows, m=columns, s=symbols per column.\n *\n * Algorithm:\n * 1. Initialize a Set for each column to collect unique values\n * 2. Single pass through all data rows, adding values to corresponding Sets\n * 3. Convert Sets to arrays and create QvdSymbol instances\n * 4. Serialize symbols to binary format and update metadata\n *\n * This approach provides:\n * - 80-90% performance improvement for large datasets (100K+ rows)\n * - Better cache locality (process all columns in one data traversal)\n * - Lower memory pressure (no intermediate arrays per column)\n *\n * @private\n */\n _buildSymbolTable() {\n this._symbolTable = [];\n this._symbolTableMetadata = [];\n this._symbolIndexByValue = [];\n\n // A table with no fields is not a QVD. Writing one produced a 741-byte file with an empty\n // `<Fields/>` element that this same library refuses to load, which is the worst of both:\n // the write reports success and the failure surfaces later, somewhere else.\n if (this._df.columns.length === 0) {\n throw new QvdValidationError('A QVD file must have at least one field', {\n file: this._path,\n stage: 'buildSymbolTable',\n });\n }\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numColumns = columns.length;\n const numRows = data.length;\n\n this._emitProgress('symbol-table', 0, numColumns);\n\n // One Map per column, from raw value to the stored index that value will get, built in the\n // single pass over the data that also discovers the distinct values.\n //\n // This used to be a Set per column, then `Array.from` on it, then a Map built from the\n // array - three structures each holding a reference to every distinct value, where one is\n // needed. On a column whose values are all distinct that was roughly 30MB of duplication\n // per million rows, and it bought nothing: a Map preserves insertion order exactly as a Set\n // does, so the indices it hands out are the same ones the array walk produced.\n /** @type {Array<Map<any, number>>} */\n const indexByValue = columns.map(() => new Map());\n /** @type {Array<boolean>} */\n const containsNull = columns.map(() => false);\n\n // A counted loop, not `data.forEach`. forEach skips array holes and the index table's loop\n // does not, so a sparse `data` array made the two passes disagree about how many rows\n // exist: a five-element array with one row set wrote a five-row file in which four rows\n // carried a real value copied from the fifth, and a hole between two rows threw a bare\n // TypeError. A hole reads as `undefined`, which is what this writer already treats as NULL\n // everywhere else, so both passes now see the same rows and a hole becomes a NULL row.\n for (let row = 0; row < numRows; row++) {\n const values = data[row];\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n containsNull[column] = true;\n continue;\n }\n\n const map = indexByValue[column];\n\n if (!map.has(value)) {\n map.set(value, map.size);\n }\n }\n }\n\n // Serialised per column and concatenated once. Concatenating onto an accumulating buffer\n // instead re-copies every byte written so far on each column - O(bytes x columns), which\n // measured 26ms against 14ms on a 67MB symbol table and gets worse linearly with the column\n // count, while transiently holding two copies of everything written so far.\n /** @type {Array<Buffer>} */\n const columnBuffers = [];\n let symbolsOffset = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const symbols = Array.from(indexByValue[column].keys(), (value) => QvdFileWriter._convertRawToSymbol(value));\n\n // @ts-ignore - Symbol byte representation\n const columnBuffer = Buffer.concat(symbols.map((symbol) => symbol.toByteRepresentation()));\n\n columnBuffers.push(columnBuffer);\n this._symbolTableMetadata?.push([symbolsOffset, columnBuffer.length, containsNull[column]]);\n // @ts-ignore - Symbol array type compatibility\n this._symbolTable?.push(symbols);\n this._symbolIndexByValue.push(indexByValue[column]);\n\n symbolsOffset += columnBuffer.length;\n\n this._emitProgress('symbol-table', column + 1, numColumns);\n }\n\n // @ts-ignore - Buffer.concat type compatibility\n this._symbolBuffer = Buffer.concat(columnBuffers);\n }\n\n /**\n * Builds the bit-packed index table of the QVD file.\n *\n * A record is `recordByteSize` bytes. Each column occupies `bitWidth` consecutive bits at\n * `bitOffset`, least significant bit first, where bit `p` of a record is\n * `(byte[p >> 3] >> (p & 7)) & 1`. `Bias` is -2 for a column containing NULLs: stored index 0\n * means NULL, and real symbols start at 2. This is exactly what the reader's\n * `decodeIndexColumn` undoes, and `writeBitField` is its inverse.\n *\n * The previous implementation went the long way round. Per cell it converted the raw value to\n * a QvdSymbol - a second time, the symbol table pass having already done it - to build a\n * template-literal lookup key, then turned the resulting index into a string of bits via\n * `toString(2).split('').map().reverse().concat().slice().reverse()`. Per row it kept an array\n * of those strings, padded each with `padStart`, reversed and joined them, split the result\n * with `/.{1,8}/g`, and allocated a Buffer; then `Buffer.concat` over one Buffer per row. On\n * the 1.7M-row taxi fixture that is 34 million symbols, 34 million key strings, 34 million bit\n * strings and 1.7 million Buffers, and it accounted for 98% of a write.\n *\n * Now: the widths are derived from the symbol counts, the offsets by prefix sum, one Buffer is\n * allocated for the whole table, and each value is OR-ed into place as an integer.\n *\n * @private\n */\n _buildIndexTable() {\n assert(this._symbolTable, 'The QVD file symbol table has not been built.');\n assert(this._symbolTableMetadata, 'The QVD file symbol table metadata has not been built.');\n assert(this._symbolIndexByValue, 'The QVD file symbol index has not been built.');\n\n this._indexTableMetadata = [];\n\n const columns = this._df.columns;\n const data = this._df.data;\n const numRows = data.length;\n const numColumns = columns.length;\n\n this._recordCount = numRows;\n this._emitProgress('index-table', 0, numRows);\n\n // Layout, one entry per column, hoisted out of the row loop so the inner loop does\n // arithmetic into a buffer and nothing else.\n /** @type {Array<{geometry: {byteStart: number, shift: number, byteCount: number}, nullShift: number}>} */\n const layout = [];\n\n let totalBits = 0;\n\n for (let column = 0; column < numColumns; column++) {\n const fieldContainsNull = this._symbolTableMetadata[column][2];\n const symbolCount = this._symbolTable[column].length;\n const nullShift = fieldContainsNull ? 2 : 0;\n\n // The largest stored index is (symbolCount - 1), shifted by 2 when the column contains\n // NULLs (index 0 denotes NULL and indices start at 2, which is what Bias=-2 encodes).\n //\n // Deriving the width this way is O(1) per column instead of O(rows), and it avoids\n // Math.max(...oneArgumentPerRow), which overflows the call stack somewhere around\n // 120k rows and made toQvd() unusable for realistic table sizes.\n const maxStoredIndex = symbolCount === 0 ? 0 : symbolCount - 1 + nullShift;\n\n // A single distinct value needs no bits at all, which matches what Qlik emits.\n const bitWidth = maxStoredIndex === 0 ? 0 : 32 - Math.clz32(maxStoredIndex);\n\n // Every index the row loop can write, checked once per column rather than once per cell.\n //\n // The row loop writes either 0, for NULL, or a value from this map, so validating the\n // map validates every write - 28,512 checks on the taxi fixture instead of 34 million,\n // and it covers the zero-width columns the per-cell check used to skip past. The bound is\n // the symbol count, not the field's capacity: a per-cell `storedIndex >= 2 ** bitWidth`\n // admitted indices in the gap between the two, which address no symbol and read back as\n // NULL with nothing thrown.\n for (const index of this._symbolIndexByValue[column].values()) {\n if (index + nullShift > maxStoredIndex) {\n throw new QvdValidationError('The symbol table and the index table are out of sync', {\n field: columns[column],\n storedIndex: index + nullShift,\n maxStoredIndex,\n symbolCount,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n }\n\n layout.push({geometry: fieldGeometry(totalBits, bitWidth), nullShift});\n\n this._indexTableMetadata.push([totalBits, bitWidth, fieldContainsNull ? -2 : 0]);\n\n totalBits += bitWidth;\n }\n\n // Every column may have a bit width of 0 - each holds a single distinct value, or only\n // NULLs - leaving no bits at all. Qlik still uses a one-byte record in that situation, and\n // a zero-byte record would be rejected on read.\n const recordByteSize = Math.max(1, Math.ceil(totalBits / 8));\n\n this._recordByteSize = recordByteSize;\n this._indexBuffer = Buffer.alloc(numRows * recordByteSize);\n\n const progressInterval = Math.max(1, Math.floor(numRows / 100)); // Report progress every 1%\n\n for (let row = 0, recordBase = 0; row < numRows; row++, recordBase += recordByteSize) {\n const values = data[row];\n\n for (let column = 0; column < numColumns; column++) {\n const value = values?.[column];\n\n if (value === null || value === undefined) {\n // NULL is stored index 0, which the bias turns back into a negative index on read.\n // Nothing to write: the buffer is already zeroed.\n continue;\n }\n\n const index = this._symbolIndexByValue[column].get(value);\n\n // A value the symbol table never saw. Unreachable while both passes walk the same rows,\n // which is the point of them sharing a counted loop - but the old code absorbed this\n // with `?? 0`, writing the first real symbol in place of the missing value, so a whole\n // column could read back as some other value with nothing thrown.\n if (index === undefined) {\n throw new QvdValidationError('A value is missing from the symbol table', {\n field: columns[column],\n row,\n file: this._path,\n stage: 'buildIndexTable',\n });\n }\n\n writeBitField(this._indexBuffer, recordBase, layout[column].geometry, index + layout[column].nullShift);\n }\n\n // Report progress periodically\n if ((row + 1) % progressInterval === 0 || row + 1 === numRows) {\n this._emitProgress('index-table', row + 1, numRows);\n }\n }\n\n // The maps are dead once the table is packed, and the writer stays alive through the header\n // build and the file write - the point at which the symbol buffer and the index buffer are\n // both resident.\n this._symbolIndexByValue = null;\n }\n\n /**\n * Converts a raw value/literal to a QVD symbol.\n *\n * @param {any} raw The raw value/literal to convert.\n * @return {QvdSymbol|null} The converted QVD symbol.\n */\n static _convertRawToSymbol(raw) {\n if (raw === null || raw === undefined) {\n return null;\n }\n\n const INT32_MIN = -2147483648;\n const INT32_MAX = 2147483647;\n\n const isInteger = typeof raw === 'number' && Number.isInteger(raw);\n const isFloat = typeof raw === 'number' && !Number.isInteger(raw);\n const isWithinInt32Range = typeof raw === 'number' && raw >= INT32_MIN && raw <= INT32_MAX;\n\n if (isInteger && isWithinInt32Range) {\n return QvdSymbol.fromDualIntValue(raw, raw.toString());\n } else if (isFloat || (isInteger && !isWithinInt32Range)) {\n return QvdSymbol.fromDualDoubleValue(raw, raw.toString());\n } else {\n return QvdSymbol.fromStringValue(raw);\n }\n }\n\n /**\n * Persists the data frame to a QVD file.\n */\n async save() {\n this._buildSymbolTable();\n this._buildIndexTable();\n this._buildHeader();\n await this._writeData();\n }\n}\n","// @ts-check\n\nimport os from 'os';\nimport v8 from 'v8';\nimport {QvdValidationError} from '../QvdErrors.js';\n\n/**\n * Gets the configured V8 heap size limit for the current Node.js process.\n * This respects the --max-old-space-size flag if set.\n *\n * @returns {number} Heap size limit in bytes\n */\nexport function getHeapLimit() {\n return v8.getHeapStatistics().heap_size_limit;\n}\n\n/**\n * Whether v8.getHeapStatistics().heap_size_limit means what it says on this runtime.\n *\n * Bun reports its *current* heap there rather than a ceiling - 229MB on a machine with 128GB of\n * RAM - so treating it as a limit rejects almost everything. It cannot be detected structurally\n * either: Bun spoofs both process.versions.v8 and process.versions.node, so the runtime's own\n * key is the only reliable signal.\n *\n * @return {boolean} True when the heap limit is a real limit.\n */\nfunction heapLimitIsMeaningful() {\n return !process.versions.bun && !process.versions.deno;\n}\n\n/**\n * Works out how much memory this process may actually use, and which limit decided it.\n *\n * Only two things can bind, and the smaller wins:\n *\n * - The V8 heap ceiling, which is what an allocation actually fails against, fatally and\n * uncatchably. V8 sizes it from physical memory by default, so it already scales down on a\n * small machine.\n * - A container memory limit, from process.constrainedMemory(). This is the case os.freemem()\n * gets dangerously wrong: inside a cgroup it reports the *host's* free memory, so a 2GB\n * container on a large host sails past the check and is then killed by the OOM killer with\n * exit 137 and no JavaScript error to catch.\n *\n * What the OS reports as free or available is deliberately *not* one of them. It is recorded for\n * diagnostics and ignored for the decision, because it does not describe a wall the process can\n * hit - a machine with virtual memory gets slower, not fatal - and because the number itself is\n * not trustworthy. os.freemem() counts only free and speculative pages, excluding the inactive\n * and file-cache pages the OS reclaims on demand. process.availableMemory() is meant to fix that\n * and does on Linux, but on macOS it depends on the libuv version underneath: Node 24 reported\n * 63GB on a 128GB machine here while Node 22 on a macOS CI runner reported 74MB, which refused a\n * 45MB load on a machine that had ample room for it. Letting either bind is what made the same\n * file load or fail from one minute, or one Node version, to the next.\n *\n * @return {{bytes: number, limitedBy: string, candidates: Array<{source: string, bytes: number}>,\n * observed: Array<{source: string, bytes: number}>}} The budget, the name of the limit that\n * bound it, what was allowed to bind, and what was recorded but not used.\n */\nexport function getMemoryBudget() {\n /** @type {Array<{source: string, bytes: number}>} */\n const candidates = [];\n\n if (heapLimitIsMeaningful()) {\n candidates.push({source: 'V8 heap limit', bytes: usableOldSpaceLimit()});\n }\n\n // Node returns 0 when the process is not constrained. Bun returns os.totalmem() instead, which\n // is not a constraint either, so anything at or above total memory is discarded rather than\n // treated as a container limit.\n const constrained = typeof process.constrainedMemory === 'function' ? process.constrainedMemory() : 0;\n if (constrained > 0 && constrained < os.totalmem()) {\n candidates.push({source: 'container memory limit', bytes: constrained});\n }\n\n // Bun outside a container has neither a usable heap limit nor a container limit, so without\n // this there would be no ceiling at all. Total memory is at least a real upper bound.\n if (candidates.length === 0) {\n candidates.push({source: 'total system memory', bytes: os.totalmem()});\n }\n\n /** @type {Array<{source: string, bytes: number}>} */\n const observed = [{source: 'free memory (os.freemem)', bytes: os.freemem()}];\n if (typeof process.availableMemory === 'function') {\n observed.push({source: 'available memory', bytes: process.availableMemory()});\n }\n\n const binding = candidates.reduce((lowest, candidate) => (candidate.bytes < lowest.bytes ? candidate : lowest));\n\n return {bytes: binding.bytes, limitedBy: binding.source, candidates, observed};\n}\n\n/**\n * What `heap_size_limit` overstates the usable old-space limit by, in bytes.\n *\n * `v8.getHeapStatistics().heap_size_limit` counts new space, code space and the trusted spaces\n * as well as old space, and it is old space that a row-materialising load exhausts. Measured on\n * this platform the gap is a flat 192MB at every configured size - `--max-old-space-size=96`\n * reports 288, 512 reports 704, 2048 reports 2240 - so it is an absolute offset, not a\n * proportion, and a safety factor cannot express it. At a 4GB heap it is under 5% and a factor\n * absorbs it; at a heap configured down to a couple of hundred megabytes it is most of the\n * budget, which is where an under-sized estimate turned into a crash.\n *\n * It used to be absorbed into the per-row constants instead, which made those constants\n * describe two unrelated things at once and left them four to six times larger than the memory\n * they were supposed to model. Subtracting it here lets the row model be a row model.\n *\n * V8 exposes no per-space limit - `getHeapSpaceStatistics()` reports current sizes, not\n * ceilings - so this is an observed constant rather than a derived one. If it is wrong on some\n * platform it is wrong in the safe direction on a large heap, and the safety factor still\n * applies underneath.\n */\nconst HEAP_LIMIT_OVERSTATEMENT_BYTES = 192 * 1024 * 1024;\n\n/**\n * Smallest budget worth reporting, in bytes.\n *\n * This is a damage limiter for a platform where the 192MB offset does not hold, not a\n * description of a real ceiling. Subtracting an offset that does not apply would leave a budget\n * near zero and refuse everything, so the floor catches that.\n *\n * It has to leave room for `BASE_BYTES` plus a small load *after* the safety factor, or it\n * achieves the opposite of its purpose. An earlier value of 16MB was exactly `BASE_BYTES`, so at\n * the floor the estimate always exceeded the budget and even `misc/small.qvd` - 606 rows, 29KB -\n * was refused on a runtime where it demonstrably loads. 64MB clears `BASE_BYTES` four times\n * over.\n *\n * It over-claims only where the true old-space limit is under 64MB, which is not a configuration\n * this library can serve: the fixed cost of reading any file at all is 15MB of that.\n */\nconst MINIMUM_BUDGET_BYTES = 64 * 1024 * 1024;\n\n/**\n * The heap limit, less the spaces a row load cannot use.\n *\n * A plain subtraction, because the overstatement is a flat offset at every configured size:\n * `--max-old-space-size=47` reports 239, 96 reports 288, 4096 reports 4288. An earlier version\n * of this only subtracted when the reported limit exceeded twice the offset and otherwise\n * returned half of it, which was meant to avoid a non-positive result. It instead produced the\n * wrong answer across the whole range the correction exists for: at a 47MB heap it returned\n * 119MB, so the guard admitted a load that needed 63MB and the process aborted - the exact\n * failure this function is here to prevent, reintroduced by the fallback rather than by the\n * rule.\n *\n * @return {number} Usable bytes.\n */\nfunction usableOldSpaceLimit() {\n const usable = getHeapLimit() - HEAP_LIMIT_OVERSTATEMENT_BYTES;\n\n return usable > MINIMUM_BUDGET_BYTES ? usable : MINIMUM_BUDGET_BYTES;\n}\n\n/**\n * Estimates the memory usage for loading a QVD file with given parameters.\n * Takes into account Phase 2.5 optimization which skips parsing unused symbols.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @returns {number} Estimated memory usage in bytes\n */\n/**\n * What a row-materialising load costs, in bytes.\n *\n * `BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columns)`.\n *\n * Recalibrated 2026-09-11, after the bitwise decode (#134) stopped the reader allocating an\n * array per row and several per cell. The method is the one the original calibration used:\n * generate N rows x C columns where every value is `(i + j) % 100`, so the symbol table stays\n * negligible and only row geometry moves, then binary-search the smallest\n * `--max-old-space-size` at which the load completes.\n *\n * shape cells was (pre-#134) now model\n * 400,000 x 10 4M 118 MB 63 77\n * 800,000 x 5 4M 237 MB 87 106\n * 200,000 x 40 8M 142 MB 79 62\n * 400,000 x 40 16M 307 MB 151 109\n * 800,000 x 20 16M 484 MB 175 202\n * 1,600,000 x 10 16M 520 MB 215 259\n *\n * and against two real files, which the original calibration did not cover:\n *\n * lego/inventory_parts 580,251 x 5 63 MB 81\n * chicago_taxi_rides 2016_01 1,705,805 x 20 367 MB 412\n *\n * The reader needs roughly 2.4x less heap than it did, which is why the old constants - 360 and\n * 34 - over-estimated a taxi read by 4.8x and refused loads that fit comfortably.\n *\n * Two of the model's figures sit *below* the measurement (200,000 x 40 and 400,000 x 40). That\n * is not an under-estimate of the rows: those two shapes are dominated by the fixed cost of\n * reading a file at all, which `BASE_BYTES` covers and which the per-row terms should not be\n * inflated to absorb. Every shape's total prediction is above its measured minimum.\n *\n * The constants are what the geometry implies rather than fitted numbers: a row is a JSArray\n * with a separate backing store, so it costs two object headers plus slack, and a cell is one\n * pointer. Fitting the eight measurements above gives 55-64 and 7.1-7.3; 72 and 8 clear every\n * one of them by 13-26%, which is the margin. Under-estimating means an uncatchable abort,\n * over-estimating means a catchable refusal, so the margin is deliberately one-sided.\n *\n * `BASE_BYTES` is what a load costs before any rows exist - the interpreter, the parsed header,\n * the decoded index columns. Measured as the floor of the binary search: a columnar read of any\n * of these files, which builds no rows at all, completes at 15MB.\n */\nconst BASE_BYTES = 16 * 1024 * 1024;\nconst ROW_BASE_BYTES = 72;\nconst PER_CELL_BYTES = 8;\n\n/**\n * Bytes a read allocates *outside* the V8 heap, in bytes.\n *\n * The decoder builds one `Int32Array` of stored indices per field, and a TypedArray's backing\n * store is external memory: it does not consume old space, so `--max-old-space-size` does not\n * bound it and the V8 heap budget must not be charged for it. A columnar read of the 38MB taxi\n * fixture completes in a 15MB heap for exactly this reason.\n *\n * A cgroup counts it, though, and exceeding a container limit is a SIGKILL - uncatchable, and\n * strictly worse than the heap abort this module exists to prevent. So it is estimated, and\n * checked against the container budget rather than the heap one.\n *\n * Both paths allocate it. A row read builds the codes and then the rows from them, so during\n * the load both are live; a columnar read keeps only the codes. The file buffer is external\n * too, but its size is not known here, and the codes dominate on the shapes that get close to\n * a limit.\n *\n * @param {number} rows Rows that will be decoded.\n * @param {number} columnCount Columns per row.\n * @return {number} Estimated external bytes.\n */\nexport function estimateExternalMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0 || !rows || rows <= 0) {\n return 0;\n }\n\n return rows * columnCount * Int32Array.BYTES_PER_ELEMENT;\n}\n\n/**\n * Estimates the heap a row-materialising load will need, in bytes.\n *\n * @param {number} rows Rows that will be materialised.\n * @param {number} columnCount Columns per row. Zero disables the term, for callers that do not\n * know the geometry yet.\n * @return {number} Estimated bytes.\n */\nfunction estimateRowMemory(rows, columnCount) {\n if (!columnCount || columnCount <= 0) {\n return 0;\n }\n return BASE_BYTES + rows * (ROW_BASE_BYTES + PER_CELL_BYTES * columnCount);\n}\n\nexport function estimateMemoryUsage(symbolTableSize, maxRows, totalRows, columnCount = 0, materialisesRows = true) {\n // Memory overhead multipliers based on empirical testing\n const FULL_PARSE_OVERHEAD = 6.0; // Baseline: JavaScript objects have 6x overhead\n const MINIMAL_OVERHEAD = 0.01; // Skipped symbols: minimal null placeholder overhead\n\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n\n // The rows themselves. This term used to be missing entirely, which is what made the guard\n // useless for the commonest Qlik shape: many rows over low-cardinality fields. A 150MB file\n // with a 0.43MB symbol table was estimated at 2.6MB and then killed a default heap.\n //\n // A columnar read materialises none of them, and what it does allocate - one Int32Array of\n // codes per field - is a TypedArray backing store, which lives outside the V8 heap this\n // budget describes. That is not a modelling nicety: binary-searching the smallest\n // --max-old-space-size at which a columnar read completes gives 15MB for every file tried,\n // from a 4MB fixture to the 38MB taxi one, because almost nothing it allocates is on the\n // heap. Charging it the row cost refused columnar reads that need a fortieth of the budget.\n const rowMemory = materialisesRows ? estimateRowMemory(rowsToLoad, columnCount) : BASE_BYTES;\n\n if (maxRows === null || maxRows >= totalRows) {\n // Loading all rows - need all symbols, no filtering benefit\n return symbolTableSize * FULL_PARSE_OVERHEAD + rowMemory;\n }\n\n // Estimate what percentage of symbols we'll need\n // Symbol usage grows slower than linear (diminishing returns as you add rows)\n // Use square root scaling as empirical approximation\n const rowPercentage = maxRows / totalRows;\n const symbolPercentage = Math.sqrt(rowPercentage);\n\n // Calculate memory for kept symbols (full overhead) + skipped symbols (minimal overhead)\n const keptSymbolsMemory = symbolTableSize * symbolPercentage * FULL_PARSE_OVERHEAD;\n const skippedSymbolsMemory = symbolTableSize * (1 - symbolPercentage) * MINIMAL_OVERHEAD;\n\n return keptSymbolsMemory + skippedSymbolsMemory + rowMemory;\n}\n\n/**\n * Finds the largest row count whose estimate fits inside a budget.\n *\n * The estimate is monotonic in rows but not invertible in closed form - the symbol term scales\n * with sqrt(rows/totalRows) while the row term scales linearly - so this bisects instead, and\n * the answer is therefore a value the caller can actually use. The previous implementation\n * inverted the square-root term alone and suggested row counts that the same check rejected on\n * the next call.\n *\n * @param {number} budget Bytes available.\n * @param {number} symbolTableSize Size of the symbol table in bytes.\n * @param {number} totalRows Rows the file declares.\n * @param {number} columnCount Columns per row.\n * @return {number} A row count whose estimate fits the budget, or 0 when none does.\n */\nexport function recommendedRowsFor(budget, symbolTableSize, totalRows, columnCount, materialisesRows = true) {\n if (estimateMemoryUsage(symbolTableSize, totalRows, totalRows, columnCount, materialisesRows) <= budget) {\n return totalRows;\n }\n\n // The bisection below treats `low` as a value known to fit, so that has to be true of its\n // starting point. It is not automatic: the estimate charges 1% of the symbol table even when\n // no rows are requested, so a symbol table two orders of magnitude larger than the budget\n // leaves nothing that fits. Clamping the answer up to 1 in that case produced a suggestion\n // the caller could not use - `maxRows: 1` threw the same error it had just been offered as\n // the fix for.\n if (estimateMemoryUsage(symbolTableSize, 0, totalRows, columnCount, materialisesRows) > budget) {\n return 0;\n }\n\n let low = 0;\n let high = totalRows;\n while (high - low > 1) {\n const mid = Math.floor((low + high) / 2);\n if (estimateMemoryUsage(symbolTableSize, mid, totalRows, columnCount, materialisesRows) <= budget) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Validates that there is sufficient memory available to load a QVD file safely.\n * Considers both available system RAM and the configured V8 heap limit.\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} [safetyFactor=0.8] Fraction of the memory budget to use (0.0-1.0). Zero\n * disables the check entirely.\n *\n * The default was 0.3 while the estimate counted only the symbol table - a proxy that\n * understated real cost by around a hundredfold for the commonest Qlik shape, so the factor was\n * quietly compensating for it. Now that the estimate models the rows too, 0.3 would double-count\n * that margin and refuse loads with four times the headroom they need. The estimate sits about\n * 1.2-1.6x above the measured requirement, so 0.8 still leaves V8 room to collect.\n * @param {number} [columnCount=0] Columns per row, so the estimate can account for the row\n * arrays. Zero omits that term, which is what the old symbol-table-only estimate did.\n * @throws {QvdValidationError} If insufficient memory is available\n */\nexport function validateMemoryAvailability(\n symbolTableSize,\n maxRows,\n totalRows,\n filePath,\n safetyFactor = 0.8,\n columnCount = 0,\n materialisesRows = true,\n) {\n if (typeof safetyFactor !== 'number' || safetyFactor < 0 || safetyFactor > 1) {\n throw new QvdValidationError('safetyFactor must be a number between 0.0 and 1.0', {safetyFactor});\n }\n\n // Zero disables the check. It used to mean a budget of zero bytes, which refused every file\n // however small - not something any caller can have wanted - so the only reading that makes it\n // useful is \"I will manage memory myself\". This is the documented escape hatch for runtimes\n // whose limits cannot be measured, and for callers who know better than the estimate.\n if (safetyFactor === 0) {\n return;\n }\n\n const budget = getMemoryBudget();\n const rowsToLoad = maxRows === null || maxRows >= totalRows ? totalRows : maxRows;\n const heapMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows, columnCount, materialisesRows);\n const externalMemory = estimateExternalMemory(rowsToLoad, columnCount);\n\n // Each candidate is measured against the memory it actually bounds. The V8 heap limit bounds\n // old space, which TypedArray backing stores do not occupy; a container limit bounds the\n // process, which they do. Checking one figure against both was wrong in both directions at\n // once: it refused columnar reads that fit the heap forty times over, and - once that was\n // fixed by not charging them for rows - it admitted a columnar read allocating 130MB of codes\n // inside a container with less than that, where the kernel answers with a SIGKILL.\n const bounded = budget.candidates.map((candidate) => {\n const heapOnly = candidate.source === 'V8 heap limit';\n\n return {\n ...candidate,\n needs: heapOnly ? heapMemory : heapMemory + externalMemory,\n allowed: candidate.bytes * safetyFactor,\n bounds: heapOnly ? 'the V8 heap' : 'the whole process',\n };\n });\n\n const exceeded = bounded.filter((candidate) => candidate.needs > candidate.allowed);\n const binding = exceeded.reduce(\n (worst, candidate) => (candidate.needs / candidate.allowed > worst.needs / worst.allowed ? candidate : worst),\n exceeded[0],\n );\n\n const heapLimit = getHeapLimit();\n const availableMemory = binding ? binding.bytes : budget.bytes;\n const estimatedMemory = binding ? binding.needs : heapMemory;\n const maxAllowedMemory = binding ? binding.allowed : budget.bytes * safetyFactor;\n\n if (binding) {\n // Bisected against the same estimate this check uses, so the suggestion is one the caller\n // can act on. It used to invert the square-root symbol term alone and could suggest a row\n // count that the very next call rejected.\n const recommendedMaxRows = recommendedRowsFor(\n maxAllowedMemory,\n symbolTableSize,\n totalRows,\n columnCount,\n materialisesRows,\n );\n\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const availableMB = Math.round(maxAllowedMemory / 1024 / 1024);\n // The usable figure, not the reported one. These differ by the 192MB of non-old-space\n // that heap_size_limit counts, and printing the reported one next to a budget breakdown\n // carrying the corrected one told the reader two different things about the same limit -\n // in the one diagnostic whose job is to say which knob to turn.\n const heapLimitMB = Math.round(usableOldSpaceLimit() / 1024 / 1024);\n const reportedHeapLimitMB = Math.round(heapLimit / 1024 / 1024);\n const availableRamMB = Math.round(availableMemory / 1024 / 1024);\n\n // Naming the limit that bound the decision is the difference between an actionable error and\n // a puzzling one: raising --max-old-space-size fixes a heap-bound refusal and does nothing\n // for a container-bound one, where it makes the OOM kill more likely rather than less.\n // The bare source name, because callers match it against memoryBudget[].source - a test\n // pins that. What the limit bounds goes in its own field and into the prose.\n const limitingFactor = binding.source;\n const limitingScope = binding.bounds;\n const budgetBreakdown = budget.candidates\n .map((candidate) => `${candidate.source} ${Math.round(candidate.bytes / 1024 / 1024)}MB`)\n .join(', ');\n const observedBreakdown = budget.observed\n .map((entry) => `${entry.source} ${Math.round(entry.bytes / 1024 / 1024)}MB`)\n .join(', ');\n\n // Saying \"try maxRows: N\" when no N fits sends the caller round a loop, so that case gets its\n // own advice rather than a number that will be rejected on the next call.\n const nothingFits = recommendedMaxRows === 0;\n const containerBound = binding.source === 'container memory limit';\n\n let advice;\n if (nothingFits) {\n advice =\n `No row count fits this budget - the symbol table alone exceeds it, so maxRows cannot help. ` +\n (containerBound\n ? `Raise the container's memory limit.`\n : `Raise the heap with --max-old-space-size, or raise memorySafetyFactor.`);\n } else if (containerBound) {\n advice = `The binding limit is the container's, so raising --max-old-space-size would let V8 grow past it and be killed by the OOM killer instead. Set it below the container limit, raise the limit, or load fewer rows with maxRows (recommended: ${recommendedMaxRows.toLocaleString()} rows or less).`;\n } else {\n advice = `Try loading fewer rows using the maxRows parameter (recommended: ${recommendedMaxRows.toLocaleString()} rows or less), or raise the heap with --max-old-space-size.`;\n }\n\n throw new QvdValidationError(\n `Insufficient memory to load file safely. ` +\n `Symbol table: ${sizeMB}MB, Estimated memory needed: ${estimatedMB}MB, Available: ${availableMB}MB (limited by ${limitingFactor}, which bounds ${limitingScope}; considered: ${budgetBreakdown}; observed but not used: ${observedBreakdown}). ` +\n advice,\n {\n file: filePath,\n symbolTableSize,\n symbolTableSizeMB: sizeMB,\n estimatedMemoryMB: estimatedMB,\n availableMemoryMB: availableMB,\n heapLimitMB,\n reportedHeapLimitMB,\n availableRamMB,\n limitingFactor,\n limitingScope,\n memoryBudget: budget.candidates,\n memoryObserved: budget.observed,\n columnCount,\n totalRows,\n maxRows,\n recommendedMaxRows,\n },\n );\n }\n}\n\n/**\n * Emits a warning for large symbol tables when loading all rows.\n * Warning threshold scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableSize Size of symbol table in bytes\n * @param {number|null} maxRows Maximum number of rows to load (null = all rows)\n * @param {number} totalRows Total number of rows in the file\n * @param {number} [columnCount=0] Columns per row, so the reported figure matches the check\n */\nexport function warnLargeSymbolTable(symbolTableSize, maxRows, totalRows, columnCount = 0, materialisesRows = true) {\n // Dynamic warning threshold: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n // 12.5% of the budget the check uses, not of the figure v8 reports. Thresholding on the\n // reported limit made the warning fire later than the refusal it is meant to precede, and by\n // the widest margin on the small heaps where the 192MB of non-old-space is most of it.\n const LARGE_SYMBOL_TABLE_WARNING = usableOldSpaceLimit() * 0.125;\n\n if (symbolTableSize > LARGE_SYMBOL_TABLE_WARNING && (maxRows === null || maxRows >= totalRows)) {\n const sizeMB = Math.round(symbolTableSize / 1024 / 1024);\n // Same estimate the check uses. Without columnCount this printed the symbol table's cost\n // alone - roughly 3.6GB where the check had just computed 5.2GB - and a caller sizing\n // --max-old-space-size from the warning would pick a heap far too small.\n const estimatedMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows, columnCount, materialisesRows);\n const estimatedMB = Math.round(estimatedMemory / 1024 / 1024);\n const warnMB = Math.round(LARGE_SYMBOL_TABLE_WARNING / 1024 / 1024);\n\n console.warn(\n `⚠️ Large symbol table detected (${sizeMB}MB > ${warnMB}MB threshold). Loading all ${totalRows.toLocaleString()} rows will use ~${estimatedMB}MB RAM. ` +\n `Consider using the maxRows parameter for better performance and lower memory usage.`,\n );\n }\n}\n","// @ts-check\n\nimport {QvdCorruptedError, QvdValidationError} from '../QvdErrors.js';\nimport {getHeapLimit} from './memoryUtils.js';\nimport {MAX_BIT_WIDTH} from './bitUtils.js';\n\n/**\n * Validates symbol table size during initial file read (early check).\n * This is the first-pass validation in _readData for lazy loading.\n * Limit scales with configured heap size (12.5% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdValidationError} If symbol table exceeds dynamic limit\n */\nexport function validateSymbolTableSizeEarly(symbolTableLength, filePath) {\n // Dynamic limit: 12.5% of configured heap size\n // Examples: 4GB heap = 512MB, 8GB heap = 1GB, 16GB heap = 2GB\n const heapLimit = getHeapLimit();\n const MAX_SYMBOL_TABLE_SIZE = heapLimit * 0.125;\n\n if (symbolTableLength > MAX_SYMBOL_TABLE_SIZE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(MAX_SYMBOL_TABLE_SIZE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table too large (${sizeMB}MB exceeds ${maxMB}MB limit for lazy loading). ` +\n `This QVD file contains extremely high-cardinality fields. ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 12.5% = ${maxMB}MB). ` +\n `Consider: (1) loading the full file without maxRows, (2) increasing heap size with --max-old-space-size, or (3) aggregating high-cardinality fields.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: MAX_SYMBOL_TABLE_SIZE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 12.5,\n },\n );\n }\n}\n\n/**\n * Validates symbol table size limits to prevent out-of-memory conditions.\n * This is the comprehensive validation in _parseSymbolTable.\n * Absolute ceiling scales with configured heap size (50% of heap).\n *\n * @param {number} symbolTableLength Size of symbol table in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number} totalRows Total number of rows in the file\n * @throws {QvdValidationError} If symbol table exceeds safety limits\n */\nexport function validateSymbolTableSize(symbolTableLength, filePath, totalRows) {\n // Dynamic absolute ceiling: 50% of configured heap size\n // Examples: 4GB heap = 2GB, 8GB heap = 4GB, 16GB heap = 8GB, 32GB heap = 16GB\n const heapLimit = getHeapLimit();\n const ABSOLUTE_MAX_SYMBOL_TABLE = heapLimit * 0.5;\n\n if (symbolTableLength > ABSOLUTE_MAX_SYMBOL_TABLE) {\n const sizeMB = Math.round(symbolTableLength / 1024 / 1024);\n const maxMB = Math.round(ABSOLUTE_MAX_SYMBOL_TABLE / 1024 / 1024);\n const heapMB = Math.round(heapLimit / 1024 / 1024);\n\n throw new QvdValidationError(\n `Symbol table exceeds absolute maximum size (${sizeMB}MB > ${maxMB}MB). ` +\n `This QVD file has pathological cardinality (likely a data modeling issue). ` +\n `Limit scales with heap size (current: ${heapMB}MB, limit: 50% = ${maxMB}MB). ` +\n `Consider: (1) increasing heap size with --max-old-space-size, (2) aggregating high-cardinality fields, (3) splitting the data, or (4) using a different format.`,\n {\n file: filePath,\n symbolTableSize: symbolTableLength,\n symbolTableSizeMB: sizeMB,\n maxAllowed: ABSOLUTE_MAX_SYMBOL_TABLE,\n maxAllowedMB: maxMB,\n heapLimitMB: heapMB,\n limitPercentage: 50,\n totalRows,\n },\n );\n }\n}\n\n/**\n * Validates field metadata before processing to prevent buffer overflow attacks.\n *\n * @param {any} field Field metadata object\n * @param {number} symbolBufferLength Length of the symbol buffer\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field metadata is invalid\n */\nexport function validateFieldMetadata(field, symbolBufferLength, filePath) {\n const symbolsOffset = parseInt(field['Offset'], 10);\n const symbolsLength = parseInt(field['Length'], 10);\n\n // Validate offset is a valid number and within bounds\n if (isNaN(symbolsOffset) || !Number.isSafeInteger(symbolsOffset) || symbolsOffset < 0) {\n throw new QvdCorruptedError('Invalid symbol offset', {\n field: field['FieldName'],\n offset: symbolsOffset,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate length is a valid number and non-negative\n if (isNaN(symbolsLength) || !Number.isSafeInteger(symbolsLength) || symbolsLength < 0) {\n throw new QvdCorruptedError('Invalid symbol length', {\n field: field['FieldName'],\n length: symbolsLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n // Validate that offset + length doesn't exceed buffer size\n if (symbolsOffset + symbolsLength > symbolBufferLength) {\n throw new QvdCorruptedError('Symbol data extends beyond buffer', {\n field: field['FieldName'],\n offset: symbolsOffset,\n length: symbolsLength,\n bufferSize: symbolBufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n}\n\n/**\n * Validates a header's declared record count.\n *\n * Extracted so the metadata-only read applies exactly the same rule as a load. When they were\n * separate, `readMetadata` coerced an unusable `NoOfRecords` to zero while `fromQvd` refused the\n * same file - so a header with the element deleted reported \"0 rows\" rather than \"this header is\n * broken\", which is indistinguishable from a genuinely empty QVD at the call site.\n *\n * @param {number} totalRows The parsed NoOfRecords.\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {string} [stage='parseIndexTable'] Stage name recorded in the error context.\n * @throws {QvdCorruptedError} If the count is not a non-negative safe integer.\n */\nexport function validateRecordCount(totalRows, filePath, stage = 'parseIndexTable') {\n if (isNaN(totalRows) || !Number.isSafeInteger(totalRows) || totalRows < 0) {\n throw new QvdCorruptedError('Invalid number of records', {\n totalRows,\n file: filePath,\n stage,\n });\n }\n}\n\n/**\n * Validates index table metadata and bounds.\n *\n * @param {number} recordSize Size of a single record in bytes\n * @param {number} totalRows Total number of rows\n * @param {number} indexTableLength Length of the index table\n * @param {number} indexTableOffset Offset to the index table\n * @param {number} bufferLength Length of the buffer\n * @param {number} rowsToLoad Number of rows to load\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {number|null} [fileSize] Actual size of the file on disk, when known. Used to detect a\n * header that describes more data than the file contains.\n * @throws {QvdCorruptedError} If index table metadata is invalid\n */\nexport function validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n indexTableOffset,\n bufferLength,\n rowsToLoad,\n filePath,\n fileSize = null,\n) {\n // Validate recordSize\n if (isNaN(recordSize) || !Number.isSafeInteger(recordSize) || recordSize < 0) {\n throw new QvdCorruptedError('Invalid record byte size', {\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n validateRecordCount(totalRows, filePath);\n\n // Allow recordSize of 0 or 1 only when there are no records (empty QVD)\n // Qlik Sense uses recordSize=1 for empty QVDs\n if (recordSize === 0 && totalRows > 0) {\n throw new QvdCorruptedError('Record byte size cannot be zero when records exist', {\n recordSize,\n totalRows,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate recordSize is reasonable (max 1MB per record)\n if (recordSize > 1048576) {\n throw new QvdCorruptedError('Record byte size exceeds maximum', {\n recordSize,\n maxSize: 1048576,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table length\n if (isNaN(indexTableLength) || !Number.isSafeInteger(indexTableLength) || indexTableLength < 0) {\n throw new QvdCorruptedError('Invalid index table length', {\n length: indexTableLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate index table start offset doesn't extend beyond buffer\n if (indexTableOffset > bufferLength) {\n throw new QvdCorruptedError('Index table offset beyond buffer', {\n indexTableOffset,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // The index table must be exactly as long as the record count implies. Every QVD produced by\n // Qlik or by this library satisfies this, so a mismatch means the header is inconsistent.\n // Checking it catches corrupt headers that would otherwise decode misaligned rows.\n if (indexTableLength !== totalRows * recordSize) {\n throw new QvdCorruptedError('Index table length inconsistent with record count', {\n indexTableLength,\n expectedLength: totalRows * recordSize,\n totalRows,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate the index table against the actual file when its size is known.\n //\n // Comparing against the in-memory buffer instead is wrong in both directions: during a lazy\n // load the buffer is deliberately truncated, so valid large files were rejected as corrupt,\n // while a truncated file whose header claims more data was accepted and silently returned\n // fewer rows than the header declares.\n if (fileSize !== null) {\n if (indexTableOffset + indexTableLength > fileSize) {\n throw new QvdCorruptedError('Index table extends beyond the end of the file', {\n indexTableOffset,\n indexTableLength,\n fileSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n }\n\n // Ensure the loaded buffer actually holds the rows we were asked to parse.\n const requiredIndexBytes = rowsToLoad * recordSize;\n if (indexTableOffset + requiredIndexBytes > bufferLength) {\n throw new QvdCorruptedError('Index table truncated', {\n indexTableOffset,\n requiredBytes: requiredIndexBytes,\n availableBytes: Math.max(0, bufferLength - indexTableOffset),\n rowsToLoad,\n recordSize,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Ensure the index table length is sufficient for the number of rows to load\n if (indexTableLength < requiredIndexBytes) {\n throw new QvdCorruptedError('Index table length smaller than required', {\n indexTableLength,\n requiredBytes: requiredIndexBytes,\n rowsToLoad,\n recordSize,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n\n/**\n * Validates field bit offset and bit width for index table parsing.\n *\n * @param {any} field Field metadata object\n * @param {number} recordSize Size of a single record in bytes\n * @param {string} filePath Path to the QVD file (for error messages)\n * @throws {QvdCorruptedError} If field bit metadata is invalid\n */\nexport function validateFieldBitMetadata(field, recordSize, filePath) {\n const bitOffset = parseInt(field['BitOffset'], 10);\n const bitWidth = parseInt(field['BitWidth'], 10);\n\n // Validate bitOffset\n if (isNaN(bitOffset) || !Number.isSafeInteger(bitOffset) || bitOffset < 0) {\n throw new QvdCorruptedError('Invalid bit offset', {\n field: field['FieldName'],\n bitOffset,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth\n if (isNaN(bitWidth) || !Number.isSafeInteger(bitWidth) || bitWidth < 0) {\n throw new QvdCorruptedError('Invalid bit width', {\n field: field['FieldName'],\n bitWidth,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate Bias.\n //\n // It is added to every decoded index inside an Int32Array, and Int32Array coerces NaN to 0 -\n // so an absent or non-numeric Bias made a file read back as plausible wrong values rather\n // than as an error. A blank <Bias> on a nullable column turned every NULL and every symbol\n // above the first into the first symbol, silently. Validated here alongside the other two\n // because the three travel together and are trusted together.\n const bias = parseInt(field['Bias'], 10);\n\n if (isNaN(bias) || !Number.isSafeInteger(bias)) {\n throw new QvdCorruptedError('Invalid bias', {\n field: field['FieldName'],\n bias: field['Bias'],\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitWidth against what a stored index can be.\n //\n // Indices are kept in an Int32Array, so the value has to fit in a positive 32-bit integer.\n // The bound is not a limitation in practice - 31 bits addresses two billion symbols in one\n // field - and refusing is the safe direction: a 32-bit width lets the top of the range wrap\n // to a negative index, and a negative index means NULL, so the file would read back with\n // plausible wrong values rather than an error.\n if (bitWidth > MAX_BIT_WIDTH) {\n throw new QvdCorruptedError('Bit width exceeds maximum', {\n field: field['FieldName'],\n bitWidth,\n maxBitWidth: MAX_BIT_WIDTH,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n\n // Validate bitOffset + bitWidth doesn't exceed record size in bits\n const recordSizeInBits = recordSize * 8;\n if (bitOffset + bitWidth > recordSizeInBits) {\n throw new QvdCorruptedError('Bit field extends beyond record size', {\n field: field['FieldName'],\n bitOffset,\n bitWidth,\n recordSizeInBits,\n file: filePath,\n stage: 'parseIndexTable',\n });\n }\n}\n","// @ts-check\n\nimport {QvdSymbol} from '../QvdSymbol.js';\nimport {QvdCorruptedError, QvdParseError} from '../QvdErrors.js';\n\n/**\n * Parses an integer symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for an integer\n if (pointer + 4 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading integer symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const byteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 4));\n const value = Buffer.from(byteData).readIntLE(0, byteData.length);\n return {symbol: QvdSymbol.fromIntValue(value), bytesRead: 4};\n}\n\n/**\n * Parses a double symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for a double\n if (pointer + 8 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading double symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const byteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 8));\n const value = Buffer.from(byteData).readDoubleLE(0);\n return {symbol: QvdSymbol.fromDoubleValue(value), bytesRead: 8};\n}\n\n/**\n * Parses a string symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n const startPointer = pointer;\n const maxStringLength = 1048576; // 1MB max string size to prevent memory exhaustion\n let stringLength = 0;\n\n // Find the null terminator\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('String symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n // Ensure we found the null terminator\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('String symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const value = symbolBuffer.subarray(startPointer, pointer).toString('utf-8');\n return {symbol: QvdSymbol.fromStringValue(value), bytesRead: pointer - startPointer + 1};\n}\n\n/**\n * Skips a string symbol in the buffer without parsing it.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {number} Bytes to skip\n */\nexport function skipStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n const startPointer = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('String symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('String symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return pointer - startPointer + 1;\n}\n\n/**\n * Parses a dual integer symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDualIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for an integer\n if (pointer + 4 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading dual integer symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const intByteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 4));\n const intValue = Buffer.from(intByteData).readIntLE(0, intByteData.length);\n pointer += 4;\n\n // Parse the string portion\n const stringStart = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const stringValue = symbolBuffer.subarray(stringStart, pointer).toString('utf-8');\n return {symbol: QvdSymbol.fromDualIntValue(intValue, stringValue), bytesRead: pointer - (stringStart - 4) + 1};\n}\n\n/**\n * Parses a dual double symbol from the buffer.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol and bytes read\n */\nexport function parseDualDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath) {\n // Validate we have enough bytes for a double\n if (pointer + 8 > bufferLength) {\n throw new QvdCorruptedError('Buffer overflow reading dual double symbol', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const doubleByteData = new Int32Array(symbolBuffer.subarray(pointer, pointer + 8));\n const doubleValue = Buffer.from(doubleByteData).readDoubleLE(0);\n pointer += 8;\n\n // Parse the string portion\n const stringStart = pointer;\n const maxStringLength = 1048576;\n let stringLength = 0;\n\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const stringValue = symbolBuffer.subarray(stringStart, pointer).toString('utf-8');\n return {\n symbol: QvdSymbol.fromDualDoubleValue(doubleValue, stringValue),\n bytesRead: pointer - (stringStart - 8) + 1,\n };\n}\n\n/**\n * Skips a dual symbol (integer or double) in the buffer without parsing it.\n *\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position\n * @param {number} bufferLength Length of the buffer\n * @param {number} numericBytes Number of bytes for the numeric portion (4 for int, 8 for double)\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @returns {number} Bytes to skip\n */\nexport function skipDualSymbol(symbolBuffer, pointer, bufferLength, numericBytes, fieldName, filePath) {\n if (pointer + numericBytes > bufferLength) {\n throw new QvdCorruptedError(`Buffer overflow reading dual symbol`, {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n const startPointer = pointer;\n pointer += numericBytes;\n\n // Skip the string portion\n const maxStringLength = 1048576;\n let stringLength = 0;\n while (pointer < bufferLength && symbolBuffer[pointer] !== 0) {\n if (stringLength >= maxStringLength) {\n throw new QvdCorruptedError('Dual string symbol exceeds maximum length', {\n field: fieldName,\n maxLength: maxStringLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n pointer++;\n stringLength++;\n }\n\n if (pointer >= bufferLength) {\n throw new QvdCorruptedError('Dual string symbol not null-terminated', {\n field: fieldName,\n pointer,\n bufferSize: bufferLength,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n\n return pointer - startPointer + 1;\n}\n\n/**\n * Parses a symbol based on the type byte.\n *\n * @param {number} typeByte The type byte\n * @param {Buffer} symbolBuffer The symbol buffer\n * @param {number} pointer Current pointer position (after type byte)\n * @param {number} bufferLength Length of the buffer\n * @param {string} fieldName Name of the field being parsed\n * @param {string} filePath Path to the QVD file (for error messages)\n * @param {boolean} shouldParse Whether to parse the symbol (true) or skip it (false)\n * @returns {{symbol: import('../QvdSymbol.js').QvdSymbol | null, bytesRead: number}} Parsed symbol (or null if skipped) and bytes read\n */\nexport function parseSymbol(typeByte, symbolBuffer, pointer, bufferLength, fieldName, filePath, shouldParse) {\n switch (typeByte) {\n case 1: {\n // Integer value (4 Bytes)\n if (shouldParse) {\n return parseIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n return {symbol: null, bytesRead: 4};\n }\n case 2: {\n // Double value (8 Bytes)\n if (shouldParse) {\n return parseDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n return {symbol: null, bytesRead: 8};\n }\n case 4: {\n // String value (0 terminated)\n if (shouldParse) {\n return parseStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipStringSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n case 5: {\n // Dual (Integer format) value (4 bytes), followed by string format\n if (shouldParse) {\n return parseDualIntegerSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipDualSymbol(symbolBuffer, pointer, bufferLength, 4, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n case 6: {\n // Dual (Double format) value (8 bytes), followed by string format\n if (shouldParse) {\n return parseDualDoubleSymbol(symbolBuffer, pointer, bufferLength, fieldName, filePath);\n }\n const bytesRead = skipDualSymbol(symbolBuffer, pointer, bufferLength, 8, fieldName, filePath);\n return {symbol: null, bytesRead};\n }\n default: {\n throw new QvdParseError('Unknown symbol type byte', {\n typeByte: typeByte.toString(16),\n offset: pointer - 1,\n file: filePath,\n stage: 'parseSymbolTable',\n });\n }\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * One column of a QVD, as the file stores it: a code per row and a dictionary of values.\n *\n * This is the shape the format already has. A QVD does not store a value per cell; it stores a\n * table of distinct symbols per field and an array of indices into it. Keeping that shape is\n * what makes a column cheap - four bytes per row, plus one entry per *distinct* value - and it\n * is why none of the questions that dog a per-row typed array arise here:\n *\n * - A mixed column needs no decision, because nothing per row is typed. On the bundled taxi\n * fixture **no column at all is strictly numeric**: `dropoff_census_tract` is 43% empty\n * strings, and four columns are 100% strings. A `Float64Array` of values would put NaN in\n * 43% of that column and erase Qlik's distinction between a blank and a number.\n * - NULL is a property of the position, not of the value: `codes[row] < 0`. No sentinel is\n * invented, so no sentinel can collide with real data.\n * - An all-null column, a single-valued column and a zero-row column are the same code path.\n */\nexport class QvdColumn {\n /**\n * @param {string} name The field name.\n * @param {Int32Array} codes One stored index per row, bias applied. Negative means NULL.\n * @param {Array<any>} symbols The field's distinct values, indexed by code.\n */\n constructor(name, codes, symbols) {\n this._name = name;\n this._codes = codes;\n this._symbols = symbols;\n\n Object.freeze(this);\n }\n\n /** @return {string} The field name. */\n get name() {\n return this._name;\n }\n\n /** @return {number} Rows in the column. */\n get length() {\n return this._codes.length;\n }\n\n /**\n * The stored index of each row. Negative means NULL.\n *\n * The table's own array, not a copy - it is the thing that makes this cheap, and copying it\n * per call would defeat the point. Treat it as read-only.\n *\n * @return {Int32Array} One code per row.\n */\n get codes() {\n return this._codes;\n }\n\n /**\n * The field's distinct values, indexed by the codes.\n *\n * One entry per distinct value, not per row: a few thousand entries for a column of millions.\n *\n * @return {ReadonlyArray<any>} The dictionary.\n */\n get symbols() {\n return this._symbols;\n }\n\n /**\n * The value of one row.\n *\n * @param {number} row The row index.\n * @return {any} The value, or null where the file stores NULL.\n * @throws {QvdValidationError} If the row is not an integer within the column.\n */\n at(row) {\n if (!Number.isInteger(row) || row < 0 || row >= this._codes.length) {\n throw new QvdValidationError('Row index out of bounds', {\n column: this._name,\n row,\n length: this._codes.length,\n });\n }\n\n const code = this._codes[row];\n\n return code < 0 ? null : this._symbols[code];\n }\n\n /**\n * Iterates the column's values without materialising it.\n *\n * @return {Iterator<any>} An iterator over the values, NULLs included as null.\n */\n [Symbol.iterator]() {\n const codes = this._codes;\n const symbols = this._symbols;\n let row = 0;\n\n return {\n next() {\n if (row >= codes.length) {\n return {done: true, value: undefined};\n }\n\n const code = codes[row++];\n\n return {done: false, value: code < 0 ? null : symbols[code]};\n },\n };\n }\n\n /**\n * The column as a plain array of values, one per row.\n *\n * Lossless, and cell-for-cell what `QvdDataFrame.data[row][column]` would hold. The caller\n * owns the result; the table keeps no reference to it, so two calls return two arrays.\n *\n * @return {Array<any>} One value per row.\n */\n toArray() {\n const out = new Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n out[row] = code < 0 ? null : this._symbols[code];\n }\n\n return out;\n }\n\n /**\n * The dictionary as numbers, for scanning without materialising the column.\n *\n * One entry per *distinct* value, not per row - 17 KB for a column of 1.7 million rows with\n * 2,188 symbols - so this is the cheap conversion, where `toFloat64Array()` is the expensive\n * one. Non-numeric symbols become NaN, which is safe here in a way it is not per row: the\n * codes still distinguish NULL, and a caller that wants the blank back still has `symbols`.\n *\n * Scanning `codes` against this is the fastest way to read a column, because both sides are\n * contiguous typed arrays and the dictionary fits in cache:\n *\n * ```js\n * const codes = column.codes;\n * const values = column.numericSymbols();\n * let total = 0;\n * for (let row = 0; row < codes.length; row++) {\n * const code = codes[row];\n * if (code >= 0) {\n * const value = values[code];\n * if (!Number.isNaN(value)) total += value;\n * }\n * }\n * ```\n *\n * @return {Float64Array} One number per distinct symbol, NaN where the symbol is not a number.\n */\n numericSymbols() {\n const out = new Float64Array(this._symbols.length);\n\n for (let index = 0; index < this._symbols.length; index++) {\n const value = this._symbols[index];\n out[index] = typeof value === 'number' ? value : NaN;\n }\n\n return out;\n }\n\n /**\n * The column as a `Float64Array`.\n *\n * Named for what it costs rather than offered as *the* representation, because it is lossy\n * and on real data it is lossy often: it cannot distinguish a blank from a number, and the\n * bundled taxi fixture has a column that is 43% blank. It therefore refuses by default\n * rather than quietly writing NaN over two fifths of a column.\n *\n * @param {Object} [options] Conversion options.\n * @param {'throw'|'nan'} [options.onNonNumeric='throw'] What to do with a value that is not a\n * number - including NULL. `'throw'` refuses and names the offending row; `'nan'` writes\n * NaN, which is the right choice only when the caller knows the column is numeric.\n * @return {Float64Array} One number per row.\n * @throws {QvdValidationError} If a value is not a number and `onNonNumeric` is `'throw'`.\n */\n toFloat64Array(options = {}) {\n const {onNonNumeric = 'throw'} = options;\n\n if (onNonNumeric !== 'throw' && onNonNumeric !== 'nan') {\n throw new QvdValidationError('onNonNumeric must be \"throw\" or \"nan\"', {\n column: this._name,\n provided: onNonNumeric,\n });\n }\n\n const out = new Float64Array(this._codes.length);\n\n for (let row = 0; row < this._codes.length; row++) {\n const code = this._codes[row];\n const value = code < 0 ? null : this._symbols[code];\n\n if (typeof value === 'number') {\n out[row] = value;\n continue;\n }\n\n if (onNonNumeric === 'throw') {\n throw new QvdValidationError('Column holds a value that is not a number', {\n column: this._name,\n row,\n value,\n type: value === null ? 'null' : typeof value,\n hint: 'Pass {onNonNumeric: \"nan\"} to write NaN instead, or use toArray() to keep the value.',\n });\n }\n\n out[row] = NaN;\n }\n\n return out;\n }\n}\n\n/**\n * A QVD read as columns rather than as rows.\n *\n * The same file, the same decoder and the same symbol resolution as `QvdDataFrame.fromQvd` -\n * it simply stops before building rows, and keeps what the decoder already produced. Measured\n * on `__tests__/data/chicago_taxi_rides/chicago_taxi_rides_2016_01.qvd`, 1,705,805 rows x 20\n * columns, as `heapUsed + external` either side of a forced collection:\n *\n * | | retained | bytes/cell |\n * | --- | --- | --- |\n * | `QvdDataFrame.fromQvd()` | 352.8 MiB | 10.84 |\n * | `QvdColumnTable.fromQvd()` | 38.6 MiB | 1.18 |\n *\n * It is not a data frame and does not become one. Offering a conversion would let a caller hold\n * both representations at once, which is the one configuration in which this costs more than it\n * saves. Re-reading a file as rows costs what reading it as rows always cost; there is no\n * saving to protect by avoiding that.\n */\nexport class QvdColumnTable {\n /**\n * @param {Object} decoded What the reader decoded.\n * @param {Array<string>} decoded.columns Field names, in file order.\n * @param {Array<Int32Array>} decoded.codesByField One code array per field.\n * @param {Array<Array<any>>} decoded.symbolsByField One dictionary per field.\n * @param {number} decoded.rowCount Rows decoded.\n * @param {any} decoded.metadata The raw QvdTableHeader.\n * @param {any} decoded.loadStats Statistics about the read.\n */\n constructor({columns, codesByField, symbolsByField, rowCount, metadata, loadStats}) {\n this._columns = columns;\n this._codesByField = codesByField;\n this._symbolsByField = symbolsByField;\n this._rowCount = rowCount;\n this._metadata = metadata;\n this._loadStats = loadStats;\n }\n\n /**\n * Reads a QVD file as columns.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Loading options, with the same meanings they have on `fromQvd`.\n * @param {number|null} [options.maxRows] Maximum rows to decode.\n * @param {string} [options.allowedDir] Directory the path must resolve inside.\n * @param {number} [options.memorySafetyFactor] Fraction of the memory budget a load may use.\n * @param {number} [options.symbolFilteringThreshold] Symbol table size above which a limited\n * read switches to two-pass filtering.\n * @return {Promise<QvdColumnTable>} The file, as columns.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n const reader = new QvdFileReader(path, {\n allowedDir: options.allowedDir,\n memorySafetyFactor: options.memorySafetyFactor,\n symbolFilteringThreshold: options.symbolFilteringThreshold,\n\n // This read builds no rows, so the memory guard must not charge it for them. A columnar\n // read of the 38MB taxi fixture completes in a 15MB heap; charged the row cost it was\n // refused below a 2GB one.\n materialisesRows: false,\n });\n\n return await reader.loadColumnar(options.maxRows !== undefined ? options.maxRows : null);\n }\n\n /** @return {Array<string>} Field names, in file order. */\n get columns() {\n return this._columns;\n }\n\n /** @return {number} Rows decoded. */\n get rowCount() {\n return this._rowCount;\n }\n\n /** @return {Array<number>} `[rows, columns]`, as on a data frame. */\n get shape() {\n return [this._rowCount, this._columns.length];\n }\n\n /** @return {any} The raw `QvdTableHeader`. */\n get metadata() {\n return this._metadata;\n }\n\n /** @return {any} Statistics about the read. */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * One column.\n *\n * @param {string} name The field name.\n * @return {QvdColumn} The column.\n * @throws {QvdValidationError} If the field is not in this file.\n */\n column(name) {\n const index = this._columns.indexOf(name);\n\n if (index === -1) {\n throw new QvdValidationError(`Column '${name}' does not exist`, {\n column: name,\n availableColumns: this._columns,\n });\n }\n\n return new QvdColumn(name, this._codesByField[index], this._symbolsByField[index]);\n }\n}\n","// @ts-check\n\nimport fs from 'fs';\nimport xml from 'xml2js';\nimport assert from 'assert';\nimport {QvdDataFrame} from './QvdDataFrame.js';\nimport {QvdParseError, QvdValidationError, QvdCorruptedError} from './QvdErrors.js';\nimport {validatePath} from './util/validatePath.js';\nimport {decodeIndexColumn} from './util/bitUtils.js';\nimport {validateMemoryAvailability, warnLargeSymbolTable} from './util/memoryUtils.js';\nimport {\n validateSymbolTableSize,\n validateSymbolTableSizeEarly,\n validateFieldMetadata,\n validateIndexTableMetadata,\n validateFieldBitMetadata,\n validateRecordCount,\n} from './util/validationUtils.js';\nimport {parseSymbol} from './util/symbolParser.js';\n\n/**\n * Maximum number of bytes searched for the XML header delimiter before giving up.\n * Real QVD headers are a few kilobytes; the largest observed is well under 100KB.\n */\nconst MAX_HEADER_SIZE = 16 * 1024 * 1024;\n\n/**\n * Maximum length of a single fs.read call. Node's fs.read binding requires the length to fit\n * in an Int32: a larger value aborts the process via a C++ assertion instead of throwing.\n */\nconst READ_CHUNK_SIZE = 512 * 1024 * 1024;\n\n/**\n * Parses a QVD file and loads it into memory.\n */\nexport class QvdFileReader {\n /**\n * Constructs a new QVD file parser.\n *\n * @param {string} filePath The path to the QVD file to load.\n * @param {Object} [options={}] Options for the reader.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file\n * path must be within this directory, with symlinks resolved first, so a link inside it that\n * points outside it is rejected. Defaults to the current working directory. To permit\n * an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or\n * empty value falls back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.3] Fraction (0.0-1.0) of the memory budget a\n * load may use. The budget is the smallest of the V8 heap limit, any container memory limit,\n * and the memory the OS reports as available. Default is 0.3. **Zero disables the memory\n * check entirely**, which is the escape hatch for runtimes whose limits cannot be measured -\n * Bun reports its current heap as its heap limit - and for callers who would rather manage\n * memory themselves than trust the estimate.\n * @param {boolean} [options.materialisesRows=true] Whether this read will build row arrays.\n * False for a columnar read, whose memory is TypedArray backing stores outside the V8 heap\n * and which must not be charged the row cost.\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes,\n * above which a lazy load switches to the two-pass filtering path. The default of 50MB is\n * the point where the extra analysis pass pays for itself; lower it to use filtering on\n * smaller files, raise it to keep the simpler single-pass read for longer.\n */\n constructor(filePath, options = {}) {\n const {\n allowedDir,\n memorySafetyFactor = 0.8,\n symbolFilteringThreshold = 50 * 1024 * 1024,\n materialisesRows = true,\n } = options;\n this._materialisesRows = materialisesRows;\n this._path = validatePath(filePath, allowedDir);\n this._memorySafetyFactor = memorySafetyFactor;\n this._symbolFilteringThreshold = symbolFilteringThreshold;\n this._buffer = null;\n this._headerOffset = null;\n this._symbolTableOffset = null;\n this._indexTableOffset = null;\n this._header = null;\n /** @type {Array<Array<import('./QvdSymbol.js').QvdSymbol>>|null} */\n this._symbolTable = null;\n /**\n * Stored symbol indices, one Int32Array per field rather than one array per row.\n *\n * Column-major because that is what lets the decoder hoist a field's bit offset, width and\n * bias out of the row loop and write straight into a typed array - no allocation per row or\n * per cell. Renamed from `_indexTable` deliberately: the shape changed, and a reader of this\n * code should not have to discover that from the subscripts.\n *\n * @type {Array<Int32Array>|null}\n */\n this._indexColumns = null;\n\n /** Rows actually decoded into `_indexColumns`. @type {number} */\n this._rowsDecoded = 0;\n /** @type {number|null} */\n this._fileSize = null;\n /** Whether the header's declared extent fits inside the file. False until _readData says so. */\n this._headerMatchesFile = false;\n }\n\n /**\n * Reads the binary data of the QVD file.\n *\n * LAZY LOADING OPTIMIZATION: When maxRows is specified, this method implements\n * true lazy loading by reading only the necessary portions of the file from disk.\n *\n * For large files (e.g., 5GB), loading only the first 1000 rows can save significant\n * memory and time:\n * - Full load: 5GB in memory, ~30-60s load time\n * - Lazy load (maxRows=1000): ~1.75-2GB in memory, ~2-5s load time\n *\n * Algorithm for Lazy Loading:\n * 1. Stream-read the file until XML header delimiter is found\n * 2. Parse header to determine symbol table and index table locations\n * 3. Calculate bytes needed: header + full symbol table + partial index table\n * 4. Read only those calculated bytes using fs.open/read\n * 5. Rest of parsing proceeds normally with limited data\n *\n * WHY THIS APPROACH:\n * - Symbol table must be fully loaded (contains all unique values)\n * - Index table can be partially loaded (only rows we need)\n * - Streaming for header finding is efficient for unknown header sizes\n * - Direct byte-range reading for remaining data is fastest\n *\n * @param {number|null} maxRows The maximum number of rows to load. If null, all data is loaded.\n * @param {boolean} [headerOnly=false] Stop once the XML header has been read, leaving the\n * symbol and index tables on disk. This is the metadata-only path: the header is a few\n * kilobytes whatever the file's size, so reading a schema costs the same for a 40MB file as\n * for a 40GB one.\n * @private\n */\n async _readData(maxRows = null, headerOnly = false) {\n // The header is scanned first on both paths, including a full load that is about to read the\n // whole file anyway. It costs a few kilobytes and it is what lets the memory check run\n // *before* the body is read: otherwise a 1.7GB file is loaded into memory in full and only\n // then refused, which is the opposite of what a safety check is for.\n const HEADER_DELIMITER = '\\r\\n\\0';\n const CHUNK_SIZE = 64 * 1024; // 64KB chunks - balance between memory and I/O efficiency\n\n // Use streaming to find the header delimiter dynamically\n // We don't know header size in advance, so we must stream-read\n const stream = fs.createReadStream(this._path, {\n highWaterMark: CHUNK_SIZE,\n });\n\n /** @type {Array<Buffer>} */\n const headerChunks = [];\n let headerBytes = 0;\n /** Last (delimiter length - 1) bytes seen so far, carried across chunk boundaries. */\n let tail = Buffer.alloc(0);\n let headerDelimiterIndex = -1;\n\n try {\n // Read chunks until we find the delimiter.\n //\n // Chunks are collected and concatenated once, and each chunk is searched individually\n // (with a small carry-over so a delimiter straddling a chunk boundary is still found).\n // Concatenating the whole accumulated buffer on every chunk and re-scanning it from the\n // start is quadratic: a 200 MB delimiter-less file cost 43 s and 13 GB of memory.\n for await (const chunk of stream) {\n // Search the new chunk prefixed by the bytes already seen, so a delimiter spanning a\n // chunk boundary is not missed.\n //\n // The carry is kept in `tail` across iterations rather than read back off the previous\n // chunk, because a chunk may be shorter than the delimiter. Taking min(bytesSoFar, 2)\n // bytes from a 1-byte previous chunk yields only 1 byte, which both misses a delimiter\n // spread over three chunks and leaves the reported offset short by the difference.\n const chunkStart = headerBytes;\n const searchBuffer = tail.length > 0 ? Buffer.concat([tail, chunk]) : chunk;\n const foundInSearch = searchBuffer.indexOf(HEADER_DELIMITER);\n\n headerChunks.push(chunk);\n headerBytes += chunk.length;\n\n if (foundInSearch !== -1) {\n // searchBuffer starts tail.length bytes before this chunk does.\n headerDelimiterIndex = chunkStart - tail.length + foundInSearch;\n stream.destroy();\n break;\n }\n\n // Copy the carry instead of keeping a subarray view, which would pin the whole chunk.\n tail = Buffer.from(searchBuffer.subarray(-(HEADER_DELIMITER.length - 1)));\n\n // Real QVD headers are a few kilobytes. Without a cap, a non-QVD or corrupt file is\n // read to its end before the error below is raised, which is a denial-of-service\n // vector for any service that accepts uploaded files.\n if (headerBytes > MAX_HEADER_SIZE) {\n stream.destroy();\n throw new QvdCorruptedError(\n `The XML header delimiter was not found within the first ${MAX_HEADER_SIZE / (1024 * 1024)}MB of the file.`,\n {\n file: this._path,\n bytesSearched: headerBytes,\n maxHeaderSize: MAX_HEADER_SIZE,\n stage: 'readData',\n },\n );\n }\n }\n } catch (error) {\n // Destroying the stream once the delimiter is found surfaces as ERR_STREAM_PREMATURE_CLOSE.\n // That one case is expected and ignored; everything else must propagate.\n //\n // The previous condition also required a 'code' property, so any error without one — a\n // TypeError or RangeError raised in the loop body, or a stream error from a source that\n // does not set a code — was swallowed. Execution then fell through to the generic\n // 'header not properly delimited' error below, reporting file corruption for what was\n // actually a bug or an I/O failure.\n const isExpectedEarlyClose =\n headerDelimiterIndex !== -1 &&\n error !== null &&\n typeof error === 'object' &&\n /** @type {{code?: unknown}} */ (error).code === 'ERR_STREAM_PREMATURE_CLOSE';\n\n if (!isExpectedEarlyClose) {\n throw error;\n }\n }\n\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'readData',\n },\n );\n }\n\n const headerBuffer = Buffer.concat(headerChunks);\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n\n // Parse header to get metadata about symbol and index table locations\n const headerXml = headerBuffer.subarray(0, headerEndIndex).toString();\n const headerObj = await xml.parseStringPromise(headerXml, {explicitArray: false});\n\n if (!headerObj) {\n throw new QvdParseError('The XML header could not be parsed.', {\n file: this._path,\n stage: 'readData',\n });\n }\n\n const symbolTableOffset = headerEndIndex;\n const symbolTableLength = parseInt(headerObj['QvdTableHeader']['Offset'], 10);\n const indexTableOffset = symbolTableOffset + symbolTableLength;\n const recordSize = parseInt(headerObj['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(headerObj['QvdTableHeader']['NoOfRecords'], 10);\n\n if (headerOnly) {\n // The header, and not one byte more. `headerChunks` holds whole 64KB chunks, so the tail\n // of the last one is whatever followed the delimiter; trimming it is what keeps this\n // constant-cost rather than \"the header plus up to 64KB of symbol table\".\n //\n // This returns before the memory check below on purpose. That check sizes the rows a call\n // will materialise, and this call materialises none - running it would let a file too\n // large to load refuse to report its own schema, which is the opposite of the point.\n //\n // _parseHeader runs next and re-derives the offsets from this buffer, exactly as it does\n // on the full path. Nothing downstream of it is reached, because there are no rows.\n this._buffer = headerBuffer.subarray(0, headerEndIndex);\n return;\n }\n\n // Column count drives the largest term in the memory estimate, because what actually\n // exhausts the heap on a many-row file is one array per row plus one slot per cell - not the\n // symbol table, which for the commonest Qlik shape is tiny.\n let headerFields = headerObj['QvdTableHeader']?.['Fields']?.['QvdFieldHeader'];\n if (headerFields && !Array.isArray(headerFields)) {\n headerFields = [headerFields];\n }\n const columnCount = Array.isArray(headerFields) ? headerFields.length : 0;\n\n // SAFETY CHECK: enough memory to materialise the rows this call will produce. Runs here,\n // before any large read, so a file too big to hold is refused rather than read and refused.\n //\n // Two conditions gate it, and both exist so that a corrupt file keeps its accurate diagnosis\n // instead of being reported as an out-of-memory problem.\n //\n // The numbers have to be usable at all - a NaN or negative Offset would produce a nonsense\n // estimate - and they have to be consistent with the file on disk. The estimate is computed\n // from NoOfRecords, so a header that overstates it produces an enormous figure: a truncated\n // 3KB file claiming 900 million rows was refused for needing 530GB of RAM, when what it\n // actually needs is to be re-downloaded. Where the file contradicts its own header, this\n // declines to make a memory claim and lets the structural checks downstream say what is\n // really wrong.\n const headerNumbersUsable = [symbolTableLength, recordSize, totalRows].every(\n (value) => Number.isSafeInteger(value) && value >= 0,\n );\n\n if (headerNumbersUsable) {\n const {size: fileSize} = await fs.promises.stat(this._path);\n this._fileSize = fileSize;\n this._headerMatchesFile = headerEndIndex + symbolTableLength + totalRows * recordSize <= fileSize;\n }\n\n if (headerNumbersUsable && this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolTableLength,\n maxRows,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n columnCount,\n this._materialisesRows,\n );\n }\n\n if (maxRows === null) {\n // Load entire file into memory (original behavior)\n // This is simple and fast for small to medium files\n this._buffer = await fs.promises.readFile(this._path);\n this._fileSize = this._buffer.length;\n return;\n }\n\n const rowsToLoad = Math.min(maxRows, totalRows);\n\n // SAFETY CHECK: Very large symbol tables are still blocked to prevent OOM. Lazy loads only -\n // a full load is bounded by validateSymbolTableSize instead, which allows more.\n validateSymbolTableSizeEarly(symbolTableLength, this._path);\n\n // Validate the header numbers before they are used to size an allocation. Without this,\n // a NaN or negative value reaches Buffer.alloc and surfaces as a raw Node RangeError.\n for (const [name, value] of [\n ['Offset', symbolTableLength],\n ['RecordByteSize', recordSize],\n ['NoOfRecords', totalRows],\n ]) {\n if (!Number.isSafeInteger(value) || Number(value) < 0) {\n throw new QvdCorruptedError(`Invalid header value: ${name}`, {\n name,\n value,\n file: this._path,\n stage: 'readData',\n });\n }\n }\n\n // Calculate how much of the index table we need to read\n const indexTableBytesToRead = rowsToLoad * recordSize;\n\n // Calculate total bytes needed: header + symbol table + partial index table\n const totalBytesToRead = indexTableOffset + indexTableBytesToRead;\n\n // Now read the exact portion we need from the file\n const fd = await fs.promises.open(this._path, 'r');\n try {\n const {size: fileSize} = await fd.stat();\n this._fileSize = fileSize;\n\n // The buffer size is derived entirely from header values, which may not describe the\n // file on disk (truncated download, interrupted copy, file still being written, or a\n // deliberately crafted header). Reading past the end would otherwise leave the tail of\n // the buffer holding whatever memory the allocator handed out, and that memory is then\n // parsed as symbol and index data.\n if (totalBytesToRead > fileSize) {\n throw new QvdCorruptedError('The file is shorter than its header claims.', {\n file: this._path,\n fileSize,\n requiredBytes: totalBytesToRead,\n stage: 'readData',\n });\n }\n\n // Zero-filled rather than allocUnsafe: if any path ever fails to overwrite part of this\n // buffer, the result is zeros instead of leaked process memory.\n this._buffer = Buffer.alloc(totalBytesToRead);\n\n // Read in bounded chunks, checking bytesRead each time. A single fs.read call with a\n // length of 2^31 or more does not throw - it trips a C++ assertion and aborts the whole\n // process, which no try/catch can intercept.\n let position = 0;\n while (position < totalBytesToRead) {\n const length = Math.min(READ_CHUNK_SIZE, totalBytesToRead - position);\n // @ts-ignore - Buffer type compatibility\n const {bytesRead} = await fd.read(this._buffer, position, length, position);\n\n if (bytesRead === 0) {\n throw new QvdCorruptedError('Unexpected end of file while reading QVD data.', {\n file: this._path,\n fileSize,\n bytesRead: position,\n requiredBytes: totalBytesToRead,\n stage: 'readData',\n });\n }\n\n position += bytesRead;\n }\n } finally {\n await fd.close();\n }\n }\n\n /**\n * Parses the XML header of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n */\n async _parseHeader() {\n if (!this._buffer) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const HEADER_DELIMITER = '\\r\\n\\0';\n\n const headerBeginIndex = 0;\n const headerDelimiterIndex = this._buffer.indexOf(HEADER_DELIMITER, headerBeginIndex);\n\n // Check explicitly for -1 (not found) rather than using falsy check (!headerDelimiterIndex)\n // because indexOf() returns 0 when the delimiter is at position 0, which is a valid buffer index.\n // Using !0 would incorrectly treat position 0 as an error.\n if (headerDelimiterIndex === -1) {\n throw new QvdCorruptedError(\n 'The XML header section does not exist or is not properly delimited from the binary data.',\n {\n file: this._path,\n stage: 'parseHeader',\n },\n );\n }\n\n const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;\n const headerBuffer = this._buffer.subarray(headerBeginIndex, headerEndIndex);\n\n /*\n * The following instruction parses the XML header into a JSON object. It is important to\n * note that the object is a plain JavaScript object and not an instance of representative\n * class. Hence, types are not casted, therefore all raw values are strings, and child nodes\n * that contain an array of objects are not represented directly as an array but as an object\n * with a property, named like the array item tag, that is an array of the actual objects. The\n * same applies to child nodes that contain a single object and the root node.\n *\n * The following XML representation of the QVD header for example...\n *\n * <QvdTableHeader>\n * ...\n * <Fields>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * <QvdFieldHeader>\n * <FieldName>Field1</FieldName>\n * ...\n * </QvdFieldHeader>\n * </Fields>\n * </QvdTableHeader>\n *\n * ...is parsed into the following object:\n *\n * {\n * QvdTableHeader: {\n * ...,\n * Fields: {\n * QvdFieldHeader: [\n * { FieldName: 'Field1', ...},\n * { FieldName: 'Field2', ...}\n * ]\n * }\n * }\n * }\n */\n\n // Note: xml2js (via sax-js) does not support external entity resolution\n // by default, providing inherent protection against XXE attacks.\n this._header = await xml.parseStringPromise(headerBuffer.toString(), {explicitArray: false});\n\n if (!this._header) {\n throw new QvdParseError('The XML header could not be parsed.', {\n file: this._path,\n stage: 'parseHeader',\n });\n }\n\n /*\n * Because the three parts of the QVD file, header, symbol and index table, are seamlessly concatenated,\n * the end of the respective previous part is the beginning of the next part.\n */\n\n // A header with no field elements, validated here rather than at each use.\n //\n // Three places downstream normalise the field list with\n // `if (!Array.isArray(fields)) fields = [fields]`, which turns an absent `<Fields/>` into\n // `[undefined]` and then dereferences it - a bare TypeError from the middle of the reader\n // where readMetadata, which checks, reports the file as corrupt. Checking once, at the\n // point the header becomes available, means every path downstream can assume a field list.\n const fields = this._header['QvdTableHeader']?.['Fields']?.['QvdFieldHeader'];\n const fieldCount = fields === undefined || fields === null ? 0 : Array.isArray(fields) ? fields.length : 1;\n\n if (fieldCount === 0) {\n throw new QvdCorruptedError('The QVD file header declares no fields', {\n file: this._path,\n stage: 'parseHeader',\n });\n }\n\n this._headerOffset = headerBeginIndex;\n this._symbolTableOffset = headerEndIndex;\n this._indexTableOffset = this._symbolTableOffset + parseInt(this._header['QvdTableHeader']['Offset'], 10);\n }\n\n /**\n * Establishes the geometry of the index table, and validates it.\n *\n * Both passes over the index table - the symbol-usage analysis and the decode itself - need\n * exactly this, and they used to derive it separately with two copies of the same bit\n * unpacking. The copies are the reason the bias comment in the analysis pass warns so loudly\n * about keeping the sign in step with the other one: the two could drift, and #113 is what\n * that looks like when they do. There is one copy now.\n *\n * @param {number|null} rowLimit Maximum rows of interest, or null for all of them.\n * @param {string} stage Stage name for any error raised here.\n * @return {{fields: Array<any>, recordSize: number, totalRows: number, rowsToLoad: number,\n * indexBuffer: Buffer}} The record geometry.\n * @private\n */\n _planIndexTable(rowLimit, stage) {\n if (!this._buffer || !this._header || !this._indexTableOffset) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage,\n },\n );\n }\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n // Size of a single row of the index table in bytes\n const recordSize = parseInt(this._header['QvdTableHeader']['RecordByteSize'], 10);\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n const rowsToLoad = rowLimit !== null ? Math.min(rowLimit, totalRows) : totalRows;\n const indexTableLength = parseInt(this._header['QvdTableHeader']['Length'], 10);\n\n // Validate all index table metadata\n validateIndexTableMetadata(\n recordSize,\n totalRows,\n indexTableLength,\n this._indexTableOffset,\n this._buffer.length,\n rowsToLoad,\n this._path,\n this._fileSize,\n );\n\n const indexBuffer = this._buffer.subarray(this._indexTableOffset, this._indexTableOffset + indexTableLength + 1);\n\n // Validate BitOffset and BitWidth for all fields before processing\n for (const field of fields) {\n validateFieldBitMetadata(field, recordSize, this._path);\n }\n\n // The decoder indexes into the buffer without per-row bounds checks, which is only sound\n // because validateIndexTableMetadata has already established that the buffer holds\n // rowsToLoad whole records: it requires indexTableLength >= rowsToLoad * recordSize and\n // indexTableOffset + rowsToLoad * recordSize <= buffer.length, and indexBuffer spans from\n // the offset to the end of the declared table. The row loop this replaced re-checked per\n // record, which was dead code for the same reason.\n //\n // Stated as an assertion rather than dropped, because relaxing any of those checks later\n // would make the decode read past the end - where an out-of-range byte is undefined, the\n // arithmetic yields NaN, and the stored index silently becomes 0. Better to fail here.\n assert(\n rowsToLoad === 0 || recordSize === 0 || Math.floor(indexBuffer.length / recordSize) >= rowsToLoad,\n `The index table holds ${Math.floor(indexBuffer.length / (recordSize || 1))} whole records ` +\n `but ${rowsToLoad} were validated as present.`,\n );\n\n return {fields, recordSize, totalRows, rowsToLoad, indexBuffer};\n }\n\n /**\n * Analyzes the index table to determine which symbols are actually needed.\n * This is used for two-pass symbol filtering optimization.\n *\n * @param {number} maxRows The maximum number of rows to analyze.\n * @return {Promise<Map<string, Set<number>>>} Map of field names to Set of needed symbol indices.\n * @private\n */\n async _analyzeIndexTableSymbolUsage(maxRows) {\n const {fields, recordSize, rowsToLoad, indexBuffer} = this._planIndexTable(maxRows, 'analyzeIndexTableSymbolUsage');\n\n // Map of field name -> Set of symbol indices needed\n /** @type {Map<string, Set<number>>} */\n const symbolUsage = new Map();\n\n // One column's worth of indices, reused across fields: the analysis only needs the distinct\n // values, so there is no reason to keep more than one decoded column alive at a time.\n const column = new Int32Array(rowsToLoad);\n\n fields.forEach((/** @type {any} */ field) => {\n const needed = new Set();\n symbolUsage.set(field['FieldName'], needed);\n\n // The bias is applied inside the decoder, which is the same call the parse pass makes.\n // When these were two separate unpackings, a sign difference here would have recorded the\n // wrong symbols as needed and every affected cell would have read back as undefined -\n // silently, because nothing throws on an index that addresses no symbol.\n decodeIndexColumn(\n indexBuffer,\n recordSize,\n rowsToLoad,\n parseInt(field['BitOffset'], 10),\n parseInt(field['BitWidth'], 10),\n parseInt(field['Bias'], 10),\n column,\n );\n\n for (let row = 0; row < rowsToLoad; row++) {\n // Negative indices denote NULL and reference no symbol, so they never need to be kept.\n if (column[row] >= 0) {\n needed.add(column[row]);\n }\n }\n });\n\n return symbolUsage;\n }\n\n /**\n * Parses the symbol table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * @param {Map<string, Set<number>>|null} symbolsToKeep Optional map of field names to symbol indices to keep.\n * If provided, only these symbols will be parsed (two-pass filtering optimization).\n * @param {number|null} maxRows Optional maximum number of rows being loaded (for memory estimation).\n */\n async _parseSymbolTable(symbolsToKeep = null, maxRows = null) {\n if (!this._buffer || !this._header || !this._symbolTableOffset || !this._indexTableOffset) {\n throw new QvdCorruptedError(\n 'The QVD file has not been loaded in the proper order or has not been loaded at all.',\n {\n file: this._path,\n stage: 'parseSymbolTable',\n },\n );\n }\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n const symbolBuffer = this._buffer.subarray(this._symbolTableOffset, this._indexTableOffset);\n const symbolTableSize = symbolBuffer.length;\n const totalRows = parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10);\n\n // SAFETY CHECK 1: Absolute ceiling to prevent pathological cases\n // Phase 2.5 optimization allows much larger symbol tables when using maxRows,\n // but we still need an absolute maximum to prevent truly extreme cases\n validateSymbolTableSize(symbolTableSize, this._path, totalRows);\n\n // SAFETY CHECK 2: Dynamic memory validation, now against the symbol table's real size rather\n // than the size its header declared. _readData already ran this check before reading\n // anything; this is the more accurate second look, and the two agree on a well-formed file.\n //\n // Skipped on the same condition as the early one. This is the call that mattered: the\n // structural checks that identify a truncated file run in _parseIndexTable, after this, so\n // an estimate built on an inflated NoOfRecords would report a memory problem for a file\n // whose real problem is that it is short.\n if (this._headerMatchesFile) {\n validateMemoryAvailability(\n symbolTableSize,\n maxRows,\n totalRows,\n this._path,\n this._memorySafetyFactor,\n Array.isArray(fields) ? fields.length : 1,\n this._materialisesRows,\n );\n }\n\n // WARNING ZONE: Large files without maxRows parameter\n // Educate users about best practices but don't block\n warnLargeSymbolTable(\n symbolTableSize,\n maxRows,\n totalRows,\n Array.isArray(fields) ? fields.length : 1,\n this._materialisesRows,\n );\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n /*\n * The symbol table is a contiguous byte array that contains all possible symbols/values of all fields/columns.\n * The symbols/values of one field are stored consecutively in the same order as the fields/columns are defined\n * in the header. The length of the symbol area as well as it's offset, relativ to the begin of the symbol\n * table, are also defined in the header.\n */\n\n // Validate all field metadata before processing to prevent buffer overflow attacks\n for (const field of fields) {\n validateFieldMetadata(field, symbolBuffer.length, this._path);\n }\n\n // Parse all possible symbols of each field/column\n // Phase 2.5 optimization: Skip parsing entirely for symbols we don't need\n this._symbolTable = fields.map((/** @type {any} */ field) => {\n const symbolsOffset = parseInt(field['Offset'], 10); // Offset of the column's symbol area in the symbol table\n const symbolsLength = parseInt(field['Length'], 10); // Length of the column's symbol area in the symbol table\n\n const fieldName = field['FieldName'];\n const neededSymbols = symbolsToKeep ? symbolsToKeep.get(fieldName) : null;\n const filteringEnabled = neededSymbols !== null;\n\n const symbols = [];\n let symbolIndex = 0; // Track current symbol index as we parse\n\n // Parse all possible values of the current field/column\n for (let pointer = symbolsOffset; pointer < symbolsOffset + symbolsLength; pointer++) {\n // Each stored symbol consists of a type byte and the actual value, which length depends on the type\n const typeByte = symbolBuffer[pointer++];\n\n // Check if we should keep this symbol (filtering mode)\n const shouldKeepSymbol = !filteringEnabled || !!(neededSymbols && neededSymbols.has(symbolIndex));\n\n // Use utility function to parse or skip symbol\n const {symbol, bytesRead} = parseSymbol(\n typeByte,\n symbolBuffer,\n pointer,\n symbolBuffer.length,\n fieldName,\n this._path,\n shouldKeepSymbol,\n );\n\n symbols.push(symbol);\n pointer += bytesRead - 1; // -1 because the loop will increment\n symbolIndex++;\n }\n\n return symbols;\n // @ts-ignore - Symbol table type assignment\n });\n }\n\n /**\n * Parses the bit stuffed index table of the QVD file. This method is part of the parsing process\n * and should not be called directly.\n *\n * One `Int32Array` per field, filled by `decodeIndexColumn`, replacing an array per row filled\n * a bit at a time. The old route, per row, built an `Int32Array` of the record's bytes,\n * concatenated a binary string of `recordSize * 8` characters, split it into a character\n * array, reversed that, and mapped it to one number per *bit*; then per cell it sliced the\n * result again and summed `bit * Math.pow(2, index)`. Several arrays the length of the record\n * in bits, built and discarded for every row.\n *\n * Column-major is what makes the decode tight: a field's bit offset, width and bias are the\n * same for every row, so they are hoisted out of the loop and the inner loop does arithmetic\n * into a typed array and nothing else. Rows are assembled later, once, in `load()`.\n *\n * @param {number|null} maxRows The maximum number of rows to parse. If null, all rows are parsed.\n */\n async _parseIndexTable(maxRows = null) {\n const {fields, recordSize, rowsToLoad, indexBuffer} = this._planIndexTable(maxRows, 'parseIndexTable');\n\n this._rowsDecoded = rowsToLoad;\n this._indexColumns = fields.map((/** @type {any} */ field) =>\n decodeIndexColumn(\n indexBuffer,\n recordSize,\n rowsToLoad,\n parseInt(field['BitOffset'], 10),\n parseInt(field['BitWidth'], 10),\n parseInt(field['Bias'], 10),\n new Int32Array(rowsToLoad),\n ),\n );\n }\n\n /**\n * Reads the file's schema and header metadata, without touching the symbol or index tables.\n *\n * Constant cost in the size of the file. `fromQvd(path, {maxRows: 0})` is not the same thing\n * and never was: the lazy path reads `headerEnd + symbolTableLength + rowsToLoad * recordSize`\n * bytes, so it still pulls the entire symbol table - 0.4MB on the taxi fixture, but hundreds\n * of megabytes on a high-cardinality file, and it has to be parsed as well as read.\n *\n * The memory check is deliberately not run for this. It sizes the rows a call will\n * materialise, and this materialises none; applying it would let a file too large to load\n * refuse to say what is in it.\n *\n * @return {Promise<import('./QvdDataFrame.js').QvdFileMetadata>} The file's schema and header.\n */\n async loadMetadata() {\n await this._readData(null, true);\n await this._parseHeader();\n\n assert(this._header, 'The QVD file header has not been parsed.');\n\n const header = this._header['QvdTableHeader'];\n\n let fields = header['Fields']?.['QvdFieldHeader'] ?? [];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n // A header that declares no fields is a broken header, not a table with no columns, and\n // reporting `columnCount: 0` for it would be the same kind of plausible-but-wrong answer\n // this library keeps having to design against. Loading such a file throws too.\n if (fields.length === 0) {\n throw new QvdCorruptedError('The QVD file header declares no fields', {\n file: this._path,\n stage: 'readMetadata',\n });\n }\n\n const columns = fields.map((/** @type {any} */ field) => field['FieldName']);\n const rowCount = parseInt(header['NoOfRecords'], 10);\n\n // The same rule a load applies, through the same function. Coercing an unusable value to\n // zero here instead would report a damaged 606-row file as empty, and `rowCount` is exactly\n // what a caller is expected to branch on.\n validateRecordCount(rowCount, this._path, 'readMetadata');\n\n // An empty frame carrying the same header, so the camelCase mappings live in one place\n // rather than being spelled out a second time here and drifting from the ones a loaded\n // frame reports.\n const shape = new QvdDataFrame([], columns, header, {\n symbolTableBytes: parseInt(header['Offset'], 10),\n totalRows: rowCount,\n rowsLoaded: 0,\n symbolFiltering: false,\n symbolsKept: null,\n });\n\n return {\n columns,\n rowCount,\n columnCount: columns.length,\n fields: columns.map((/** @type {string} */ name) => shape.getFieldMetadata(name)),\n fileMetadata: shape.fileMetadata,\n metadata: header,\n };\n }\n\n /**\n * Loads the QVD file into memory and parses it.\n *\n * @param {number|null} maxRows The maximum number of rows to load. If null, all rows are loaded.\n * Must be a non-negative integer when given.\n * @throws {QvdValidationError} If maxRows is neither null nor a non-negative integer.\n * @return {Promise<QvdDataFrame>} The loaded QVD file.\n */\n async load(maxRows = null) {\n const {columns, metadata, loadStats, resolvedByField} = await this._decode(maxRows);\n\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n // Rows are built once, here, from the decoded columns. `data` stays eager: of the four ways\n // this library is used - a full read, a preview already bounded by maxRows, writing an\n // array out, and reading metadata - not one is helped by materialising a row only when it\n // is touched, and a lazy accessor would cost a proxy, a cache and mutation semantics to\n // serve none of them. A caller who wants columns without paying for rows uses\n // QvdColumnTable, which stops before this loop.\n const indexColumns = this._indexColumns;\n const fieldCount = indexColumns.length;\n const data = new Array(this._rowsDecoded);\n\n for (let row = 0; row < this._rowsDecoded; row++) {\n const values = new Array(fieldCount);\n\n for (let field = 0; field < fieldCount; field++) {\n const symbolIndex = indexColumns[field][row];\n\n // A negative index is how a bias of -2 encodes NULL: stored index 0 means NULL, and\n // real symbols start at 2. It addresses no symbol.\n values[field] = symbolIndex < 0 ? null : resolvedByField[field][symbolIndex];\n }\n\n data[row] = values;\n }\n\n loadStats.rowsLoaded = data.length;\n\n return new QvdDataFrame(data, columns, metadata, loadStats);\n }\n\n /**\n * Reads and decodes the file, stopping short of building rows.\n *\n * Everything `load()` and `loadColumnar()` have in common, which is everything except the\n * shape of the answer. Two read paths for one binary format is the drift risk #113 is the\n * standing example of - a stored index resolved one way here and another way there returns\n * plausible wrong values and throws nothing - so there is one path, and the two entry points\n * differ only in what they do with what it returns.\n *\n * @param {number|null} maxRows Maximum rows to decode, or null for all of them.\n * @return {Promise<{columns: Array<string>, metadata: any, loadStats: any,\n * resolvedByField: Array<Array<any>>}>} The decoded file.\n * @private\n */\n async _decode(maxRows = null) {\n // Validate before any I/O. Every downstream use is Math.min(maxRows, totalRows), which\n // silently accepts nonsense: a negative value yields a negative row count, NaN makes every\n // comparison false, and a fractional value produces a fractional loop bound. Each of those\n // returns a wrong or empty data frame rather than an error, so reject them up front.\n // undefined never reaches here: the default parameter above turns it into null.\n if (maxRows !== null && (typeof maxRows !== 'number' || !Number.isInteger(maxRows) || maxRows < 0)) {\n throw new QvdValidationError('maxRows must be a non-negative integer, or null to load all rows', {\n provided: maxRows,\n type: typeof maxRows,\n file: this._path,\n });\n }\n\n await this._readData(maxRows);\n await this._parseHeader();\n\n // Determine if we should use two-pass symbol filtering\n // This optimization is beneficial for large symbol tables with limited row access\n let symbolsToKeep = null;\n let symbolsKept = null;\n\n if (maxRows !== null && this._header) {\n const symbolTableLength = parseInt(this._header['QvdTableHeader']['Offset'], 10);\n\n // Use two-pass filtering for symbol tables above the threshold when loading limited rows.\n // The threshold is an option rather than a constant so this path can be exercised with a\n // small fixture: it is the most intricate code in the reader, and the only files large\n // enough to reach the 50MB default are ones no repository should be carrying around.\n if (symbolTableLength > this._symbolFilteringThreshold) {\n // Pass 1: Analyze which symbols are actually needed\n symbolsToKeep = await this._analyzeIndexTableSymbolUsage(maxRows);\n\n // Recorded rather than logged. This used to be a console.log, which a library has no\n // business emitting: callers could not silence it, and it was the only way to find out\n // whether filtering had happened. It is now reported through QvdDataFrame.loadStats,\n // which callers can inspect - and tests can assert on deterministically, where the\n // previous test measured a heapUsed delta and failed on GC timing instead.\n symbolsKept = Array.from(symbolsToKeep.values()).reduce((sum, set) => sum + set.size, 0);\n }\n }\n\n // Pass 2: Parse symbol table (with filtering if enabled)\n await this._parseSymbolTable(symbolsToKeep, maxRows);\n await this._parseIndexTable(maxRows);\n\n assert(this._header, 'The QVD file header has not been parsed.');\n assert(this._symbolTable, 'The QVD file symbol table has not been parsed.');\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n // Resolve each field's symbols once rather than once per cell.\n //\n // A stored index addresses the same symbol in every row, so the work below - the symbol\n // lookup, toPrimaryValue(), and the numeric-string coercion - depends only on the index.\n // Doing it inside the row loop repeated it 34 million times on the taxi fixture for a\n // symbol table of a few thousand entries.\n //\n // A filtered-out symbol is stored as null by the two-pass path, and an index past the end\n // of the array reads as undefined. Both resolve to undefined here, which is what the\n // per-cell version produced through optional chaining.\n const resolvedByField = this._symbolTable.map((symbols) => {\n const resolved = new Array(symbols.length);\n\n for (let index = 0; index < symbols.length; index++) {\n const value = symbols[index]?.toPrimaryValue();\n\n // Number('') and Number(' ') are 0, which silently turned every blank cell Qlik\n // stored into the number zero - indistinguishable from a real zero, and persisted as\n // one on the next write. Blank strings are never numeric, so exclude them.\n resolved[index] =\n typeof value === 'string' && value.trim() !== '' && !isNaN(Number(value)) ? Number(value) : value;\n }\n\n return resolved;\n });\n\n let fields = this._header['QvdTableHeader']['Fields']['QvdFieldHeader'];\n\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const columns = fields.map((/** @type {any} */ field) => field['FieldName']);\n\n // Pass the complete header metadata to the caller\n const metadata = this._header['QvdTableHeader'];\n\n /** @type {import('./QvdDataFrame.js').QvdLoadStats} */\n const loadStats = {\n symbolTableBytes: parseInt(this._header['QvdTableHeader']['Offset'], 10),\n totalRows: parseInt(this._header['QvdTableHeader']['NoOfRecords'], 10),\n rowsLoaded: this._rowsDecoded,\n symbolFiltering: symbolsToKeep !== null,\n symbolsKept,\n };\n\n return {columns, metadata, loadStats, resolvedByField};\n }\n\n /**\n * Reads the file as columns, without ever materialising rows.\n *\n * Shares every step with `load()` up to the point where rows would be built - see `_decode`.\n * What it keeps instead is what the decoder already produced: one `Int32Array` of stored\n * indices per field, and one resolved value per distinct symbol. On the 1.7M x 20 taxi\n * fixture that is 38.6 MiB against the 352.8 MiB `data` retains, because a column costs four\n * bytes per row rather than a boxed value per cell, and the symbols are a few thousand\n * entries shared across every row that uses them.\n *\n * @param {number|null} maxRows The maximum number of rows to decode.\n * @return {Promise<import('./QvdColumnTable.js').QvdColumnTable>} The decoded columns.\n */\n async loadColumnar(maxRows = null) {\n const {columns, metadata, loadStats, resolvedByField} = await this._decode(maxRows);\n const {QvdColumnTable} = await import('./QvdColumnTable.js');\n\n assert(this._indexColumns, 'The QVD file index table has not been parsed.');\n\n return new QvdColumnTable({\n columns,\n codesByField: this._indexColumns,\n symbolsByField: resolvedByField,\n rowCount: this._rowsDecoded,\n metadata,\n loadStats,\n });\n }\n}\n","// @ts-check\n\nimport {QvdValidationError} from './QvdErrors.js';\n\n/**\n * @typedef {Object} QvdNumberFormat\n * @property {string} Type - Number format type\n * @property {string} nDec - Number of decimals\n * @property {string} UseThou - Use thousands separator\n * @property {string} Fmt - Format string\n * @property {string} Dec - Decimal separator\n * @property {string} Thou - Thousands separator\n */\n\n/**\n * @typedef {Object} QvdFieldHeader\n * @property {string} FieldName - The name of the field\n * @property {string|number} [BitOffset] - The bit offset\n * @property {string|number} [BitWidth] - The bit width\n * @property {string|number} [Bias] - The bias value\n * @property {string|number} [NoOfSymbols] - Number of symbols\n * @property {string|number} [Offset] - The offset\n * @property {string|number} [Length] - The length\n * @property {string} [Comment] - Field comment\n * @property {QvdNumberFormat|string} [NumberFormat] - Number format\n * @property {Object|string} [Tags] - Field tags\n */\n\n/**\n * @typedef {Object} QvdFields\n * @property {QvdFieldHeader|QvdFieldHeader[]} QvdFieldHeader - Field header(s)\n */\n\n/**\n * @typedef {Object} QvdMetadata\n * @property {string|number} [QvBuildNo] - QlikView build number\n * @property {string} [CreatorDoc] - Creator document\n * @property {string} [CreateUtcTime] - Creation UTC time\n * @property {string} [SourceCreateUtcTime] - Source creation UTC time\n * @property {string} [SourceFileUtcTime] - Source file UTC time\n * @property {string|number} [SourceFileSize] - Source file size\n * @property {string} [StaleUtcTime] - Stale UTC time\n * @property {string} [TableName] - Table name\n * @property {string|number} [NoOfRecords] - Number of records\n * @property {string|number} [RecordByteSize] - Record byte size\n * @property {string|number} [Offset] - Offset\n * @property {string|number} [Length] - Length\n * @property {string} [Compression] - Compression type\n * @property {string} [Comment] - Comment\n * @property {string} [EncryptionInfo] - Encryption info\n * @property {string} [TableTags] - Table tags\n * @property {string} [ProfilingData] - Profiling data\n * @property {Object|string} [Lineage] - Lineage\n * @property {QvdFields} [Fields] - Fields information\n */\n\n/**\n * A QVD file's schema and header, read without its data.\n *\n * @typedef {Object} QvdFileMetadata\n * @property {Array<string>} columns Field names, in file order.\n * @property {number} rowCount Rows the file declares in its header. Note that this is the\n * file's row count, not a number of rows loaded - nothing was loaded.\n * @property {number} columnCount Number of fields.\n * @property {Array<Object|null>} fields Per-field metadata, in the same shape and order that\n * `getFieldMetadata()` returns for a loaded frame.\n * @property {Object} fileMetadata File-level metadata, in the same shape as the `fileMetadata`\n * accessor on a loaded frame.\n * @property {QvdMetadata} metadata The raw `QvdTableHeader`, as `metadata` gives it.\n */\n\n/**\n * Statistics describing the read that produced a data frame.\n *\n * @typedef {Object} QvdLoadStats\n * @property {number} symbolTableBytes Size of the file's symbol table, in bytes.\n * @property {number} totalRows Rows the file declares in its header.\n * @property {number} rowsLoaded Rows actually materialised.\n * @property {boolean} symbolFiltering Whether the two-pass symbol-filtering path was used.\n * @property {number|null} symbolsKept Symbols retained by that path, or null when it did not run.\n */\n\n/**\n * Represents a loaded QVD file.\n */\nexport class QvdDataFrame {\n /**\n * Represents the data frame stored inside a QVD file.\n * @param {Array<Array<any>>} data The data of the data frame.\n * @param {Array<string>} columns The columns of the data frame.\n * @param {QvdMetadata|null} metadata The metadata from the QVD file header (optional).\n * @param {QvdLoadStats|null} loadStats Statistics about the read (optional).\n */\n constructor(data, columns, metadata = null, loadStats = null) {\n this._data = data;\n this._columns = columns;\n this._metadata = metadata;\n this._loadStats = loadStats;\n }\n\n /**\n * Returns the data of the data frame.\n */\n get data() {\n return this._data;\n }\n\n /**\n * Returns the columns of the data frame.\n */\n get columns() {\n return this._columns;\n }\n\n /**\n * Returns the shape of the data frame.\n */\n get shape() {\n return [this._data.length, this._columns.length];\n }\n\n /**\n * Returns the complete metadata object from the QVD file header.\n * @return {Object|null} The complete metadata object or null if not available.\n */\n get metadata() {\n return this._metadata;\n }\n\n /**\n * Returns statistics about the read that produced this data frame.\n *\n * Only a frame returned by fromQvd() carries these; fromDict(), head() and tail() produce\n * frames that describe no particular read, and report null rather than a stale figure.\n *\n * The main use is confirming that a lazy load actually filtered the symbol table:\n * `symbolFiltering` says whether the two-pass path ran, and `symbolsKept` how many symbols\n * survived it, which for a small maxRows should be a tiny fraction of the file's total.\n *\n * @return {QvdLoadStats|null} Load statistics, or null if this frame did not come from a file.\n */\n get loadStats() {\n return this._loadStats;\n }\n\n /**\n * Returns file-level metadata from the QVD header.\n * @return {Object} File-level metadata properties.\n */\n get fileMetadata() {\n if (!this._metadata) {\n return {};\n }\n\n const header = this._metadata;\n return {\n qvBuildNo: header.QvBuildNo,\n creatorDoc: header.CreatorDoc,\n createUtcTime: header.CreateUtcTime,\n sourceCreateUtcTime: header.SourceCreateUtcTime,\n sourceFileUtcTime: header.SourceFileUtcTime,\n sourceFileSize: header.SourceFileSize,\n staleUtcTime: header.StaleUtcTime,\n tableName: header.TableName,\n noOfRecords: header.NoOfRecords,\n recordByteSize: header.RecordByteSize,\n offset: header.Offset,\n length: header.Length,\n compression: header.Compression,\n comment: header.Comment,\n encryptionInfo: header.EncryptionInfo,\n tableTags: header.TableTags,\n profilingData: header.ProfilingData,\n lineage: header.Lineage,\n };\n }\n\n /**\n * Returns field-level metadata for a specific field/column.\n * @param {string} fieldName The name of the field.\n * @return {Object|null} Field metadata or null if field not found.\n */\n getFieldMetadata(fieldName) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return null;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n const field = fields.find((f) => f.FieldName === fieldName);\n if (!field) {\n return null;\n }\n\n return {\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n };\n }\n\n /**\n * Returns field-level metadata for all fields.\n * @return {Array<Object>} Array of field metadata objects.\n */\n getAllFieldMetadata() {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return [];\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n }\n\n return fields.map((field) => ({\n fieldName: field.FieldName,\n bitOffset: field.BitOffset,\n bitWidth: field.BitWidth,\n bias: field.Bias,\n noOfSymbols: field.NoOfSymbols,\n offset: field.Offset,\n length: field.Length,\n comment: field.Comment,\n numberFormat: field.NumberFormat,\n tags: field.Tags,\n }));\n }\n\n /**\n * @typedef {Object} FileMetadataUpdate\n * @property {string|number} [qvBuildNo] - QlikView build number\n * @property {string} [creatorDoc] - Creator document\n * @property {string} [createUtcTime] - Creation UTC time\n * @property {string} [sourceCreateUtcTime] - Source creation UTC time\n * @property {string} [sourceFileUtcTime] - Source file UTC time\n * @property {string|number} [sourceFileSize] - Source file size\n * @property {string} [staleUtcTime] - Stale UTC time\n * @property {string} [tableName] - Table name\n * @property {string} [compression] - Compression type\n * @property {string} [comment] - Comment\n * @property {string} [encryptionInfo] - Encryption info\n * @property {string} [tableTags] - Table tags\n * @property {string} [profilingData] - Profiling data\n * @property {Object|string} [lineage] - Lineage\n */\n\n /**\n * Sets modifiable file-level metadata. Immutable properties related to data storage are ignored.\n * @param {FileMetadataUpdate} metadata Object containing metadata properties to update.\n */\n setFileMetadata(metadata) {\n if (!this._metadata) {\n // Initialize metadata structure if it doesn't exist\n this._metadata = {\n QvBuildNo: 50667,\n CreatorDoc: '',\n CreateUtcTime: '',\n SourceCreateUtcTime: '',\n SourceFileUtcTime: '',\n SourceFileSize: -1,\n StaleUtcTime: '',\n TableName: '',\n Fields: {\n QvdFieldHeader: this._columns.map((column) => ({\n FieldName: column,\n BitOffset: 0,\n BitWidth: 0,\n Bias: 0,\n NoOfSymbols: 0,\n Offset: 0,\n Length: 0,\n Comment: '',\n NumberFormat: {\n Type: 'UNKNOWN',\n nDec: '0',\n UseThou: '0',\n Fmt: '',\n Dec: '',\n Thou: '',\n },\n Tags: {},\n })),\n },\n NoOfRecords: 0,\n RecordByteSize: 0,\n Offset: 0,\n Length: 0,\n Compression: '',\n Comment: '',\n EncryptionInfo: '',\n TableTags: '',\n ProfilingData: '',\n Lineage: {},\n };\n }\n\n // Only allow modification of certain fields (not Offset, Length, NoOfRecords, RecordByteSize)\n const modifiableFields = [\n 'qvBuildNo',\n 'creatorDoc',\n 'createUtcTime',\n 'sourceCreateUtcTime',\n 'sourceFileUtcTime',\n 'sourceFileSize',\n 'staleUtcTime',\n 'tableName',\n 'compression',\n 'comment',\n 'encryptionInfo',\n 'tableTags',\n 'profilingData',\n 'lineage',\n ];\n\n // Map camelCase to XML property names\n const fieldMapping = {\n qvBuildNo: 'QvBuildNo',\n creatorDoc: 'CreatorDoc',\n createUtcTime: 'CreateUtcTime',\n sourceCreateUtcTime: 'SourceCreateUtcTime',\n sourceFileUtcTime: 'SourceFileUtcTime',\n sourceFileSize: 'SourceFileSize',\n staleUtcTime: 'StaleUtcTime',\n tableName: 'TableName',\n compression: 'Compression',\n comment: 'Comment',\n encryptionInfo: 'EncryptionInfo',\n tableTags: 'TableTags',\n profilingData: 'ProfilingData',\n lineage: 'Lineage',\n };\n\n modifiableFields.forEach((field) => {\n // @ts-ignore - Dynamic property access for metadata mapping\n if (metadata[field] !== undefined) {\n // @ts-ignore - Dynamic property access for metadata mapping\n this._metadata[fieldMapping[field]] = metadata[field];\n }\n });\n }\n\n /**\n * @typedef {Object} FieldMetadataUpdate\n * @property {string} [comment] - Field comment\n * @property {QvdNumberFormat|string} [numberFormat] - Number format\n * @property {Object|string} [tags] - Field tags\n */\n\n /**\n * Sets modifiable field-level metadata for a specific field.\n * Immutable properties related to data storage (Offset, Length, BitOffset, etc.) are ignored.\n * @param {string} fieldName The name of the field.\n * @param {FieldMetadataUpdate} metadata Object containing field metadata properties to update.\n */\n setFieldMetadata(fieldName, metadata) {\n if (!this._metadata || !this._metadata.Fields || !this._metadata.Fields.QvdFieldHeader) {\n return;\n }\n\n let fields = this._metadata.Fields.QvdFieldHeader;\n if (!Array.isArray(fields)) {\n fields = [fields];\n this._metadata.Fields.QvdFieldHeader = fields;\n }\n\n const fieldIndex = fields.findIndex((f) => f.FieldName === fieldName);\n if (fieldIndex === -1) {\n return;\n }\n\n // Only allow modification of Comment, NumberFormat, and Tags (not Offset, Length, BitOffset, etc.)\n if (metadata.comment !== undefined) {\n fields[fieldIndex].Comment = metadata.comment;\n }\n if (metadata.numberFormat !== undefined) {\n fields[fieldIndex].NumberFormat = metadata.numberFormat;\n }\n if (metadata.tags !== undefined) {\n fields[fieldIndex].Tags = metadata.tags;\n }\n }\n\n /**\n * Returns the first n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n head(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('head() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(this._data.slice(0, n), this._columns, this._metadata);\n }\n\n /**\n * Returns the last n rows of the data frame.\n *\n * @param {number} n The number of rows to return.\n * @return {QvdDataFrame} The first n rows of the data frame.\n * @throws {QvdValidationError} If n is not a non-negative integer.\n */\n tail(n = 5) {\n if (typeof n !== 'number' || !Number.isInteger(n) || n < 0) {\n throw new QvdValidationError('tail() requires a non-negative integer', {\n provided: n,\n type: typeof n,\n });\n }\n return new QvdDataFrame(n === 0 ? [] : this._data.slice(-n), this._columns, this._metadata);\n }\n\n /**\n * Returns the selected rows of the data frame.\n *\n * @param {...number} args The indices of the rows to return.\n * @return {QvdDataFrame} The selected rows of the data frame.\n * @throws {QvdValidationError} If any index is not an integer or is out of bounds.\n */\n rows(...args) {\n for (const index of args) {\n if (typeof index !== 'number' || !Number.isInteger(index)) {\n throw new QvdValidationError('rows() requires integer indices', {\n provided: index,\n type: typeof index,\n });\n }\n if (index < 0 || index >= this._data.length) {\n throw new QvdValidationError(`Row index ${index} out of bounds`, {\n index,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n }\n return new QvdDataFrame(\n args.map((index) => this._data[index]),\n this._columns,\n this._metadata,\n );\n }\n\n /**\n * Returns the value at the specified row and column.\n *\n * @param {number} row The index of the row.\n * @param {string} column The name of the column.\n * @return {any} The value at the specified row and column.\n * @throws {QvdValidationError} If row is not an integer, out of bounds, or column does not exist.\n */\n at(row, column) {\n if (typeof row !== 'number' || !Number.isInteger(row)) {\n throw new QvdValidationError('Row index must be an integer', {\n provided: row,\n type: typeof row,\n });\n }\n if (row < 0 || row >= this._data.length) {\n throw new QvdValidationError(`Row index ${row} out of bounds`, {\n index: row,\n validRange: [0, this._data.length - 1],\n dataLength: this._data.length,\n });\n }\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n return this._data[row][this._columns.indexOf(column)];\n }\n\n /**\n * Selects the specified columns from the data frame.\n *\n * @param {...string} args The names of the columns to select.\n * @return {QvdDataFrame} The selected columns of the data frame.\n * @throws {QvdValidationError} If any column name does not exist.\n */\n select(...args) {\n for (const column of args) {\n if (!this._columns.includes(column)) {\n throw new QvdValidationError(`Column '${column}' does not exist`, {\n column,\n availableColumns: this._columns,\n });\n }\n }\n const indices = args.map((arg) => this._columns.indexOf(arg));\n const data = this._data.map((row) => indices.map((index) => row[index]));\n const columns = indices.map((index) => this._columns[index]);\n return new QvdDataFrame(data, columns, this._metadata);\n }\n\n /**\n * Returns the data frame as a dictionary.\n *\n * @return {Promise<{columns: Array<string>, data: Array<Array<any>>}>} The data frame as a dictionary.\n */\n async toDict() {\n return {columns: this._columns, data: this._data};\n }\n\n /**\n * Persists the data frame to a QVD file.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional writing options.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {Function} [options.onProgress] Optional progress callback function that receives progress updates during write operations.\n */\n async toQvd(path, options = {}) {\n const {QvdFileWriter} = await import('./QvdFileWriter.js');\n const writerOptions = {\n allowedDir: options.allowedDir,\n onProgress: options.onProgress,\n };\n await new QvdFileWriter(path, this, writerOptions).save();\n }\n\n /**\n * Loads a QVD file and returns its data frame.\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional loading options.\n * @param {number|null} [options.maxRows] The maximum number of rows to load. Must be a non-negative\n * integer; if not specified or null, all rows are loaded. Anything else throws a QvdValidationError.\n * @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path\n * must be within this directory, with symlinks resolved first, so a link inside it that points\n * outside it is rejected. Defaults to the current working directory. To permit an entire\n * volume, pass its root explicitly ('/' on POSIX, 'C:\\\\' on Windows); a null or empty value falls\n * back to the working directory rather than removing the restriction.\n * @param {number} [options.memorySafetyFactor=0.8] Fraction (0.0-1.0) of the memory budget a load\n * may use. The budget is the smaller of the V8 heap limit and any container memory limit. Default\n * is 0.8; the estimate it scales accounts for the rows and columns being materialised, so this is\n * headroom for garbage collection rather than compensation for an inaccurate figure.\n * **Zero disables the memory check entirely.**\n * @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes, above which\n * a lazy load switches to the two-pass filtering path. Defaults to 50MB.\n * @throws {QvdValidationError} If options.maxRows is neither null/undefined nor a non-negative integer.\n * @return {Promise<QvdDataFrame>} The data frame of the QVD file.\n */\n static async fromQvd(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n const readerOptions = {\n allowedDir: options.allowedDir,\n memorySafetyFactor: options.memorySafetyFactor,\n symbolFilteringThreshold: options.symbolFilteringThreshold,\n };\n return await new QvdFileReader(path, readerOptions).load(options.maxRows !== undefined ? options.maxRows : null);\n }\n\n /**\n * Reads a QVD file's schema and header metadata, without reading its data.\n *\n * Costs the same whatever the file's size, because it stops at the XML header - a few\n * kilobytes - and never touches the symbol or index tables.\n *\n * This is what `{maxRows: 0}` looks like but is not. That still reads and parses the whole\n * symbol table, which is 0.4MB on a 38MB taxi fixture but hundreds of megabytes on a\n * high-cardinality file. Use this when you want to know what is in a file rather than to\n * read any of it.\n *\n * No data frame comes back, deliberately: one with `data: []` would be indistinguishable\n * from an empty file at the call site.\n *\n * ```js\n * const {columns, rowCount, fields} = await QvdDataFrame.readMetadata('sales.qvd');\n * ```\n *\n * @param {string} path The path to the QVD file.\n * @param {Object} [options] Optional reading options.\n * @param {string} [options.allowedDir] Optional allowed directory path, applied exactly as it\n * is for `fromQvd`.\n * @return {Promise<QvdFileMetadata>} The file's schema and header metadata.\n */\n static async readMetadata(path, options = {}) {\n const {QvdFileReader} = await import('./QvdFileReader.js');\n\n return await new QvdFileReader(path, {allowedDir: options.allowedDir}).loadMetadata();\n }\n\n /**\n * Constructs a data frame from a dictionary.\n *\n * @param {{columns: Array<string>, data: Array<Array<any>>}} data The dictionary to construct the data frame from.\n * @return {Promise<QvdDataFrame>} The constructed data frame.\n */\n static async fromDict(data) {\n if (!data.columns) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any columns.', {\n data,\n });\n }\n if (!data.data) {\n throw new QvdValidationError('The dictionary to construct the data frame from does not contain any data.', {\n data,\n });\n }\n\n return new QvdDataFrame(data.data, data.columns);\n }\n}\n","// @ts-check\n\nexport {QvdSymbol} from './QvdSymbol.js';\nexport {QvdDataFrame} from './QvdDataFrame.js';\nexport {QvdColumnTable, QvdColumn} from './QvdColumnTable.js';\nexport {QvdFileReader} from './QvdFileReader.js';\nexport {QvdFileWriter} from './QvdFileWriter.js';\nexport {\n QvdError,\n QvdParseError,\n QvdValidationError,\n QvdIOError,\n QvdCorruptedError,\n QvdSecurityError,\n} from './QvdErrors.js';\n"]}
|