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 +192 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +191 -99
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
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 =
|
|
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 =
|
|
2418
|
-
const symbolsLength =
|
|
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
|
|
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
|
|
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 =
|
|
2547
|
-
const bitWidth =
|
|
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 =
|
|
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
|
|
3500
|
-
|
|
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 =
|
|
3649
|
+
const symbolTableLength = headerInteger(headerObj["QvdTableHeader"]["Offset"]);
|
|
3509
3650
|
const indexTableOffset = symbolTableOffset + symbolTableLength;
|
|
3510
|
-
const recordSize =
|
|
3511
|
-
const totalRows =
|
|
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
|
-
|
|
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
|
-
|
|
3554
|
-
|
|
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
|
|
3666
|
-
|
|
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 +
|
|
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 =
|
|
3727
|
-
const totalRows =
|
|
3728
|
-
const indexTableLength =
|
|
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 =
|
|
3782
|
-
const bitWidth =
|
|
3783
|
-
const bias =
|
|
3784
|
-
const length =
|
|
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 =
|
|
3938
|
+
const offset = headerInteger(field["Offset"]);
|
|
3838
3939
|
return countFieldSymbols(
|
|
3839
3940
|
symbolBuffer,
|
|
3840
3941
|
offset,
|
|
3841
|
-
offset +
|
|
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 =
|
|
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 =
|
|
3897
|
-
const symbolsLength =
|
|
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
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
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
|
-
|
|
3984
|
-
|
|
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:
|
|
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 =
|
|
4163
|
-
const symbolTableLength =
|
|
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;
|