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.cjs CHANGED
@@ -5,7 +5,7 @@ var path2 = require('path');
5
5
  var assert3 = require('assert');
6
6
  var crypto2 = require('crypto');
7
7
  var promises = require('timers/promises');
8
- var xml2 = require('xml2js');
8
+ var xml = require('xml2js');
9
9
  var os = require('os');
10
10
  var v8 = require('v8');
11
11
  var util = require('util');
@@ -16,7 +16,7 @@ var fs2__default = /*#__PURE__*/_interopDefault(fs2);
16
16
  var path2__default = /*#__PURE__*/_interopDefault(path2);
17
17
  var assert3__default = /*#__PURE__*/_interopDefault(assert3);
18
18
  var crypto2__default = /*#__PURE__*/_interopDefault(crypto2);
19
- var xml2__default = /*#__PURE__*/_interopDefault(xml2);
19
+ var xml__default = /*#__PURE__*/_interopDefault(xml);
20
20
  var os__default = /*#__PURE__*/_interopDefault(os);
21
21
  var v8__default = /*#__PURE__*/_interopDefault(v8);
22
22
 
@@ -1802,7 +1802,7 @@ var init_QvdFileWriter = __esm({
1802
1802
  });
1803
1803
  }
1804
1804
  }
1805
- const builder = new xml2__default.default.Builder({
1805
+ const builder = new xml__default.default.Builder({
1806
1806
  renderOpts: {
1807
1807
  pretty: true,
1808
1808
  newline: "\r\n",
@@ -2364,6 +2364,13 @@ var init_memoryUtils = __esm({
2364
2364
  });
2365
2365
 
2366
2366
  // src/util/validationUtils.js
2367
+ function headerInteger(value) {
2368
+ if (typeof value !== "string" || !/^\s*-?\d+\s*$/.test(value)) {
2369
+ return NaN;
2370
+ }
2371
+ const number = Number(value);
2372
+ return number === 0 ? 0 : number;
2373
+ }
2367
2374
  function validateHeaderStructure(headerObj, filePath, stage) {
2368
2375
  const tableHeader = headerObj?.["QvdTableHeader"];
2369
2376
  if (tableHeader === null || typeof tableHeader !== "object" || Array.isArray(tableHeader)) {
@@ -2373,7 +2380,7 @@ function validateHeaderStructure(headerObj, filePath, stage) {
2373
2380
  stage
2374
2381
  });
2375
2382
  }
2376
- const symbolTableLength = parseInt(tableHeader["Offset"], 10);
2383
+ const symbolTableLength = headerInteger(tableHeader["Offset"]);
2377
2384
  if (isNaN(symbolTableLength) || !Number.isSafeInteger(symbolTableLength) || symbolTableLength < 0) {
2378
2385
  throw new exports.QvdCorruptedError("Invalid symbol table offset", {
2379
2386
  offset: tableHeader["Offset"],
@@ -2381,6 +2388,47 @@ function validateHeaderStructure(headerObj, filePath, stage) {
2381
2388
  stage
2382
2389
  });
2383
2390
  }
2391
+ const fields = tableHeader["Fields"]?.["QvdFieldHeader"];
2392
+ const fieldList = fields === void 0 || fields === null ? [] : Array.isArray(fields) ? fields : [fields];
2393
+ if (fieldList.length === 0) {
2394
+ throw new exports.QvdCorruptedError("The QVD file header declares no fields", {
2395
+ file: filePath,
2396
+ stage
2397
+ });
2398
+ }
2399
+ const malformedIndex = fieldList.findIndex(
2400
+ (field) => field === null || typeof field !== "object" || Array.isArray(field)
2401
+ );
2402
+ if (malformedIndex !== -1) {
2403
+ throw new exports.QvdCorruptedError("The QVD file header declares a field with no properties", {
2404
+ fieldIndex: malformedIndex,
2405
+ fieldCount: fieldList.length,
2406
+ file: filePath,
2407
+ stage
2408
+ });
2409
+ }
2410
+ const seen = /* @__PURE__ */ new Map();
2411
+ fieldList.forEach((field, fieldIndex) => {
2412
+ const name = field["FieldName"];
2413
+ if (typeof name !== "string" || name === "") {
2414
+ throw new exports.QvdCorruptedError("The QVD file header declares a field with no usable name", {
2415
+ fieldIndex,
2416
+ fieldName: name,
2417
+ file: filePath,
2418
+ stage
2419
+ });
2420
+ }
2421
+ if (seen.has(name)) {
2422
+ throw new exports.QvdCorruptedError("The QVD file header declares two fields with the same name", {
2423
+ field: name,
2424
+ fieldIndexes: [seen.get(name), fieldIndex],
2425
+ file: filePath,
2426
+ stage
2427
+ });
2428
+ }
2429
+ seen.set(name, fieldIndex);
2430
+ });
2431
+ return fieldList;
2384
2432
  }
2385
2433
  function validateSymbolTableSizeEarly(symbolTableLength, filePath) {
2386
2434
  const heapLimit = getHeapLimit();
@@ -2426,8 +2474,8 @@ function validateSymbolTableSize(symbolTableLength, filePath, totalRows) {
2426
2474
  }
2427
2475
  }
2428
2476
  function validateFieldMetadata(field, symbolBufferLength, filePath) {
2429
- const symbolsOffset = parseInt(field["Offset"], 10);
2430
- const symbolsLength = parseInt(field["Length"], 10);
2477
+ const symbolsOffset = headerInteger(field["Offset"]);
2478
+ const symbolsLength = headerInteger(field["Length"]);
2431
2479
  if (isNaN(symbolsOffset) || !Number.isSafeInteger(symbolsOffset) || symbolsOffset < 0) {
2432
2480
  throw new exports.QvdCorruptedError("Invalid symbol offset", {
2433
2481
  field: field["FieldName"],
@@ -2455,6 +2503,63 @@ function validateFieldMetadata(field, symbolBufferLength, filePath) {
2455
2503
  });
2456
2504
  }
2457
2505
  }
2506
+ function firstOverlap(ranges) {
2507
+ const claimed = ranges.filter((range) => range.length > 0).sort((a, b) => a.start - b.start);
2508
+ let furthest = null;
2509
+ for (const range of claimed) {
2510
+ if (furthest !== null && range.start < furthest.start + furthest.length) {
2511
+ return [furthest, range];
2512
+ }
2513
+ if (furthest === null || range.start + range.length > furthest.start + furthest.length) {
2514
+ furthest = range;
2515
+ }
2516
+ }
2517
+ return null;
2518
+ }
2519
+ function validateSymbolAreas(fields, filePath) {
2520
+ const overlap = firstOverlap(
2521
+ fields.map((field) => ({
2522
+ field: field["FieldName"],
2523
+ start: headerInteger(field["Offset"]),
2524
+ length: headerInteger(field["Length"])
2525
+ }))
2526
+ );
2527
+ if (overlap !== null) {
2528
+ const [first, second] = overlap;
2529
+ throw new exports.QvdCorruptedError("Symbol areas overlap", {
2530
+ field: second.field,
2531
+ offset: second.start,
2532
+ length: second.length,
2533
+ overlaps: first.field,
2534
+ overlapsOffset: first.start,
2535
+ overlapsLength: first.length,
2536
+ file: filePath,
2537
+ stage: "parseSymbolTable"
2538
+ });
2539
+ }
2540
+ }
2541
+ function validateBitFields(fields, filePath) {
2542
+ const overlap = firstOverlap(
2543
+ fields.map((field) => ({
2544
+ field: field["FieldName"],
2545
+ start: headerInteger(field["BitOffset"]),
2546
+ length: headerInteger(field["BitWidth"])
2547
+ }))
2548
+ );
2549
+ if (overlap !== null) {
2550
+ const [first, second] = overlap;
2551
+ throw new exports.QvdCorruptedError("Bit fields overlap", {
2552
+ field: second.field,
2553
+ bitOffset: second.start,
2554
+ bitWidth: second.length,
2555
+ overlaps: first.field,
2556
+ overlapsBitOffset: first.start,
2557
+ overlapsBitWidth: first.length,
2558
+ file: filePath,
2559
+ stage: "parseIndexTable"
2560
+ });
2561
+ }
2562
+ }
2458
2563
  function validateRecordCount(totalRows, filePath, stage = "parseIndexTable") {
2459
2564
  if (isNaN(totalRows) || !Number.isSafeInteger(totalRows) || totalRows < 0) {
2460
2565
  throw new exports.QvdCorruptedError("Invalid number of records", {
@@ -2464,14 +2569,17 @@ function validateRecordCount(totalRows, filePath, stage = "parseIndexTable") {
2464
2569
  });
2465
2570
  }
2466
2571
  }
2467
- function validateIndexTableMetadata(recordSize, totalRows, indexTableLength, indexTableOffset, bufferLength, rowsToLoad, filePath, fileSize = null, windowFirstRow = 0, bufferFirstRow = 0) {
2572
+ function validateRecordSize(recordSize, filePath, stage = "parseIndexTable") {
2468
2573
  if (isNaN(recordSize) || !Number.isSafeInteger(recordSize) || recordSize < 0) {
2469
2574
  throw new exports.QvdCorruptedError("Invalid record byte size", {
2470
2575
  recordSize,
2471
2576
  file: filePath,
2472
- stage: "parseIndexTable"
2577
+ stage
2473
2578
  });
2474
2579
  }
2580
+ }
2581
+ function validateIndexTableMetadata(recordSize, totalRows, indexTableLength, indexTableOffset, bufferLength, rowsToLoad, filePath, fileSize = null, windowFirstRow = 0, bufferFirstRow = 0) {
2582
+ validateRecordSize(recordSize, filePath);
2475
2583
  validateRecordCount(totalRows, filePath);
2476
2584
  if (recordSize === 0 && totalRows > 0) {
2477
2585
  throw new exports.QvdCorruptedError("Record byte size cannot be zero when records exist", {
@@ -2555,8 +2663,8 @@ function validateIndexTableMetadata(recordSize, totalRows, indexTableLength, ind
2555
2663
  }
2556
2664
  }
2557
2665
  function validateFieldBitMetadata(field, recordSize, filePath) {
2558
- const bitOffset = parseInt(field["BitOffset"], 10);
2559
- const bitWidth = parseInt(field["BitWidth"], 10);
2666
+ const bitOffset = headerInteger(field["BitOffset"]);
2667
+ const bitWidth = headerInteger(field["BitWidth"]);
2560
2668
  if (isNaN(bitOffset) || !Number.isSafeInteger(bitOffset) || bitOffset < 0) {
2561
2669
  throw new exports.QvdCorruptedError("Invalid bit offset", {
2562
2670
  field: field["FieldName"],
@@ -2573,7 +2681,7 @@ function validateFieldBitMetadata(field, recordSize, filePath) {
2573
2681
  stage: "parseIndexTable"
2574
2682
  });
2575
2683
  }
2576
- const bias = parseInt(field["Bias"], 10);
2684
+ const bias = headerInteger(field["Bias"]);
2577
2685
  if (isNaN(bias) || !Number.isSafeInteger(bias)) {
2578
2686
  throw new exports.QvdCorruptedError("Invalid bias", {
2579
2687
  field: field["FieldName"],
@@ -2600,6 +2708,14 @@ function validateFieldBitMetadata(field, recordSize, filePath) {
2600
2708
  stage: "parseIndexTable"
2601
2709
  });
2602
2710
  }
2711
+ if (bias !== 0 && bias !== -2) {
2712
+ throw new exports.QvdCorruptedError("Bias is neither 0 nor -2", {
2713
+ field: field["FieldName"],
2714
+ bias,
2715
+ file: filePath,
2716
+ stage: "parseIndexTable"
2717
+ });
2718
+ }
2603
2719
  const recordSizeInBits = recordSize * 8;
2604
2720
  if (bitOffset + bitWidth > recordSizeInBits) {
2605
2721
  throw new exports.QvdCorruptedError("Bit field extends beyond record size", {
@@ -2617,11 +2733,16 @@ var init_validationUtils = __esm({
2617
2733
  init_QvdErrors();
2618
2734
  init_memoryUtils();
2619
2735
  init_bitUtils();
2736
+ __name(headerInteger, "headerInteger");
2620
2737
  __name(validateHeaderStructure, "validateHeaderStructure");
2621
2738
  __name(validateSymbolTableSizeEarly, "validateSymbolTableSizeEarly");
2622
2739
  __name(validateSymbolTableSize, "validateSymbolTableSize");
2623
2740
  __name(validateFieldMetadata, "validateFieldMetadata");
2741
+ __name(firstOverlap, "firstOverlap");
2742
+ __name(validateSymbolAreas, "validateSymbolAreas");
2743
+ __name(validateBitFields, "validateBitFields");
2624
2744
  __name(validateRecordCount, "validateRecordCount");
2745
+ __name(validateRecordSize, "validateRecordSize");
2625
2746
  __name(validateIndexTableMetadata, "validateIndexTableMetadata");
2626
2747
  __name(validateFieldBitMetadata, "validateFieldBitMetadata");
2627
2748
  }
@@ -3253,6 +3374,31 @@ async function* chunksFrom(handle, chunkSize, failed) {
3253
3374
  position += bytesRead;
3254
3375
  }
3255
3376
  }
3377
+ async function parseHeaderXml(text, file, stage) {
3378
+ let parsed;
3379
+ try {
3380
+ parsed = await xml__default.default.parseStringPromise(text, { explicitArray: false });
3381
+ } catch (error) {
3382
+ throw new exports.QvdParseError(
3383
+ "The XML header could not be parsed.",
3384
+ {
3385
+ // The first line of the parser's message. The rest is the line and column it stopped at, which
3386
+ // stay on `cause`.
3387
+ reason: String(
3388
+ /** @type {any} */
3389
+ error?.message ?? error
3390
+ ).split("\n")[0],
3391
+ file,
3392
+ stage
3393
+ },
3394
+ { cause: error }
3395
+ );
3396
+ }
3397
+ if (!parsed) {
3398
+ throw new exports.QvdParseError("The XML header could not be parsed.", { file, stage });
3399
+ }
3400
+ return parsed;
3401
+ }
3256
3402
  var MAX_HEADER_SIZE, READ_CHUNK_SIZE, ANALYSIS_SLICE_ROWS, COUNT_SYMBOLS_PAST; exports.QvdFileReader = void 0;
3257
3403
  var init_QvdFileReader = __esm({
3258
3404
  "src/QvdFileReader.js"() {
@@ -3273,6 +3419,7 @@ var init_QvdFileReader = __esm({
3273
3419
  ANALYSIS_SLICE_ROWS = 65536;
3274
3420
  COUNT_SYMBOLS_PAST = 65536;
3275
3421
  __name(chunksFrom, "chunksFrom");
3422
+ __name(parseHeaderXml, "parseHeaderXml");
3276
3423
  exports.QvdFileReader = class {
3277
3424
  static {
3278
3425
  __name(this, "QvdFileReader");
@@ -3508,29 +3655,19 @@ var init_QvdFileReader = __esm({
3508
3655
  const headerBuffer = Buffer.concat(headerChunks);
3509
3656
  const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;
3510
3657
  const headerXml = headerBuffer.subarray(0, headerEndIndex).toString();
3511
- const headerObj = await xml2__default.default.parseStringPromise(headerXml, { explicitArray: false });
3512
- if (!headerObj) {
3513
- throw new exports.QvdParseError("The XML header could not be parsed.", {
3514
- file: this._path,
3515
- stage: "readData"
3516
- });
3517
- }
3518
- validateHeaderStructure(headerObj, this._path, "readData");
3658
+ const headerObj = await parseHeaderXml(headerXml, this._path, "readData");
3659
+ const headerFields = validateHeaderStructure(headerObj, this._path, "readData");
3519
3660
  const symbolTableOffset = headerEndIndex;
3520
- const symbolTableLength = parseInt(headerObj["QvdTableHeader"]["Offset"], 10);
3661
+ const symbolTableLength = headerInteger(headerObj["QvdTableHeader"]["Offset"]);
3521
3662
  const indexTableOffset = symbolTableOffset + symbolTableLength;
3522
- const recordSize = parseInt(headerObj["QvdTableHeader"]["RecordByteSize"], 10);
3523
- const totalRows = parseInt(headerObj["QvdTableHeader"]["NoOfRecords"], 10);
3663
+ const recordSize = headerInteger(headerObj["QvdTableHeader"]["RecordByteSize"]);
3664
+ const totalRows = headerInteger(headerObj["QvdTableHeader"]["NoOfRecords"]);
3524
3665
  if (headerOnly) {
3525
3666
  this._buffer = headerBuffer.subarray(0, headerEndIndex);
3526
3667
  this._emitProgress("read", 1, 1);
3527
3668
  return;
3528
3669
  }
3529
- let headerFields = headerObj["QvdTableHeader"]?.["Fields"]?.["QvdFieldHeader"];
3530
- if (headerFields && !Array.isArray(headerFields)) {
3531
- headerFields = [headerFields];
3532
- }
3533
- const columnCount = Array.isArray(headerFields) ? selectFields(headerFields, this._requestedFields, this._path).length : 0;
3670
+ const columnCount = selectFields(headerFields, this._requestedFields, this._path).length;
3534
3671
  const headerNumbersUsable = [symbolTableLength, recordSize, totalRows].every(
3535
3672
  (value) => Number.isSafeInteger(value) && value >= 0
3536
3673
  );
@@ -3562,20 +3699,8 @@ var init_QvdFileReader = __esm({
3562
3699
  }
3563
3700
  const rowsToLoad = windowRows;
3564
3701
  validateSymbolTableSizeEarly(symbolTableLength, this._path);
3565
- for (const [name, value] of [
3566
- ["Offset", symbolTableLength],
3567
- ["RecordByteSize", recordSize],
3568
- ["NoOfRecords", totalRows]
3569
- ]) {
3570
- if (!Number.isSafeInteger(value) || Number(value) < 0) {
3571
- throw new exports.QvdCorruptedError(`Invalid header value: ${name}`, {
3572
- name,
3573
- value,
3574
- file: this._path,
3575
- stage: "readData"
3576
- });
3577
- }
3578
- }
3702
+ validateRecordSize(recordSize, this._path, "readData");
3703
+ validateRecordCount(totalRows, this._path, "readData");
3579
3704
  const skippedIndexBytes = resolved.offset * recordSize;
3580
3705
  const indexTableBytesToRead = rowsToLoad * recordSize;
3581
3706
  const totalBytesToRead = indexTableOffset + indexTableBytesToRead;
@@ -3674,36 +3799,11 @@ var init_QvdFileReader = __esm({
3674
3799
  const headerEndIndex = headerDelimiterIndex + HEADER_DELIMITER.length;
3675
3800
  const headerBuffer = this._buffer.subarray(headerBeginIndex, headerEndIndex);
3676
3801
  this._fieldBitMetadataValidated = false;
3677
- this._header = await xml2__default.default.parseStringPromise(headerBuffer.toString(), { explicitArray: false });
3678
- if (!this._header) {
3679
- throw new exports.QvdParseError("The XML header could not be parsed.", {
3680
- file: this._path,
3681
- stage: "parseHeader"
3682
- });
3683
- }
3684
- validateHeaderStructure(this._header, this._path, "parseHeader");
3685
- const fields = this._header["QvdTableHeader"]?.["Fields"]?.["QvdFieldHeader"];
3686
- const fieldList = fields === void 0 || fields === null ? [] : Array.isArray(fields) ? fields : [fields];
3687
- if (fieldList.length === 0) {
3688
- throw new exports.QvdCorruptedError("The QVD file header declares no fields", {
3689
- file: this._path,
3690
- stage: "parseHeader"
3691
- });
3692
- }
3693
- const malformedIndex = fieldList.findIndex(
3694
- (field) => field === null || typeof field !== "object" || Array.isArray(field)
3695
- );
3696
- if (malformedIndex !== -1) {
3697
- throw new exports.QvdCorruptedError("The QVD file header declares a field with no properties", {
3698
- fieldIndex: malformedIndex,
3699
- fieldCount: fieldList.length,
3700
- file: this._path,
3701
- stage: "parseHeader"
3702
- });
3703
- }
3802
+ this._header = await parseHeaderXml(headerBuffer.toString(), this._path, "parseHeader");
3803
+ const fieldList = validateHeaderStructure(this._header, this._path, "parseHeader");
3704
3804
  this._headerOffset = headerBeginIndex;
3705
3805
  this._symbolTableOffset = headerEndIndex;
3706
- this._indexTableOffset = this._symbolTableOffset + parseInt(this._header["QvdTableHeader"]["Offset"], 10);
3806
+ this._indexTableOffset = this._symbolTableOffset + headerInteger(this._header["QvdTableHeader"]["Offset"]);
3707
3807
  this._allFields = fieldList;
3708
3808
  this._selectedFields = selectFields(this._allFields, this._requestedFields, this._path);
3709
3809
  }
@@ -3735,9 +3835,9 @@ var init_QvdFileReader = __esm({
3735
3835
  }
3736
3836
  const allFields = this._allFields;
3737
3837
  const fields = this._selectedFields;
3738
- const recordSize = parseInt(this._header["QvdTableHeader"]["RecordByteSize"], 10);
3739
- const totalRows = parseInt(this._header["QvdTableHeader"]["NoOfRecords"], 10);
3740
- const indexTableLength = parseInt(this._header["QvdTableHeader"]["Length"], 10);
3838
+ const recordSize = headerInteger(this._header["QvdTableHeader"]["RecordByteSize"]);
3839
+ const totalRows = headerInteger(this._header["QvdTableHeader"]["NoOfRecords"]);
3840
+ const indexTableLength = headerInteger(this._header["QvdTableHeader"]["Length"]);
3741
3841
  const { offset: firstRow, limit: rowsToLoad } = resolveWindow(window, totalRows);
3742
3842
  validateIndexTableMetadata(
3743
3843
  recordSize,
@@ -3760,6 +3860,7 @@ var init_QvdFileReader = __esm({
3760
3860
  for (const field of allFields) {
3761
3861
  validateFieldBitMetadata(field, recordSize, this._path);
3762
3862
  }
3863
+ validateBitFields(allFields, this._path);
3763
3864
  this._fieldBitMetadataValidated = true;
3764
3865
  }
3765
3866
  assert3__default.default(
@@ -3790,10 +3891,10 @@ var init_QvdFileReader = __esm({
3790
3891
  this._throwIfAborted();
3791
3892
  const needed = /* @__PURE__ */ new Set();
3792
3893
  symbolUsage[position] = needed;
3793
- const bitOffset = parseInt(field["BitOffset"], 10);
3794
- const bitWidth = parseInt(field["BitWidth"], 10);
3795
- const bias = parseInt(field["Bias"], 10);
3796
- const length = parseInt(field["Length"], 10);
3894
+ const bitOffset = headerInteger(field["BitOffset"]);
3895
+ const bitWidth = headerInteger(field["BitWidth"]);
3896
+ const bias = headerInteger(field["Bias"]);
3897
+ const length = headerInteger(field["Length"]);
3797
3898
  let indexLimit = Number.isSafeInteger(length) && length >= 0 ? Math.ceil(length / 2) : Infinity;
3798
3899
  let counted = false;
3799
3900
  for (let first = 0; first < rowsToLoad; first += sliceRows) {
@@ -3846,11 +3947,11 @@ var init_QvdFileReader = __esm({
3846
3947
  );
3847
3948
  const symbolBuffer = this._buffer.subarray(this._symbolTableOffset, this._indexTableOffset);
3848
3949
  validateFieldMetadata(field, symbolBuffer.length, this._path);
3849
- const offset = parseInt(field["Offset"], 10);
3950
+ const offset = headerInteger(field["Offset"]);
3850
3951
  return countFieldSymbols(
3851
3952
  symbolBuffer,
3852
3953
  offset,
3853
- offset + parseInt(field["Length"], 10),
3954
+ offset + headerInteger(field["Length"]),
3854
3955
  field["FieldName"],
3855
3956
  this._path
3856
3957
  );
@@ -3885,7 +3986,7 @@ var init_QvdFileReader = __esm({
3885
3986
  const fields = this._selectedFields;
3886
3987
  const symbolBuffer = this._buffer.subarray(this._symbolTableOffset, this._indexTableOffset);
3887
3988
  const symbolTableSize = symbolBuffer.length;
3888
- const totalRows = parseInt(this._header["QvdTableHeader"]["NoOfRecords"], 10);
3989
+ const totalRows = headerInteger(this._header["QvdTableHeader"]["NoOfRecords"]);
3889
3990
  validateSymbolTableSize(symbolTableSize, this._path, totalRows);
3890
3991
  if (this._headerMatchesFile) {
3891
3992
  validateMemoryAvailability(
@@ -3903,10 +4004,11 @@ var init_QvdFileReader = __esm({
3903
4004
  for (const field of allFields) {
3904
4005
  validateFieldMetadata(field, symbolBuffer.length, this._path);
3905
4006
  }
4007
+ validateSymbolAreas(allFields, this._path);
3906
4008
  this._symbolTable = fields.map((field, position) => {
3907
4009
  this._throwIfAborted();
3908
- const symbolsOffset = parseInt(field["Offset"], 10);
3909
- const symbolsLength = parseInt(field["Length"], 10);
4010
+ const symbolsOffset = headerInteger(field["Offset"]);
4011
+ const symbolsLength = headerInteger(field["Length"]);
3910
4012
  const symbols = parseFieldSymbols(
3911
4013
  symbolBuffer,
3912
4014
  symbolsOffset,
@@ -3958,9 +4060,9 @@ var init_QvdFileReader = __esm({
3958
4060
  indexBuffer,
3959
4061
  recordSize,
3960
4062
  rowsToLoad,
3961
- parseInt(field["BitOffset"], 10),
3962
- parseInt(field["BitWidth"], 10),
3963
- parseInt(field["Bias"], 10),
4063
+ headerInteger(field["BitOffset"]),
4064
+ headerInteger(field["BitWidth"]),
4065
+ headerInteger(field["Bias"]),
3964
4066
  new Int32Array(rowsToLoad),
3965
4067
  { symbolCount: symbolTable[position].numbers.length, field: field["FieldName"], file: this._path, firstRow }
3966
4068
  );
@@ -3990,23 +4092,13 @@ var init_QvdFileReader = __esm({
3990
4092
  await this._parseHeader();
3991
4093
  this._emitProgress("header", 1, 1);
3992
4094
  this._throwIfAborted();
3993
- assert3__default.default(this._header, "The QVD file header has not been parsed.");
4095
+ assert3__default.default(this._header && this._allFields, "The QVD file header has not been parsed.");
3994
4096
  const header = this._header["QvdTableHeader"];
3995
- let fields = header["Fields"]?.["QvdFieldHeader"] ?? [];
3996
- if (!Array.isArray(fields)) {
3997
- fields = [fields];
3998
- }
3999
- if (fields.length === 0) {
4000
- throw new exports.QvdCorruptedError("The QVD file header declares no fields", {
4001
- file: this._path,
4002
- stage: "readMetadata"
4003
- });
4004
- }
4005
- const columns = fields.map((field) => field["FieldName"]);
4006
- const rowCount = parseInt(header["NoOfRecords"], 10);
4097
+ const columns = this._allFields.map((field) => field["FieldName"]);
4098
+ const rowCount = headerInteger(header["NoOfRecords"]);
4007
4099
  validateRecordCount(rowCount, this._path, "readMetadata");
4008
4100
  const shape = new exports.QvdDataFrame([], columns, header, {
4009
- symbolTableBytes: parseInt(header["Offset"], 10),
4101
+ symbolTableBytes: headerInteger(header["Offset"]),
4010
4102
  totalRows: rowCount,
4011
4103
  rowsLoaded: 0,
4012
4104
  symbolFiltering: false,
@@ -4171,8 +4263,8 @@ var init_QvdFileReader = __esm({
4171
4263
  this._emitProgress("header", 1, 1);
4172
4264
  this._throwIfAborted();
4173
4265
  assert3__default.default(this._header, "The QVD file header has not been parsed.");
4174
- const totalRows = parseInt(this._header["QvdTableHeader"]["NoOfRecords"], 10);
4175
- const symbolTableLength = parseInt(this._header["QvdTableHeader"]["Offset"], 10);
4266
+ const totalRows = headerInteger(this._header["QvdTableHeader"]["NoOfRecords"]);
4267
+ const symbolTableLength = headerInteger(this._header["QvdTableHeader"]["Offset"]);
4176
4268
  const resolved = resolveWindow(window, totalRows);
4177
4269
  const rowsAvailable = resolved.limit;
4178
4270
  let symbolsToKeep = null;