qvdjs 2.0.1 → 2.0.2

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/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import path2 from 'path';
3
3
  import assert3 from 'assert';
4
4
  import crypto2 from 'crypto';
5
5
  import { setTimeout } from 'timers/promises';
6
- import xml2 from 'xml2js';
6
+ import xml from 'xml2js';
7
7
  import os from 'os';
8
8
  import v8 from 'v8';
9
9
  import { types } from 'util';
@@ -1790,7 +1790,7 @@ var init_QvdFileWriter = __esm({
1790
1790
  });
1791
1791
  }
1792
1792
  }
1793
- const builder = new xml2.Builder({
1793
+ const builder = new xml.Builder({
1794
1794
  renderOpts: {
1795
1795
  pretty: true,
1796
1796
  newline: "\r\n",
@@ -2352,6 +2352,13 @@ var init_memoryUtils = __esm({
2352
2352
  });
2353
2353
 
2354
2354
  // src/util/validationUtils.js
2355
+ function headerInteger(value) {
2356
+ if (typeof value !== "string" || !/^\s*-?\d+\s*$/.test(value)) {
2357
+ return NaN;
2358
+ }
2359
+ const number = Number(value);
2360
+ return number === 0 ? 0 : number;
2361
+ }
2355
2362
  function validateHeaderStructure(headerObj, filePath, stage) {
2356
2363
  const tableHeader = headerObj?.["QvdTableHeader"];
2357
2364
  if (tableHeader === null || typeof tableHeader !== "object" || Array.isArray(tableHeader)) {
@@ -2361,7 +2368,7 @@ function validateHeaderStructure(headerObj, filePath, stage) {
2361
2368
  stage
2362
2369
  });
2363
2370
  }
2364
- const symbolTableLength = parseInt(tableHeader["Offset"], 10);
2371
+ const symbolTableLength = headerInteger(tableHeader["Offset"]);
2365
2372
  if (isNaN(symbolTableLength) || !Number.isSafeInteger(symbolTableLength) || symbolTableLength < 0) {
2366
2373
  throw new QvdCorruptedError("Invalid symbol table offset", {
2367
2374
  offset: tableHeader["Offset"],
@@ -2369,6 +2376,47 @@ function validateHeaderStructure(headerObj, filePath, stage) {
2369
2376
  stage
2370
2377
  });
2371
2378
  }
2379
+ const fields = tableHeader["Fields"]?.["QvdFieldHeader"];
2380
+ const fieldList = fields === void 0 || fields === null ? [] : Array.isArray(fields) ? fields : [fields];
2381
+ if (fieldList.length === 0) {
2382
+ throw new QvdCorruptedError("The QVD file header declares no fields", {
2383
+ file: filePath,
2384
+ stage
2385
+ });
2386
+ }
2387
+ const malformedIndex = fieldList.findIndex(
2388
+ (field) => field === null || typeof field !== "object" || Array.isArray(field)
2389
+ );
2390
+ if (malformedIndex !== -1) {
2391
+ throw new QvdCorruptedError("The QVD file header declares a field with no properties", {
2392
+ fieldIndex: malformedIndex,
2393
+ fieldCount: fieldList.length,
2394
+ file: filePath,
2395
+ stage
2396
+ });
2397
+ }
2398
+ const seen = /* @__PURE__ */ new Map();
2399
+ fieldList.forEach((field, fieldIndex) => {
2400
+ const name = field["FieldName"];
2401
+ if (typeof name !== "string" || name === "") {
2402
+ throw new QvdCorruptedError("The QVD file header declares a field with no usable name", {
2403
+ fieldIndex,
2404
+ fieldName: name,
2405
+ file: filePath,
2406
+ stage
2407
+ });
2408
+ }
2409
+ if (seen.has(name)) {
2410
+ throw new QvdCorruptedError("The QVD file header declares two fields with the same name", {
2411
+ field: name,
2412
+ fieldIndexes: [seen.get(name), fieldIndex],
2413
+ file: filePath,
2414
+ stage
2415
+ });
2416
+ }
2417
+ seen.set(name, fieldIndex);
2418
+ });
2419
+ return fieldList;
2372
2420
  }
2373
2421
  function validateSymbolTableSizeEarly(symbolTableLength, filePath) {
2374
2422
  const heapLimit = getHeapLimit();
@@ -2414,8 +2462,8 @@ function validateSymbolTableSize(symbolTableLength, filePath, totalRows) {
2414
2462
  }
2415
2463
  }
2416
2464
  function validateFieldMetadata(field, symbolBufferLength, filePath) {
2417
- const symbolsOffset = parseInt(field["Offset"], 10);
2418
- const symbolsLength = parseInt(field["Length"], 10);
2465
+ const symbolsOffset = headerInteger(field["Offset"]);
2466
+ const symbolsLength = headerInteger(field["Length"]);
2419
2467
  if (isNaN(symbolsOffset) || !Number.isSafeInteger(symbolsOffset) || symbolsOffset < 0) {
2420
2468
  throw new QvdCorruptedError("Invalid symbol offset", {
2421
2469
  field: field["FieldName"],
@@ -2443,6 +2491,63 @@ function validateFieldMetadata(field, symbolBufferLength, filePath) {
2443
2491
  });
2444
2492
  }
2445
2493
  }
2494
+ function firstOverlap(ranges) {
2495
+ const claimed = ranges.filter((range) => range.length > 0).sort((a, b) => a.start - b.start);
2496
+ let furthest = null;
2497
+ for (const range of claimed) {
2498
+ if (furthest !== null && range.start < furthest.start + furthest.length) {
2499
+ return [furthest, range];
2500
+ }
2501
+ if (furthest === null || range.start + range.length > furthest.start + furthest.length) {
2502
+ furthest = range;
2503
+ }
2504
+ }
2505
+ return null;
2506
+ }
2507
+ function validateSymbolAreas(fields, filePath) {
2508
+ const overlap = firstOverlap(
2509
+ fields.map((field) => ({
2510
+ field: field["FieldName"],
2511
+ start: headerInteger(field["Offset"]),
2512
+ length: headerInteger(field["Length"])
2513
+ }))
2514
+ );
2515
+ if (overlap !== null) {
2516
+ const [first, second] = overlap;
2517
+ throw new QvdCorruptedError("Symbol areas overlap", {
2518
+ field: second.field,
2519
+ offset: second.start,
2520
+ length: second.length,
2521
+ overlaps: first.field,
2522
+ overlapsOffset: first.start,
2523
+ overlapsLength: first.length,
2524
+ file: filePath,
2525
+ stage: "parseSymbolTable"
2526
+ });
2527
+ }
2528
+ }
2529
+ function validateBitFields(fields, filePath) {
2530
+ const overlap = firstOverlap(
2531
+ fields.map((field) => ({
2532
+ field: field["FieldName"],
2533
+ start: headerInteger(field["BitOffset"]),
2534
+ length: headerInteger(field["BitWidth"])
2535
+ }))
2536
+ );
2537
+ if (overlap !== null) {
2538
+ const [first, second] = overlap;
2539
+ throw new QvdCorruptedError("Bit fields overlap", {
2540
+ field: second.field,
2541
+ bitOffset: second.start,
2542
+ bitWidth: second.length,
2543
+ overlaps: first.field,
2544
+ overlapsBitOffset: first.start,
2545
+ overlapsBitWidth: first.length,
2546
+ file: filePath,
2547
+ stage: "parseIndexTable"
2548
+ });
2549
+ }
2550
+ }
2446
2551
  function validateRecordCount(totalRows, filePath, stage = "parseIndexTable") {
2447
2552
  if (isNaN(totalRows) || !Number.isSafeInteger(totalRows) || totalRows < 0) {
2448
2553
  throw new QvdCorruptedError("Invalid number of records", {
@@ -2452,14 +2557,17 @@ function validateRecordCount(totalRows, filePath, stage = "parseIndexTable") {
2452
2557
  });
2453
2558
  }
2454
2559
  }
2455
- function validateIndexTableMetadata(recordSize, totalRows, indexTableLength, indexTableOffset, bufferLength, rowsToLoad, filePath, fileSize = null, windowFirstRow = 0, bufferFirstRow = 0) {
2560
+ function validateRecordSize(recordSize, filePath, stage = "parseIndexTable") {
2456
2561
  if (isNaN(recordSize) || !Number.isSafeInteger(recordSize) || recordSize < 0) {
2457
2562
  throw new QvdCorruptedError("Invalid record byte size", {
2458
2563
  recordSize,
2459
2564
  file: filePath,
2460
- stage: "parseIndexTable"
2565
+ stage
2461
2566
  });
2462
2567
  }
2568
+ }
2569
+ function validateIndexTableMetadata(recordSize, totalRows, indexTableLength, indexTableOffset, bufferLength, rowsToLoad, filePath, fileSize = null, windowFirstRow = 0, bufferFirstRow = 0) {
2570
+ validateRecordSize(recordSize, filePath);
2463
2571
  validateRecordCount(totalRows, filePath);
2464
2572
  if (recordSize === 0 && totalRows > 0) {
2465
2573
  throw new QvdCorruptedError("Record byte size cannot be zero when records exist", {
@@ -2543,8 +2651,8 @@ function validateIndexTableMetadata(recordSize, totalRows, indexTableLength, ind
2543
2651
  }
2544
2652
  }
2545
2653
  function validateFieldBitMetadata(field, recordSize, filePath) {
2546
- const bitOffset = parseInt(field["BitOffset"], 10);
2547
- const bitWidth = parseInt(field["BitWidth"], 10);
2654
+ const bitOffset = headerInteger(field["BitOffset"]);
2655
+ const bitWidth = headerInteger(field["BitWidth"]);
2548
2656
  if (isNaN(bitOffset) || !Number.isSafeInteger(bitOffset) || bitOffset < 0) {
2549
2657
  throw new QvdCorruptedError("Invalid bit offset", {
2550
2658
  field: field["FieldName"],
@@ -2561,7 +2669,7 @@ function validateFieldBitMetadata(field, recordSize, filePath) {
2561
2669
  stage: "parseIndexTable"
2562
2670
  });
2563
2671
  }
2564
- const bias = parseInt(field["Bias"], 10);
2672
+ const bias = headerInteger(field["Bias"]);
2565
2673
  if (isNaN(bias) || !Number.isSafeInteger(bias)) {
2566
2674
  throw new QvdCorruptedError("Invalid bias", {
2567
2675
  field: field["FieldName"],
@@ -2588,6 +2696,14 @@ function validateFieldBitMetadata(field, recordSize, filePath) {
2588
2696
  stage: "parseIndexTable"
2589
2697
  });
2590
2698
  }
2699
+ if (bias !== 0 && bias !== -2) {
2700
+ throw new QvdCorruptedError("Bias is neither 0 nor -2", {
2701
+ field: field["FieldName"],
2702
+ bias,
2703
+ file: filePath,
2704
+ stage: "parseIndexTable"
2705
+ });
2706
+ }
2591
2707
  const recordSizeInBits = recordSize * 8;
2592
2708
  if (bitOffset + bitWidth > recordSizeInBits) {
2593
2709
  throw new QvdCorruptedError("Bit field extends beyond record size", {
@@ -2605,11 +2721,16 @@ var init_validationUtils = __esm({
2605
2721
  init_QvdErrors();
2606
2722
  init_memoryUtils();
2607
2723
  init_bitUtils();
2724
+ __name(headerInteger, "headerInteger");
2608
2725
  __name(validateHeaderStructure, "validateHeaderStructure");
2609
2726
  __name(validateSymbolTableSizeEarly, "validateSymbolTableSizeEarly");
2610
2727
  __name(validateSymbolTableSize, "validateSymbolTableSize");
2611
2728
  __name(validateFieldMetadata, "validateFieldMetadata");
2729
+ __name(firstOverlap, "firstOverlap");
2730
+ __name(validateSymbolAreas, "validateSymbolAreas");
2731
+ __name(validateBitFields, "validateBitFields");
2612
2732
  __name(validateRecordCount, "validateRecordCount");
2733
+ __name(validateRecordSize, "validateRecordSize");
2613
2734
  __name(validateIndexTableMetadata, "validateIndexTableMetadata");
2614
2735
  __name(validateFieldBitMetadata, "validateFieldBitMetadata");
2615
2736
  }
@@ -3241,6 +3362,31 @@ async function* chunksFrom(handle, chunkSize, failed) {
3241
3362
  position += bytesRead;
3242
3363
  }
3243
3364
  }
3365
+ async function parseHeaderXml(text, file, stage) {
3366
+ let parsed;
3367
+ try {
3368
+ parsed = await xml.parseStringPromise(text, { explicitArray: false });
3369
+ } catch (error) {
3370
+ throw new QvdParseError(
3371
+ "The XML header could not be parsed.",
3372
+ {
3373
+ // The first line of the parser's message. The rest is the line and column it stopped at, which
3374
+ // stay on `cause`.
3375
+ reason: String(
3376
+ /** @type {any} */
3377
+ error?.message ?? error
3378
+ ).split("\n")[0],
3379
+ file,
3380
+ stage
3381
+ },
3382
+ { cause: error }
3383
+ );
3384
+ }
3385
+ if (!parsed) {
3386
+ throw new QvdParseError("The XML header could not be parsed.", { file, stage });
3387
+ }
3388
+ return parsed;
3389
+ }
3244
3390
  var MAX_HEADER_SIZE, READ_CHUNK_SIZE, ANALYSIS_SLICE_ROWS, COUNT_SYMBOLS_PAST, QvdFileReader;
3245
3391
  var init_QvdFileReader = __esm({
3246
3392
  "src/QvdFileReader.js"() {
@@ -3261,6 +3407,7 @@ var init_QvdFileReader = __esm({
3261
3407
  ANALYSIS_SLICE_ROWS = 65536;
3262
3408
  COUNT_SYMBOLS_PAST = 65536;
3263
3409
  __name(chunksFrom, "chunksFrom");
3410
+ __name(parseHeaderXml, "parseHeaderXml");
3264
3411
  QvdFileReader = class {
3265
3412
  static {
3266
3413
  __name(this, "QvdFileReader");
@@ -3496,29 +3643,19 @@ var init_QvdFileReader = __esm({
3496
3643
  const headerBuffer = Buffer.concat(headerChunks);
3497
3644
  const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;
3498
3645
  const headerXml = headerBuffer.subarray(0, headerEndIndex).toString();
3499
- const headerObj = await xml2.parseStringPromise(headerXml, { explicitArray: false });
3500
- if (!headerObj) {
3501
- throw new QvdParseError("The XML header could not be parsed.", {
3502
- file: this._path,
3503
- stage: "readData"
3504
- });
3505
- }
3506
- validateHeaderStructure(headerObj, this._path, "readData");
3646
+ const headerObj = await parseHeaderXml(headerXml, this._path, "readData");
3647
+ const headerFields = validateHeaderStructure(headerObj, this._path, "readData");
3507
3648
  const symbolTableOffset = headerEndIndex;
3508
- const symbolTableLength = parseInt(headerObj["QvdTableHeader"]["Offset"], 10);
3649
+ const symbolTableLength = headerInteger(headerObj["QvdTableHeader"]["Offset"]);
3509
3650
  const indexTableOffset = symbolTableOffset + symbolTableLength;
3510
- const recordSize = parseInt(headerObj["QvdTableHeader"]["RecordByteSize"], 10);
3511
- const totalRows = parseInt(headerObj["QvdTableHeader"]["NoOfRecords"], 10);
3651
+ const recordSize = headerInteger(headerObj["QvdTableHeader"]["RecordByteSize"]);
3652
+ const totalRows = headerInteger(headerObj["QvdTableHeader"]["NoOfRecords"]);
3512
3653
  if (headerOnly) {
3513
3654
  this._buffer = headerBuffer.subarray(0, headerEndIndex);
3514
3655
  this._emitProgress("read", 1, 1);
3515
3656
  return;
3516
3657
  }
3517
- let headerFields = headerObj["QvdTableHeader"]?.["Fields"]?.["QvdFieldHeader"];
3518
- if (headerFields && !Array.isArray(headerFields)) {
3519
- headerFields = [headerFields];
3520
- }
3521
- const columnCount = Array.isArray(headerFields) ? selectFields(headerFields, this._requestedFields, this._path).length : 0;
3658
+ const columnCount = selectFields(headerFields, this._requestedFields, this._path).length;
3522
3659
  const headerNumbersUsable = [symbolTableLength, recordSize, totalRows].every(
3523
3660
  (value) => Number.isSafeInteger(value) && value >= 0
3524
3661
  );
@@ -3550,20 +3687,8 @@ var init_QvdFileReader = __esm({
3550
3687
  }
3551
3688
  const rowsToLoad = windowRows;
3552
3689
  validateSymbolTableSizeEarly(symbolTableLength, this._path);
3553
- for (const [name, value] of [
3554
- ["Offset", symbolTableLength],
3555
- ["RecordByteSize", recordSize],
3556
- ["NoOfRecords", totalRows]
3557
- ]) {
3558
- if (!Number.isSafeInteger(value) || Number(value) < 0) {
3559
- throw new QvdCorruptedError(`Invalid header value: ${name}`, {
3560
- name,
3561
- value,
3562
- file: this._path,
3563
- stage: "readData"
3564
- });
3565
- }
3566
- }
3690
+ validateRecordSize(recordSize, this._path, "readData");
3691
+ validateRecordCount(totalRows, this._path, "readData");
3567
3692
  const skippedIndexBytes = resolved.offset * recordSize;
3568
3693
  const indexTableBytesToRead = rowsToLoad * recordSize;
3569
3694
  const totalBytesToRead = indexTableOffset + indexTableBytesToRead;
@@ -3662,36 +3787,11 @@ var init_QvdFileReader = __esm({
3662
3787
  const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;
3663
3788
  const headerBuffer = this._buffer.subarray(headerBeginIndex, headerEndIndex);
3664
3789
  this._fieldBitMetadataValidated = false;
3665
- this._header = await xml2.parseStringPromise(headerBuffer.toString(), { explicitArray: false });
3666
- if (!this._header) {
3667
- throw new QvdParseError("The XML header could not be parsed.", {
3668
- file: this._path,
3669
- stage: "parseHeader"
3670
- });
3671
- }
3672
- validateHeaderStructure(this._header, this._path, "parseHeader");
3673
- const fields = this._header["QvdTableHeader"]?.["Fields"]?.["QvdFieldHeader"];
3674
- const fieldList = fields === void 0 || fields === null ? [] : Array.isArray(fields) ? fields : [fields];
3675
- if (fieldList.length === 0) {
3676
- throw new QvdCorruptedError("The QVD file header declares no fields", {
3677
- file: this._path,
3678
- stage: "parseHeader"
3679
- });
3680
- }
3681
- const malformedIndex = fieldList.findIndex(
3682
- (field) => field === null || typeof field !== "object" || Array.isArray(field)
3683
- );
3684
- if (malformedIndex !== -1) {
3685
- throw new QvdCorruptedError("The QVD file header declares a field with no properties", {
3686
- fieldIndex: malformedIndex,
3687
- fieldCount: fieldList.length,
3688
- file: this._path,
3689
- stage: "parseHeader"
3690
- });
3691
- }
3790
+ this._header = await parseHeaderXml(headerBuffer.toString(), this._path, "parseHeader");
3791
+ const fieldList = validateHeaderStructure(this._header, this._path, "parseHeader");
3692
3792
  this._headerOffset = headerBeginIndex;
3693
3793
  this._symbolTableOffset = headerEndIndex;
3694
- this._indexTableOffset = this._symbolTableOffset + parseInt(this._header["QvdTableHeader"]["Offset"], 10);
3794
+ this._indexTableOffset = this._symbolTableOffset + headerInteger(this._header["QvdTableHeader"]["Offset"]);
3695
3795
  this._allFields = fieldList;
3696
3796
  this._selectedFields = selectFields(this._allFields, this._requestedFields, this._path);
3697
3797
  }
@@ -3723,9 +3823,9 @@ var init_QvdFileReader = __esm({
3723
3823
  }
3724
3824
  const allFields = this._allFields;
3725
3825
  const fields = this._selectedFields;
3726
- const recordSize = parseInt(this._header["QvdTableHeader"]["RecordByteSize"], 10);
3727
- const totalRows = parseInt(this._header["QvdTableHeader"]["NoOfRecords"], 10);
3728
- const indexTableLength = parseInt(this._header["QvdTableHeader"]["Length"], 10);
3826
+ const recordSize = headerInteger(this._header["QvdTableHeader"]["RecordByteSize"]);
3827
+ const totalRows = headerInteger(this._header["QvdTableHeader"]["NoOfRecords"]);
3828
+ const indexTableLength = headerInteger(this._header["QvdTableHeader"]["Length"]);
3729
3829
  const { offset: firstRow, limit: rowsToLoad } = resolveWindow(window, totalRows);
3730
3830
  validateIndexTableMetadata(
3731
3831
  recordSize,
@@ -3748,6 +3848,7 @@ var init_QvdFileReader = __esm({
3748
3848
  for (const field of allFields) {
3749
3849
  validateFieldBitMetadata(field, recordSize, this._path);
3750
3850
  }
3851
+ validateBitFields(allFields, this._path);
3751
3852
  this._fieldBitMetadataValidated = true;
3752
3853
  }
3753
3854
  assert3(
@@ -3778,10 +3879,10 @@ var init_QvdFileReader = __esm({
3778
3879
  this._throwIfAborted();
3779
3880
  const needed = /* @__PURE__ */ new Set();
3780
3881
  symbolUsage[position] = needed;
3781
- const bitOffset = parseInt(field["BitOffset"], 10);
3782
- const bitWidth = parseInt(field["BitWidth"], 10);
3783
- const bias = parseInt(field["Bias"], 10);
3784
- const length = parseInt(field["Length"], 10);
3882
+ const bitOffset = headerInteger(field["BitOffset"]);
3883
+ const bitWidth = headerInteger(field["BitWidth"]);
3884
+ const bias = headerInteger(field["Bias"]);
3885
+ const length = headerInteger(field["Length"]);
3785
3886
  let indexLimit = Number.isSafeInteger(length) && length >= 0 ? Math.ceil(length / 2) : Infinity;
3786
3887
  let counted = false;
3787
3888
  for (let first = 0; first < rowsToLoad; first += sliceRows) {
@@ -3834,11 +3935,11 @@ var init_QvdFileReader = __esm({
3834
3935
  );
3835
3936
  const symbolBuffer = this._buffer.subarray(this._symbolTableOffset, this._indexTableOffset);
3836
3937
  validateFieldMetadata(field, symbolBuffer.length, this._path);
3837
- const offset = parseInt(field["Offset"], 10);
3938
+ const offset = headerInteger(field["Offset"]);
3838
3939
  return countFieldSymbols(
3839
3940
  symbolBuffer,
3840
3941
  offset,
3841
- offset + parseInt(field["Length"], 10),
3942
+ offset + headerInteger(field["Length"]),
3842
3943
  field["FieldName"],
3843
3944
  this._path
3844
3945
  );
@@ -3873,7 +3974,7 @@ var init_QvdFileReader = __esm({
3873
3974
  const fields = this._selectedFields;
3874
3975
  const symbolBuffer = this._buffer.subarray(this._symbolTableOffset, this._indexTableOffset);
3875
3976
  const symbolTableSize = symbolBuffer.length;
3876
- const totalRows = parseInt(this._header["QvdTableHeader"]["NoOfRecords"], 10);
3977
+ const totalRows = headerInteger(this._header["QvdTableHeader"]["NoOfRecords"]);
3877
3978
  validateSymbolTableSize(symbolTableSize, this._path, totalRows);
3878
3979
  if (this._headerMatchesFile) {
3879
3980
  validateMemoryAvailability(
@@ -3891,10 +3992,11 @@ var init_QvdFileReader = __esm({
3891
3992
  for (const field of allFields) {
3892
3993
  validateFieldMetadata(field, symbolBuffer.length, this._path);
3893
3994
  }
3995
+ validateSymbolAreas(allFields, this._path);
3894
3996
  this._symbolTable = fields.map((field, position) => {
3895
3997
  this._throwIfAborted();
3896
- const symbolsOffset = parseInt(field["Offset"], 10);
3897
- const symbolsLength = parseInt(field["Length"], 10);
3998
+ const symbolsOffset = headerInteger(field["Offset"]);
3999
+ const symbolsLength = headerInteger(field["Length"]);
3898
4000
  const symbols = parseFieldSymbols(
3899
4001
  symbolBuffer,
3900
4002
  symbolsOffset,
@@ -3946,9 +4048,9 @@ var init_QvdFileReader = __esm({
3946
4048
  indexBuffer,
3947
4049
  recordSize,
3948
4050
  rowsToLoad,
3949
- parseInt(field["BitOffset"], 10),
3950
- parseInt(field["BitWidth"], 10),
3951
- parseInt(field["Bias"], 10),
4051
+ headerInteger(field["BitOffset"]),
4052
+ headerInteger(field["BitWidth"]),
4053
+ headerInteger(field["Bias"]),
3952
4054
  new Int32Array(rowsToLoad),
3953
4055
  { symbolCount: symbolTable[position].numbers.length, field: field["FieldName"], file: this._path, firstRow }
3954
4056
  );
@@ -3978,23 +4080,13 @@ var init_QvdFileReader = __esm({
3978
4080
  await this._parseHeader();
3979
4081
  this._emitProgress("header", 1, 1);
3980
4082
  this._throwIfAborted();
3981
- assert3(this._header, "The QVD file header has not been parsed.");
4083
+ assert3(this._header && this._allFields, "The QVD file header has not been parsed.");
3982
4084
  const header = this._header["QvdTableHeader"];
3983
- let fields = header["Fields"]?.["QvdFieldHeader"] ?? [];
3984
- if (!Array.isArray(fields)) {
3985
- fields = [fields];
3986
- }
3987
- if (fields.length === 0) {
3988
- throw new QvdCorruptedError("The QVD file header declares no fields", {
3989
- file: this._path,
3990
- stage: "readMetadata"
3991
- });
3992
- }
3993
- const columns = fields.map((field) => field["FieldName"]);
3994
- const rowCount = parseInt(header["NoOfRecords"], 10);
4085
+ const columns = this._allFields.map((field) => field["FieldName"]);
4086
+ const rowCount = headerInteger(header["NoOfRecords"]);
3995
4087
  validateRecordCount(rowCount, this._path, "readMetadata");
3996
4088
  const shape = new QvdDataFrame([], columns, header, {
3997
- symbolTableBytes: parseInt(header["Offset"], 10),
4089
+ symbolTableBytes: headerInteger(header["Offset"]),
3998
4090
  totalRows: rowCount,
3999
4091
  rowsLoaded: 0,
4000
4092
  symbolFiltering: false,
@@ -4159,8 +4251,8 @@ var init_QvdFileReader = __esm({
4159
4251
  this._emitProgress("header", 1, 1);
4160
4252
  this._throwIfAborted();
4161
4253
  assert3(this._header, "The QVD file header has not been parsed.");
4162
- const totalRows = parseInt(this._header["QvdTableHeader"]["NoOfRecords"], 10);
4163
- const symbolTableLength = parseInt(this._header["QvdTableHeader"]["Offset"], 10);
4254
+ const totalRows = headerInteger(this._header["QvdTableHeader"]["NoOfRecords"]);
4255
+ const symbolTableLength = headerInteger(this._header["QvdTableHeader"]["Offset"]);
4164
4256
  const resolved = resolveWindow(window, totalRows);
4165
4257
  const rowsAvailable = resolved.limit;
4166
4258
  let symbolsToKeep = null;