xz-compat 1.1.0 → 1.1.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/cjs/xz/Decoder.d.cts +2 -2
- package/dist/cjs/xz/Decoder.d.ts +2 -2
- package/dist/cjs/xz/Decoder.js +48 -18
- package/dist/cjs/xz/Decoder.js.map +1 -1
- package/dist/esm/xz/Decoder.d.ts +2 -2
- package/dist/esm/xz/Decoder.js +44 -18
- package/dist/esm/xz/Decoder.js.map +1 -1
- package/package.json +1 -1
|
@@ -37,7 +37,7 @@ export declare function decodeXZ(input: Buffer): Promise<BufferLike>;
|
|
|
37
37
|
* Create an XZ decompression Transform stream
|
|
38
38
|
* @returns Transform stream that decompresses XZ data
|
|
39
39
|
*
|
|
40
|
-
* Uses
|
|
41
|
-
*
|
|
40
|
+
* Uses native lzma-native bindings when available for better performance.
|
|
41
|
+
* Falls back to pure JS implementation on older Node versions or when native is unavailable.
|
|
42
42
|
*/
|
|
43
43
|
export declare function createXZDecoder(): TransformType;
|
package/dist/cjs/xz/Decoder.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare function decodeXZ(input: Buffer): Promise<BufferLike>;
|
|
|
37
37
|
* Create an XZ decompression Transform stream
|
|
38
38
|
* @returns Transform stream that decompresses XZ data
|
|
39
39
|
*
|
|
40
|
-
* Uses
|
|
41
|
-
*
|
|
40
|
+
* Uses native lzma-native bindings when available for better performance.
|
|
41
|
+
* Falls back to pure JS implementation on older Node versions or when native is unavailable.
|
|
42
42
|
*/
|
|
43
43
|
export declare function createXZDecoder(): TransformType;
|
package/dist/cjs/xz/Decoder.js
CHANGED
|
@@ -323,9 +323,16 @@ var FILTER_LZMA2 = 0x21;
|
|
|
323
323
|
var indexStart = footerEnd - 12 - backwardSize;
|
|
324
324
|
// Parse Index to get block information
|
|
325
325
|
var blockRecords = parseIndex(input, indexStart, checkSize);
|
|
326
|
-
//
|
|
327
|
-
|
|
328
|
-
|
|
326
|
+
// Calculate total uncompressed size for multi-block decision
|
|
327
|
+
var totalUncompressedSize = 0;
|
|
328
|
+
for(var i = 0; i < blockRecords.length; i++){
|
|
329
|
+
totalUncompressedSize += blockRecords[i].uncompressedSize;
|
|
330
|
+
}
|
|
331
|
+
// Small multi-block files: use Buffer.concat directly (avoids BufferList overhead)
|
|
332
|
+
// Threshold of 64KB: below this, the overhead of linked list nodes isn't worth it
|
|
333
|
+
var BUFFERLIST_THRESHOLD = 64 * 1024; // 64KB
|
|
334
|
+
// Single block OR small multi-block: return Buffer directly
|
|
335
|
+
if (blockRecords.length === 1 || totalUncompressedSize < BUFFERLIST_THRESHOLD) {
|
|
329
336
|
var record = blockRecords[0];
|
|
330
337
|
var recordStart = record.compressedPos;
|
|
331
338
|
var blockInfo = parseBlockHeader(input, recordStart, checkSize);
|
|
@@ -338,10 +345,10 @@ var FILTER_LZMA2 = 0x21;
|
|
|
338
345
|
}
|
|
339
346
|
return blockOutput;
|
|
340
347
|
}
|
|
341
|
-
// Multi-block: use BufferList to avoid large contiguous allocation
|
|
348
|
+
// Multi-block (large): use BufferList to avoid large contiguous allocation
|
|
342
349
|
var output = new _extractbaseiterator.BufferList();
|
|
343
|
-
for(var
|
|
344
|
-
var record1 = blockRecords[
|
|
350
|
+
for(var i1 = 0; i1 < blockRecords.length; i1++){
|
|
351
|
+
var record1 = blockRecords[i1];
|
|
345
352
|
var recordStart1 = record1.compressedPos;
|
|
346
353
|
// Parse block header
|
|
347
354
|
var blockInfo1 = parseBlockHeader(input, recordStart1, checkSize);
|
|
@@ -400,6 +407,23 @@ function decodeXZ(input, callback) {
|
|
|
400
407
|
}
|
|
401
408
|
function createXZDecoder() {
|
|
402
409
|
var bufferList = new _extractbaseiterator.BufferList();
|
|
410
|
+
// Cache native module lookup (only done once)
|
|
411
|
+
var native = (0, _nativets.tryLoadNative)();
|
|
412
|
+
// Choose decoder: native (async via callback) or pure JS (sync wrapped in callback)
|
|
413
|
+
var decodeLzma2Block = (native === null || native === void 0 ? void 0 : native.lzma2) ? function(data, props, size, cb) {
|
|
414
|
+
var _native_lzma2;
|
|
415
|
+
(_native_lzma2 = native.lzma2) === null || _native_lzma2 === void 0 ? void 0 : _native_lzma2.call(native, data, props, size).then(function(result) {
|
|
416
|
+
return cb(null, result);
|
|
417
|
+
}, function(err) {
|
|
418
|
+
return cb(err);
|
|
419
|
+
});
|
|
420
|
+
} : function(data, props, size, cb) {
|
|
421
|
+
try {
|
|
422
|
+
cb(null, (0, _indexts.decodeLzma2)(data, props, size));
|
|
423
|
+
} catch (err) {
|
|
424
|
+
cb(err);
|
|
425
|
+
}
|
|
426
|
+
};
|
|
403
427
|
return new _extractbaseiterator.Transform({
|
|
404
428
|
transform: function transform(chunk, _encoding, callback) {
|
|
405
429
|
bufferList.append(chunk);
|
|
@@ -466,7 +490,7 @@ function createXZDecoder() {
|
|
|
466
490
|
var indexStart = footerEnd - 12 - backwardSize;
|
|
467
491
|
// Parse Index to get block information
|
|
468
492
|
var blockRecords = parseIndex(input, indexStart, checkSize);
|
|
469
|
-
// Decompress
|
|
493
|
+
// Decompress blocks sequentially (native is async)
|
|
470
494
|
var blockIndex = 0;
|
|
471
495
|
var pushBlock = function(err) {
|
|
472
496
|
if (err) {
|
|
@@ -474,7 +498,8 @@ function createXZDecoder() {
|
|
|
474
498
|
return;
|
|
475
499
|
}
|
|
476
500
|
if (blockIndex >= blockRecords.length) {
|
|
477
|
-
// All blocks processed
|
|
501
|
+
// All blocks processed - purge input BufferList to free memory
|
|
502
|
+
if (!Buffer.isBuffer(input)) input.clear();
|
|
478
503
|
callback(null);
|
|
479
504
|
return;
|
|
480
505
|
}
|
|
@@ -491,16 +516,21 @@ function createXZDecoder() {
|
|
|
491
516
|
var dataStart = recordStart + headerSize;
|
|
492
517
|
var dataEnd = dataStart + record.compressedDataSize;
|
|
493
518
|
var compressedData = input.slice(dataStart, dataEnd);
|
|
494
|
-
// Decompress this block
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
519
|
+
// Decompress this block (native or pure JS, callback-based)
|
|
520
|
+
decodeLzma2Block(compressedData, blockInfo.lzma2Props, record.uncompressedSize, function(decodeErr, blockOutput) {
|
|
521
|
+
if (decodeErr || !blockOutput) {
|
|
522
|
+
pushBlock(decodeErr || new Error('Decode returned no data'));
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
// Apply preprocessing filters in reverse order
|
|
526
|
+
for(var j = blockInfo.filters.length - 1; j >= 0; j--){
|
|
527
|
+
blockOutput = applyFilter(blockOutput, blockInfo.filters[j]);
|
|
528
|
+
}
|
|
529
|
+
// Push the block output immediately (streaming)
|
|
530
|
+
_this.push(blockOutput);
|
|
531
|
+
// Continue with next block
|
|
532
|
+
pushBlock(null);
|
|
533
|
+
});
|
|
504
534
|
};
|
|
505
535
|
// Start processing blocks
|
|
506
536
|
pushBlock(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/iterators/xz-compat/src/xz/Decoder.ts"],"sourcesContent":["/**\n * XZ Decompression Module\n *\n * XZ is a container format that wraps LZMA2 compressed data.\n * This module provides both synchronous and streaming XZ decoders.\n *\n * Pure JavaScript implementation, works on Node.js 0.8+\n *\n * IMPORTANT: Buffer Management Pattern\n *\n * When calling decodeLzma2(), use the direct return pattern:\n *\n * ✅ CORRECT - Fast path:\n * const output = decodeLzma2(data, props, size) as Buffer;\n *\n * ❌ WRONG - Slow path (do NOT buffer):\n * const chunks: Buffer[] = [];\n * decodeLzma2(data, props, size, { write: c => chunks.push(c) });\n * return Buffer.concat(chunks); // ← Unnecessary copies!\n */\n\nimport { type BufferLike, BufferList, Transform } from 'extract-base-iterator';\nimport type { Transform as TransformType } from 'stream';\nimport { decodeBcj } from '../filters/bcj/Bcj.ts';\nimport { decodeBcjArm } from '../filters/bcj/BcjArm.ts';\nimport { decodeBcjArm64 } from '../filters/bcj/BcjArm64.ts';\nimport { decodeBcjArmt } from '../filters/bcj/BcjArmt.ts';\nimport { decodeBcjIa64 } from '../filters/bcj/BcjIa64.ts';\nimport { decodeBcjPpc } from '../filters/bcj/BcjPpc.ts';\nimport { decodeBcjSparc } from '../filters/bcj/BcjSparc.ts';\nimport { decodeDelta } from '../filters/delta/Delta.ts';\nimport { decodeLzma2 } from '../lzma/index.ts';\nimport { tryLoadNative } from '../native.ts';\nimport type { DecodeCallback } from '../sevenz.ts';\n\n// XZ magic bytes\nconst XZ_MAGIC = [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00];\nconst XZ_FOOTER_MAGIC = [0x59, 0x5a]; // \"YZ\"\n\n// Filter IDs (from XZ specification)\nconst FILTER_DELTA = 0x03;\nconst FILTER_BCJ_X86 = 0x04;\nconst FILTER_BCJ_PPC = 0x05;\nconst FILTER_BCJ_IA64 = 0x06;\nconst FILTER_BCJ_ARM = 0x07;\nconst FILTER_BCJ_ARMT = 0x08;\nconst FILTER_BCJ_SPARC = 0x09;\nconst FILTER_BCJ_ARM64 = 0x0a;\nconst FILTER_LZMA2 = 0x21;\n\n// Filter info for parsing\ninterface FilterInfo {\n id: number;\n props: Buffer;\n}\n\n// Re-export BufferLike for public API\nexport type { BufferLike } from 'extract-base-iterator';\n\n/**\n * Read a byte from Buffer or BufferList\n */\nfunction readByte(buf: BufferLike, offset: number): number {\n return Buffer.isBuffer(buf) ? buf[offset] : buf.readByte(offset);\n}\n\n/**\n * Read UInt32LE from Buffer or BufferList (returns null if out of bounds)\n */\nfunction readUInt32LE(buf: BufferLike, offset: number): number | null {\n if (Buffer.isBuffer(buf)) {\n if (offset < 0 || offset + 4 > buf.length) return null;\n return buf.readUInt32LE(offset);\n }\n return buf.readUInt32LEAt(offset);\n}\n\n/**\n * Compare buffer contents at offset with expected byte sequence\n * Works with both Buffer and BufferList\n */\nfunction bufferEquals(buf: BufferLike, offset: number, expected: number[]): boolean {\n if (offset + expected.length > buf.length) {\n return false;\n }\n for (let i = 0; i < expected.length; i++) {\n if (readByte(buf, offset + i) !== expected[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Decode variable-length integer (XZ multibyte encoding)\n * Works with both Buffer and BufferList\n */\nfunction decodeMultibyte(buf: BufferLike, offset: number): { value: number; bytesRead: number } {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= buf.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = readByte(buf, offset + i);\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n}\n\n/**\n * Apply a preprocessing filter (BCJ/Delta) to decompressed data\n */\nfunction applyFilter(data: Buffer, filter: FilterInfo): Buffer {\n switch (filter.id) {\n case FILTER_BCJ_X86:\n return decodeBcj(data, filter.props);\n case FILTER_BCJ_ARM:\n return decodeBcjArm(data, filter.props);\n case FILTER_BCJ_ARM64:\n return decodeBcjArm64(data, filter.props);\n case FILTER_BCJ_ARMT:\n return decodeBcjArmt(data, filter.props);\n case FILTER_BCJ_PPC:\n return decodeBcjPpc(data, filter.props);\n case FILTER_BCJ_SPARC:\n return decodeBcjSparc(data, filter.props);\n case FILTER_BCJ_IA64:\n return decodeBcjIa64(data, filter.props);\n case FILTER_DELTA:\n return decodeDelta(data, filter.props);\n default:\n throw new Error(`Unsupported filter: 0x${filter.id.toString(16)}`);\n }\n}\n\n/**\n * Parse XZ Block Header to extract filters and LZMA2 properties\n */\nfunction parseBlockHeader(\n input: Buffer,\n offset: number,\n _checkSize: number\n): {\n filters: FilterInfo[];\n lzma2Props: Buffer;\n headerSize: number;\n dataStart: number;\n dataEnd: number;\n nextOffset: number;\n} {\n // Block header size\n const blockHeaderSizeRaw = input[offset];\n if (blockHeaderSizeRaw === 0) {\n throw new Error('Invalid block header size (index indicator found instead of block)');\n }\n const blockHeaderSize = (blockHeaderSizeRaw + 1) * 4;\n\n // Parse block header\n const blockHeaderStart = offset;\n offset++; // skip size byte\n\n const blockFlags = input[offset++];\n const numFilters = (blockFlags & 0x03) + 1;\n const hasCompressedSize = (blockFlags & 0x40) !== 0;\n const hasUncompressedSize = (blockFlags & 0x80) !== 0;\n\n // Skip optional sizes\n if (hasCompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n if (hasUncompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n // Parse all filters\n const filters: FilterInfo[] = [];\n let lzma2Props: Buffer | null = null;\n\n for (let i = 0; i < numFilters; i++) {\n const filterIdResult = decodeMultibyte(input, offset);\n const filterId = filterIdResult.value;\n offset += filterIdResult.bytesRead;\n\n const propsSizeResult = decodeMultibyte(input, offset);\n offset += propsSizeResult.bytesRead;\n\n const filterProps = input.slice(offset, offset + propsSizeResult.value);\n offset += propsSizeResult.value;\n\n if (filterId === FILTER_LZMA2) {\n // LZMA2 must be the last filter\n lzma2Props = filterProps;\n } else if (filterId === FILTER_DELTA || (filterId >= FILTER_BCJ_X86 && filterId <= FILTER_BCJ_ARM64)) {\n // Preprocessing filter - store for later application\n filters.push({ id: filterId, props: filterProps });\n } else {\n throw new Error(`Unsupported filter: 0x${filterId.toString(16)}`);\n }\n }\n\n if (!lzma2Props) {\n throw new Error('No LZMA2 filter found in XZ block');\n }\n\n // Skip to end of block header (must be aligned to 4 bytes)\n const blockDataStart = blockHeaderStart + blockHeaderSize;\n\n return {\n filters,\n lzma2Props,\n headerSize: blockHeaderSize,\n dataStart: blockDataStart,\n dataEnd: input.length,\n nextOffset: blockDataStart,\n };\n}\n\n/**\n * Parse XZ Index to get block positions\n * Works with both Buffer and BufferList\n */\nfunction parseIndex(\n input: BufferLike,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n // One-time binding for buffer access (avoids repeated Buffer.isBuffer checks)\n const getByte = Buffer.isBuffer(input) ? (offset: number) => input[offset] : (offset: number) => input.readByte(offset);\n\n // Local multibyte decoder using bound getByte\n const decodeMultibyteLocal = (offset: number): { value: number; bytesRead: number } => {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= input.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = getByte(offset + i);\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n };\n\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (getByte(offset) !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyteLocal(offset);\n const recordCount = countResult.value;\n offset += countResult.bytesRead;\n\n const records: Array<{\n compressedPos: number;\n unpaddedSize: number;\n compressedDataSize: number;\n uncompressedSize: number;\n }> = [];\n\n // Parse each record\n for (let i = 0; i < recordCount; i++) {\n // Unpadded Size (header + compressed data + check)\n const unpaddedResult = decodeMultibyteLocal(offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyteLocal(offset);\n offset += uncompressedResult.bytesRead;\n\n records.push({\n compressedPos: 0, // will be calculated\n unpaddedSize: unpaddedResult.value,\n compressedDataSize: 0, // will be calculated\n uncompressedSize: uncompressedResult.value,\n });\n }\n\n // Calculate actual positions by walking through blocks\n let currentPos = 12; // After stream header\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n // Record where this block's header starts\n record.compressedPos = currentPos;\n\n // Get block header size from the actual data\n const headerSizeRaw = getByte(currentPos);\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n record.compressedDataSize = record.unpaddedSize - headerSize - checkSize;\n\n // Move to next block: unpaddedSize + padding to 4-byte boundary\n const paddedSize = Math.ceil(record.unpaddedSize / 4) * 4;\n currentPos += paddedSize;\n }\n\n return records;\n}\n\n/**\n * Pure JS XZ decompression (handles all XZ spec features)\n * Returns BufferList for memory efficiency with large files.\n */\nfunction decodeXZPure(input: Buffer): Buffer | BufferList {\n // Verify XZ magic\n if (input.length < 12 || !bufferEquals(input, 0, XZ_MAGIC)) {\n throw new Error('Invalid XZ magic bytes');\n }\n\n // Stream flags at offset 6-7\n const checkType = readByte(input, 7) & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n // Stream padding must be multiple of 4 bytes\n let footerEnd = input.length;\n while (footerEnd > 12 && readByte(input, footerEnd - 1) === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary (stream padding rules)\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {\n throw new Error('Invalid XZ footer magic');\n }\n\n // Get backward size (tells us where index starts) - at footerEnd - 8\n const backwardSizeLE = readUInt32LE(input, footerEnd - 8);\n if (backwardSizeLE === null) {\n throw new Error('Invalid backward size');\n }\n const backwardSize = (backwardSizeLE + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Single block optimization: return Buffer directly (avoids BufferList overhead)\n // Most small files have only one block\n if (blockRecords.length === 1) {\n const record = blockRecords[0];\n const recordStart = record.compressedPos;\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n const dataStart = recordStart + blockInfo.headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n const compressedData = input.slice(dataStart, dataEnd);\n\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n return blockOutput;\n }\n\n // Multi-block: use BufferList to avoid large contiguous allocation\n const output = new BufferList();\n\n for (let i = 0; i < blockRecords.length; i++) {\n const record = blockRecords[i];\n const recordStart = record.compressedPos;\n\n // Parse block header\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + blockInfo.headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n\n // Note: XZ blocks have padding AFTER the check field to align to 4 bytes,\n // but the compressedSize from index is exact - no need to strip padding.\n // LZMA2 data includes a 0x00 end marker which must NOT be stripped.\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block with LZMA2 (fast path, no buffering)\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n // Apply preprocessing filters in reverse order (BCJ/Delta applied after LZMA2)\n // Filters are stored in order they were applied during compression,\n // so we need to reverse for decompression\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n // Append block to BufferList\n output.append(blockOutput);\n }\n\n return output;\n}\n\n/** Callback invoked when an async decode completes */\nexport type XzDecodeCallback = DecodeCallback<BufferLike>;\n\n/**\n * Decompress XZ data. With a callback the result is provided asynchronously;\n * otherwise a Promise resolves with the decoded data.\n *\n * Returns Buffer for single-block files (most small files).\n * Returns BufferList for multi-block files (avoids large contiguous allocation).\n */\nexport function decodeXZ(input: Buffer, callback: XzDecodeCallback): void;\nexport function decodeXZ(input: Buffer): Promise<BufferLike>;\nexport function decodeXZ(input: Buffer, callback?: XzDecodeCallback): Promise<BufferLike> | void {\n const worker = (cb: XzDecodeCallback) => {\n const fallback = () => {\n try {\n cb(null, decodeXZPure(input));\n } catch (err) {\n cb(err as Error);\n }\n };\n\n const native = tryLoadNative();\n if (native?.xz?.decompress) {\n try {\n const promise = native.xz.decompress(input);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value as BufferLike), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as BufferLike))));\n}\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n *\n * Uses BufferList to avoid large contiguous buffer allocations.\n * Decompresses and pushes blocks one at a time for streaming output.\n */\nexport function createXZDecoder(): TransformType {\n const bufferList = new BufferList();\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n bufferList.append(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n const input: BufferLike = bufferList;\n\n // One-time binding for buffer access (avoids repeated Buffer.isBuffer checks)\n const getByte = Buffer.isBuffer(input) ? (offset: number) => input[offset] : (offset: number) => input.readByte(offset);\n\n const getUInt32LE = Buffer.isBuffer(input) ? (offset: number) => (offset < 0 || offset + 4 > input.length ? null : input.readUInt32LE(offset)) : (offset: number) => input.readUInt32LEAt(offset);\n\n const equals = (offset: number, expected: number[]): boolean => {\n if (offset + expected.length > input.length) return false;\n for (let i = 0; i < expected.length; i++) {\n if (getByte(offset + i) !== expected[i]) return false;\n }\n return true;\n };\n\n // Verify XZ magic (need at least 12 bytes)\n if (input.length < 12 || !equals(0, XZ_MAGIC)) {\n callback(new Error('Invalid XZ magic bytes'));\n return;\n }\n\n // Stream flags at offset 6-7\n const checkType = getByte(7) & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n let footerEnd = input.length;\n while (footerEnd > 12 && getByte(footerEnd - 1) === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!equals(footerEnd - 2, XZ_FOOTER_MAGIC)) {\n callback(new Error('Invalid XZ footer magic'));\n return;\n }\n\n // Get backward size (at footerEnd - 8)\n const backwardSizeLE = getUInt32LE(footerEnd - 8);\n if (backwardSizeLE === null) {\n callback(new Error('Invalid backward size'));\n return;\n }\n const backwardSize = (backwardSizeLE + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Decompress and push each block (streaming, no large allocations)\n let blockIndex = 0;\n const pushBlock = (err: Error | null) => {\n if (err) {\n callback(err);\n return;\n }\n\n if (blockIndex >= blockRecords.length) {\n // All blocks processed\n callback(null);\n return;\n }\n\n const record = blockRecords[blockIndex++];\n const recordStart = record.compressedPos;\n\n // Parse block header (need to get the header bytes)\n // Read header size byte first\n const headerSizeRaw = getByte(recordStart);\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Read the full header to parse filters\n const headerData = input.slice(recordStart, recordStart + headerSize);\n const blockInfo = parseBlockHeader(headerData, 0, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n // Apply preprocessing filters in reverse order\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n // Push the block output immediately (streaming)\n this.push(blockOutput);\n\n // Continue with next block\n pushBlock(null);\n };\n\n // Start processing blocks\n pushBlock(null);\n },\n });\n}\n"],"names":["createXZDecoder","decodeXZ","XZ_MAGIC","XZ_FOOTER_MAGIC","FILTER_DELTA","FILTER_BCJ_X86","FILTER_BCJ_PPC","FILTER_BCJ_IA64","FILTER_BCJ_ARM","FILTER_BCJ_ARMT","FILTER_BCJ_SPARC","FILTER_BCJ_ARM64","FILTER_LZMA2","readByte","buf","offset","Buffer","isBuffer","readUInt32LE","length","readUInt32LEAt","bufferEquals","expected","i","decodeMultibyte","value","byte","Error","bytesRead","applyFilter","data","filter","id","decodeBcj","props","decodeBcjArm","decodeBcjArm64","decodeBcjArmt","decodeBcjPpc","decodeBcjSparc","decodeBcjIa64","decodeDelta","toString","parseBlockHeader","input","_checkSize","blockHeaderSizeRaw","blockHeaderSize","blockHeaderStart","blockFlags","numFilters","hasCompressedSize","hasUncompressedSize","result","filters","lzma2Props","filterIdResult","filterId","propsSizeResult","filterProps","slice","push","blockDataStart","headerSize","dataStart","dataEnd","nextOffset","parseIndex","indexStart","checkSize","getByte","decodeMultibyteLocal","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","decodeXZPure","checkSizes","checkType","footerEnd","backwardSizeLE","backwardSize","blockRecords","recordStart","blockInfo","compressedData","blockOutput","decodeLzma2","j","output","BufferList","append","callback","worker","cb","native","fallback","err","tryLoadNative","xz","decompress","promise","then","Promise","resolve","reject","bufferList","Transform","transform","chunk","_encoding","flush","getUInt32LE","equals","blockIndex","pushBlock","headerData"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;CAmBC;;;;;;;;;;;QAsceA;eAAAA;;QApCAC;eAAAA;;;mCAhauC;qBAE7B;wBACG;0BACE;yBACD;yBACA;wBACD;0BACE;uBACH;uBACA;wBACE;AAG9B,iBAAiB;AACjB,IAAMC,WAAW;IAAC;IAAM;IAAM;IAAM;IAAM;IAAM;CAAK;AACrD,IAAMC,kBAAkB;IAAC;IAAM;CAAK,EAAE,OAAO;AAE7C,qCAAqC;AACrC,IAAMC,eAAe;AACrB,IAAMC,iBAAiB;AACvB,IAAMC,iBAAiB;AACvB,IAAMC,kBAAkB;AACxB,IAAMC,iBAAiB;AACvB,IAAMC,kBAAkB;AACxB,IAAMC,mBAAmB;AACzB,IAAMC,mBAAmB;AACzB,IAAMC,eAAe;AAWrB;;CAEC,GACD,SAASC,SAASC,GAAe,EAAEC,MAAc;IAC/C,OAAOC,OAAOC,QAAQ,CAACH,OAAOA,GAAG,CAACC,OAAO,GAAGD,IAAID,QAAQ,CAACE;AAC3D;AAEA;;CAEC,GACD,SAASG,aAAaJ,GAAe,EAAEC,MAAc;IACnD,IAAIC,OAAOC,QAAQ,CAACH,MAAM;QACxB,IAAIC,SAAS,KAAKA,SAAS,IAAID,IAAIK,MAAM,EAAE,OAAO;QAClD,OAAOL,IAAII,YAAY,CAACH;IAC1B;IACA,OAAOD,IAAIM,cAAc,CAACL;AAC5B;AAEA;;;CAGC,GACD,SAASM,aAAaP,GAAe,EAAEC,MAAc,EAAEO,QAAkB;IACvE,IAAIP,SAASO,SAASH,MAAM,GAAGL,IAAIK,MAAM,EAAE;QACzC,OAAO;IACT;IACA,IAAK,IAAII,IAAI,GAAGA,IAAID,SAASH,MAAM,EAAEI,IAAK;QACxC,IAAIV,SAASC,KAAKC,SAASQ,OAAOD,QAAQ,CAACC,EAAE,EAAE;YAC7C,OAAO;QACT;IACF;IACA,OAAO;AACT;AAEA;;;CAGC,GACD,SAASC,gBAAgBV,GAAe,EAAEC,MAAc;IACtD,IAAIU,QAAQ;IACZ,IAAIF,IAAI;IACR,IAAIG;IACJ,GAAG;QACD,IAAIX,SAASQ,KAAKT,IAAIK,MAAM,EAAE;YAC5B,MAAM,IAAIQ,MAAM;QAClB;QACAD,OAAOb,SAASC,KAAKC,SAASQ;QAC9BE,SAAS,AAACC,CAAAA,OAAO,IAAG,KAAOH,IAAI;QAC/BA;QACA,IAAIA,IAAI,GAAG;YACT,MAAM,IAAII,MAAM;QAClB;IACF,QAASD,OAAO,MAAM;IACtB,OAAO;QAAED,OAAAA;QAAOG,WAAWL;IAAE;AAC/B;AAEA;;CAEC,GACD,SAASM,YAAYC,IAAY,EAAEC,MAAkB;IACnD,OAAQA,OAAOC,EAAE;QACf,KAAK3B;YACH,OAAO4B,IAAAA,gBAAS,EAACH,MAAMC,OAAOG,KAAK;QACrC,KAAK1B;YACH,OAAO2B,IAAAA,sBAAY,EAACL,MAAMC,OAAOG,KAAK;QACxC,KAAKvB;YACH,OAAOyB,IAAAA,0BAAc,EAACN,MAAMC,OAAOG,KAAK;QAC1C,KAAKzB;YACH,OAAO4B,IAAAA,wBAAa,EAACP,MAAMC,OAAOG,KAAK;QACzC,KAAK5B;YACH,OAAOgC,IAAAA,sBAAY,EAACR,MAAMC,OAAOG,KAAK;QACxC,KAAKxB;YACH,OAAO6B,IAAAA,0BAAc,EAACT,MAAMC,OAAOG,KAAK;QAC1C,KAAK3B;YACH,OAAOiC,IAAAA,wBAAa,EAACV,MAAMC,OAAOG,KAAK;QACzC,KAAK9B;YACH,OAAOqC,IAAAA,oBAAW,EAACX,MAAMC,OAAOG,KAAK;QACvC;YACE,MAAM,IAAIP,MAAM,AAAC,yBAA+C,OAAvBI,OAAOC,EAAE,CAACU,QAAQ,CAAC;IAChE;AACF;AAEA;;CAEC,GACD,SAASC,iBACPC,KAAa,EACb7B,MAAc,EACd8B,UAAkB;IASlB,oBAAoB;IACpB,IAAMC,qBAAqBF,KAAK,CAAC7B,OAAO;IACxC,IAAI+B,uBAAuB,GAAG;QAC5B,MAAM,IAAInB,MAAM;IAClB;IACA,IAAMoB,kBAAkB,AAACD,CAAAA,qBAAqB,CAAA,IAAK;IAEnD,qBAAqB;IACrB,IAAME,mBAAmBjC;IACzBA,UAAU,iBAAiB;IAE3B,IAAMkC,aAAaL,KAAK,CAAC7B,SAAS;IAClC,IAAMmC,aAAa,AAACD,CAAAA,aAAa,IAAG,IAAK;IACzC,IAAME,oBAAoB,AAACF,CAAAA,aAAa,IAAG,MAAO;IAClD,IAAMG,sBAAsB,AAACH,CAAAA,aAAa,IAAG,MAAO;IAEpD,sBAAsB;IACtB,IAAIE,mBAAmB;QACrB,IAAME,SAAS7B,gBAAgBoB,OAAO7B;QACtCA,UAAUsC,OAAOzB,SAAS;IAC5B;IAEA,IAAIwB,qBAAqB;QACvB,IAAMC,UAAS7B,gBAAgBoB,OAAO7B;QACtCA,UAAUsC,QAAOzB,SAAS;IAC5B;IAEA,oBAAoB;IACpB,IAAM0B,UAAwB,EAAE;IAChC,IAAIC,aAA4B;IAEhC,IAAK,IAAIhC,IAAI,GAAGA,IAAI2B,YAAY3B,IAAK;QACnC,IAAMiC,iBAAiBhC,gBAAgBoB,OAAO7B;QAC9C,IAAM0C,WAAWD,eAAe/B,KAAK;QACrCV,UAAUyC,eAAe5B,SAAS;QAElC,IAAM8B,kBAAkBlC,gBAAgBoB,OAAO7B;QAC/CA,UAAU2C,gBAAgB9B,SAAS;QAEnC,IAAM+B,cAAcf,MAAMgB,KAAK,CAAC7C,QAAQA,SAAS2C,gBAAgBjC,KAAK;QACtEV,UAAU2C,gBAAgBjC,KAAK;QAE/B,IAAIgC,aAAa7C,cAAc;YAC7B,gCAAgC;YAChC2C,aAAaI;QACf,OAAO,IAAIF,aAAarD,gBAAiBqD,YAAYpD,kBAAkBoD,YAAY9C,kBAAmB;YACpG,qDAAqD;YACrD2C,QAAQO,IAAI,CAAC;gBAAE7B,IAAIyB;gBAAUvB,OAAOyB;YAAY;QAClD,OAAO;YACL,MAAM,IAAIhC,MAAM,AAAC,yBAA8C,OAAtB8B,SAASf,QAAQ,CAAC;QAC7D;IACF;IAEA,IAAI,CAACa,YAAY;QACf,MAAM,IAAI5B,MAAM;IAClB;IAEA,2DAA2D;IAC3D,IAAMmC,iBAAiBd,mBAAmBD;IAE1C,OAAO;QACLO,SAAAA;QACAC,YAAAA;QACAQ,YAAYhB;QACZiB,WAAWF;QACXG,SAASrB,MAAMzB,MAAM;QACrB+C,YAAYJ;IACd;AACF;AAEA;;;CAGC,GACD,SAASK,WACPvB,KAAiB,EACjBwB,UAAkB,EAClBC,SAAiB;IAMjB,8EAA8E;IAC9E,IAAMC,UAAUtD,OAAOC,QAAQ,CAAC2B,SAAS,SAAC7B;eAAmB6B,KAAK,CAAC7B,OAAO;QAAG,SAACA;eAAmB6B,MAAM/B,QAAQ,CAACE;;IAEhH,8CAA8C;IAC9C,IAAMwD,uBAAuB,SAACxD;QAC5B,IAAIU,QAAQ;QACZ,IAAIF,IAAI;QACR,IAAIG;QACJ,GAAG;YACD,IAAIX,SAASQ,KAAKqB,MAAMzB,MAAM,EAAE;gBAC9B,MAAM,IAAIQ,MAAM;YAClB;YACAD,OAAO4C,QAAQvD,SAASQ;YACxBE,SAAS,AAACC,CAAAA,OAAO,IAAG,KAAOH,IAAI;YAC/BA;YACA,IAAIA,IAAI,GAAG;gBACT,MAAM,IAAII,MAAM;YAClB;QACF,QAASD,OAAO,MAAM;QACtB,OAAO;YAAED,OAAAA;YAAOG,WAAWL;QAAE;IAC/B;IAEA,IAAIR,SAASqD;IAEb,yBAAyB;IACzB,IAAIE,QAAQvD,YAAY,MAAM;QAC5B,MAAM,IAAIY,MAAM;IAClB;IACAZ;IAEA,oBAAoB;IACpB,IAAMyD,cAAcD,qBAAqBxD;IACzC,IAAM0D,cAAcD,YAAY/C,KAAK;IACrCV,UAAUyD,YAAY5C,SAAS;IAE/B,IAAM8C,UAKD,EAAE;IAEP,oBAAoB;IACpB,IAAK,IAAInD,IAAI,GAAGA,IAAIkD,aAAalD,IAAK;QACpC,mDAAmD;QACnD,IAAMoD,iBAAiBJ,qBAAqBxD;QAC5CA,UAAU4D,eAAe/C,SAAS;QAElC,oBAAoB;QACpB,IAAMgD,qBAAqBL,qBAAqBxD;QAChDA,UAAU6D,mBAAmBhD,SAAS;QAEtC8C,QAAQb,IAAI,CAAC;YACXgB,eAAe;YACfC,cAAcH,eAAelD,KAAK;YAClCsD,oBAAoB;YACpBC,kBAAkBJ,mBAAmBnD,KAAK;QAC5C;IACF;IAEA,uDAAuD;IACvD,IAAIwD,aAAa,IAAI,sBAAsB;IAC3C,IAAK,IAAI1D,KAAI,GAAGA,KAAImD,QAAQvD,MAAM,EAAEI,KAAK;QACvC,IAAM2D,SAASR,OAAO,CAACnD,GAAE;QACzB,0CAA0C;QAC1C2D,OAAOL,aAAa,GAAGI;QAEvB,6CAA6C;QAC7C,IAAME,gBAAgBb,QAAQW;QAC9B,IAAMlB,aAAa,AAACoB,CAAAA,gBAAgB,CAAA,IAAK;QAEzC,oDAAoD;QACpDD,OAAOH,kBAAkB,GAAGG,OAAOJ,YAAY,GAAGf,aAAaM;QAE/D,gEAAgE;QAChE,IAAMe,aAAaC,KAAKC,IAAI,CAACJ,OAAOJ,YAAY,GAAG,KAAK;QACxDG,cAAcG;IAChB;IAEA,OAAOV;AACT;AAEA;;;CAGC,GACD,SAASa,aAAa3C,KAAa;QAgBf4C;IAflB,kBAAkB;IAClB,IAAI5C,MAAMzB,MAAM,GAAG,MAAM,CAACE,aAAauB,OAAO,GAAG1C,WAAW;QAC1D,MAAM,IAAIyB,MAAM;IAClB;IAEA,6BAA6B;IAC7B,IAAM8D,YAAY5E,SAAS+B,OAAO,KAAK;IAEvC,kCAAkC;IAClC,IAAM4C,aAAwC;QAC5C,GAAG;QACH,GAAG;QACH,GAAG;QACH,IAAI;IACN;IACA,IAAMnB,aAAYmB,wBAAAA,UAAU,CAACC,UAAU,cAArBD,mCAAAA,wBAAyB;IAE3C,2EAA2E;IAC3E,6CAA6C;IAC7C,IAAIE,YAAY9C,MAAMzB,MAAM;IAC5B,MAAOuE,YAAY,MAAM7E,SAAS+B,OAAO8C,YAAY,OAAO,KAAM;QAChEA;IACF;IACA,kDAAkD;IAClD,MAAOA,YAAY,MAAM,KAAKA,YAAY,GAAI;QAC5CA;IACF;IAEA,yCAAyC;IACzC,IAAI,CAACrE,aAAauB,OAAO8C,YAAY,GAAGvF,kBAAkB;QACxD,MAAM,IAAIwB,MAAM;IAClB;IAEA,qEAAqE;IACrE,IAAMgE,iBAAiBzE,aAAa0B,OAAO8C,YAAY;IACvD,IAAIC,mBAAmB,MAAM;QAC3B,MAAM,IAAIhE,MAAM;IAClB;IACA,IAAMiE,eAAe,AAACD,CAAAA,iBAAiB,CAAA,IAAK;IAC5C,IAAMvB,aAAasB,YAAY,KAAKE;IAEpC,uCAAuC;IACvC,IAAMC,eAAe1B,WAAWvB,OAAOwB,YAAYC;IAEnD,iFAAiF;IACjF,uCAAuC;IACvC,IAAIwB,aAAa1E,MAAM,KAAK,GAAG;QAC7B,IAAM+D,SAASW,YAAY,CAAC,EAAE;QAC9B,IAAMC,cAAcZ,OAAOL,aAAa;QACxC,IAAMkB,YAAYpD,iBAAiBC,OAAOkD,aAAazB;QACvD,IAAML,YAAY8B,cAAcC,UAAUhC,UAAU;QACpD,IAAME,UAAUD,YAAYkB,OAAOH,kBAAkB;QACrD,IAAMiB,iBAAiBpD,MAAMgB,KAAK,CAACI,WAAWC;QAE9C,IAAIgC,cAAcC,IAAAA,oBAAW,EAACF,gBAAgBD,UAAUxC,UAAU,EAAE2B,OAAOF,gBAAgB;QAE3F,IAAK,IAAImB,IAAIJ,UAAUzC,OAAO,CAACnC,MAAM,GAAG,GAAGgF,KAAK,GAAGA,IAAK;YACtDF,cAAcpE,YAAYoE,aAAaF,UAAUzC,OAAO,CAAC6C,EAAE;QAC7D;QAEA,OAAOF;IACT;IAEA,mEAAmE;IACnE,IAAMG,SAAS,IAAIC,+BAAU;IAE7B,IAAK,IAAI9E,IAAI,GAAGA,IAAIsE,aAAa1E,MAAM,EAAEI,IAAK;QAC5C,IAAM2D,UAASW,YAAY,CAACtE,EAAE;QAC9B,IAAMuE,eAAcZ,QAAOL,aAAa;QAExC,qBAAqB;QACrB,IAAMkB,aAAYpD,iBAAiBC,OAAOkD,cAAazB;QAEvD,yCAAyC;QACzC,IAAML,aAAY8B,eAAcC,WAAUhC,UAAU;QACpD,IAAME,WAAUD,aAAYkB,QAAOH,kBAAkB;QAErD,0EAA0E;QAC1E,yEAAyE;QACzE,oEAAoE;QACpE,IAAMiB,kBAAiBpD,MAAMgB,KAAK,CAACI,YAAWC;QAE9C,6DAA6D;QAC7D,IAAIgC,eAAcC,IAAAA,oBAAW,EAACF,iBAAgBD,WAAUxC,UAAU,EAAE2B,QAAOF,gBAAgB;QAE3F,+EAA+E;QAC/E,oEAAoE;QACpE,0CAA0C;QAC1C,IAAK,IAAImB,KAAIJ,WAAUzC,OAAO,CAACnC,MAAM,GAAG,GAAGgF,MAAK,GAAGA,KAAK;YACtDF,eAAcpE,YAAYoE,cAAaF,WAAUzC,OAAO,CAAC6C,GAAE;QAC7D;QAEA,6BAA6B;QAC7BC,OAAOE,MAAM,CAACL;IAChB;IAEA,OAAOG;AACT;AAcO,SAASnG,SAAS2C,KAAa,EAAE2D,QAA2B;IACjE,IAAMC,SAAS,SAACC;YAUVC;QATJ,IAAMC,WAAW;YACf,IAAI;gBACFF,GAAG,MAAMlB,aAAa3C;YACxB,EAAE,OAAOgE,KAAK;gBACZH,GAAGG;YACL;QACF;QAEA,IAAMF,SAASG,IAAAA,uBAAa;QAC5B,IAAIH,mBAAAA,8BAAAA,aAAAA,OAAQI,EAAE,cAAVJ,iCAAAA,WAAYK,UAAU,EAAE;YAC1B,IAAI;gBACF,IAAMC,UAAUN,OAAOI,EAAE,CAACC,UAAU,CAACnE;gBACrC,IAAIoE,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,SAACxF;+BAAUgF,GAAG,MAAMhF;uBAAsBkF;oBACvD;gBACF;YACF,EAAE,eAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOJ,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIW,QAAQ,SAACC,SAASC;eAAWZ,OAAO,SAACI,KAAKnF;mBAAWmF,MAAMQ,OAAOR,OAAOO,QAAQ1F;;;AAC9F;AASO,SAASzB;IACd,IAAMqH,aAAa,IAAIhB,+BAAU;IAEjC,OAAO,IAAIiB,8BAAS,CAAC;QACnBC,WAAAA,SAAAA,UAAUC,KAAa,EAAEC,SAAiB,EAAElB,QAAwC;YAClFc,WAAWf,MAAM,CAACkB;YAClBjB;QACF;QAEAmB,OAAAA,SAAAA,MAAMnB,QAAwC;;gBAgC1Bf;YA/BlB,IAAM5C,QAAoByE;YAE1B,8EAA8E;YAC9E,IAAM/C,UAAUtD,OAAOC,QAAQ,CAAC2B,SAAS,SAAC7B;uBAAmB6B,KAAK,CAAC7B,OAAO;gBAAG,SAACA;uBAAmB6B,MAAM/B,QAAQ,CAACE;;YAEhH,IAAM4G,cAAc3G,OAAOC,QAAQ,CAAC2B,SAAS,SAAC7B;uBAAoBA,SAAS,KAAKA,SAAS,IAAI6B,MAAMzB,MAAM,GAAG,OAAOyB,MAAM1B,YAAY,CAACH;gBAAW,SAACA;uBAAmB6B,MAAMxB,cAAc,CAACL;;YAE1L,IAAM6G,SAAS,SAAC7G,QAAgBO;gBAC9B,IAAIP,SAASO,SAASH,MAAM,GAAGyB,MAAMzB,MAAM,EAAE,OAAO;gBACpD,IAAK,IAAII,IAAI,GAAGA,IAAID,SAASH,MAAM,EAAEI,IAAK;oBACxC,IAAI+C,QAAQvD,SAASQ,OAAOD,QAAQ,CAACC,EAAE,EAAE,OAAO;gBAClD;gBACA,OAAO;YACT;YAEA,2CAA2C;YAC3C,IAAIqB,MAAMzB,MAAM,GAAG,MAAM,CAACyG,OAAO,GAAG1H,WAAW;gBAC7CqG,SAAS,IAAI5E,MAAM;gBACnB;YACF;YAEA,6BAA6B;YAC7B,IAAM8D,YAAYnB,QAAQ,KAAK;YAE/B,kCAAkC;YAClC,IAAMkB,aAAwC;gBAC5C,GAAG;gBACH,GAAG;gBACH,GAAG;gBACH,IAAI;YACN;YACA,IAAMnB,aAAYmB,wBAAAA,UAAU,CAACC,UAAU,cAArBD,mCAAAA,wBAAyB;YAE3C,2EAA2E;YAC3E,IAAIE,YAAY9C,MAAMzB,MAAM;YAC5B,MAAOuE,YAAY,MAAMpB,QAAQoB,YAAY,OAAO,KAAM;gBACxDA;YACF;YACA,2BAA2B;YAC3B,MAAOA,YAAY,MAAM,KAAKA,YAAY,GAAI;gBAC5CA;YACF;YAEA,yCAAyC;YACzC,IAAI,CAACkC,OAAOlC,YAAY,GAAGvF,kBAAkB;gBAC3CoG,SAAS,IAAI5E,MAAM;gBACnB;YACF;YAEA,uCAAuC;YACvC,IAAMgE,iBAAiBgC,YAAYjC,YAAY;YAC/C,IAAIC,mBAAmB,MAAM;gBAC3BY,SAAS,IAAI5E,MAAM;gBACnB;YACF;YACA,IAAMiE,eAAe,AAACD,CAAAA,iBAAiB,CAAA,IAAK;YAC5C,IAAMvB,aAAasB,YAAY,KAAKE;YAEpC,uCAAuC;YACvC,IAAMC,eAAe1B,WAAWvB,OAAOwB,YAAYC;YAEnD,mEAAmE;YACnE,IAAIwD,aAAa;YACjB,IAAMC,YAAY,SAAClB;gBACjB,IAAIA,KAAK;oBACPL,SAASK;oBACT;gBACF;gBAEA,IAAIiB,cAAchC,aAAa1E,MAAM,EAAE;oBACrC,uBAAuB;oBACvBoF,SAAS;oBACT;gBACF;gBAEA,IAAMrB,SAASW,YAAY,CAACgC,aAAa;gBACzC,IAAM/B,cAAcZ,OAAOL,aAAa;gBAExC,oDAAoD;gBACpD,8BAA8B;gBAC9B,IAAMM,gBAAgBb,QAAQwB;gBAC9B,IAAM/B,aAAa,AAACoB,CAAAA,gBAAgB,CAAA,IAAK;gBAEzC,wCAAwC;gBACxC,IAAM4C,aAAanF,MAAMgB,KAAK,CAACkC,aAAaA,cAAc/B;gBAC1D,IAAMgC,YAAYpD,iBAAiBoF,YAAY,GAAG1D;gBAElD,yCAAyC;gBACzC,IAAML,YAAY8B,cAAc/B;gBAChC,IAAME,UAAUD,YAAYkB,OAAOH,kBAAkB;gBACrD,IAAMiB,iBAAiBpD,MAAMgB,KAAK,CAACI,WAAWC;gBAE9C,wBAAwB;gBACxB,IAAIgC,cAAcC,IAAAA,oBAAW,EAACF,gBAAgBD,UAAUxC,UAAU,EAAE2B,OAAOF,gBAAgB;gBAE3F,+CAA+C;gBAC/C,IAAK,IAAImB,IAAIJ,UAAUzC,OAAO,CAACnC,MAAM,GAAG,GAAGgF,KAAK,GAAGA,IAAK;oBACtDF,cAAcpE,YAAYoE,aAAaF,UAAUzC,OAAO,CAAC6C,EAAE;gBAC7D;gBAEA,gDAAgD;gBAChD,MAAKtC,IAAI,CAACoC;gBAEV,2BAA2B;gBAC3B6B,UAAU;YACZ;YAEA,0BAA0B;YAC1BA,UAAU;QACZ;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/iterators/xz-compat/src/xz/Decoder.ts"],"sourcesContent":["/**\n * XZ Decompression Module\n *\n * XZ is a container format that wraps LZMA2 compressed data.\n * This module provides both synchronous and streaming XZ decoders.\n *\n * Pure JavaScript implementation, works on Node.js 0.8+\n *\n * IMPORTANT: Buffer Management Pattern\n *\n * When calling decodeLzma2(), use the direct return pattern:\n *\n * ✅ CORRECT - Fast path:\n * const output = decodeLzma2(data, props, size) as Buffer;\n *\n * ❌ WRONG - Slow path (do NOT buffer):\n * const chunks: Buffer[] = [];\n * decodeLzma2(data, props, size, { write: c => chunks.push(c) });\n * return Buffer.concat(chunks); // ← Unnecessary copies!\n */\n\nimport { type BufferLike, BufferList, Transform } from 'extract-base-iterator';\nimport type { Transform as TransformType } from 'stream';\nimport { decodeBcj } from '../filters/bcj/Bcj.ts';\nimport { decodeBcjArm } from '../filters/bcj/BcjArm.ts';\nimport { decodeBcjArm64 } from '../filters/bcj/BcjArm64.ts';\nimport { decodeBcjArmt } from '../filters/bcj/BcjArmt.ts';\nimport { decodeBcjIa64 } from '../filters/bcj/BcjIa64.ts';\nimport { decodeBcjPpc } from '../filters/bcj/BcjPpc.ts';\nimport { decodeBcjSparc } from '../filters/bcj/BcjSparc.ts';\nimport { decodeDelta } from '../filters/delta/Delta.ts';\nimport { decodeLzma2 } from '../lzma/index.ts';\nimport { tryLoadNative } from '../native.ts';\nimport type { DecodeCallback } from '../sevenz.ts';\n\n// XZ magic bytes\nconst XZ_MAGIC = [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00];\nconst XZ_FOOTER_MAGIC = [0x59, 0x5a]; // \"YZ\"\n\n// Filter IDs (from XZ specification)\nconst FILTER_DELTA = 0x03;\nconst FILTER_BCJ_X86 = 0x04;\nconst FILTER_BCJ_PPC = 0x05;\nconst FILTER_BCJ_IA64 = 0x06;\nconst FILTER_BCJ_ARM = 0x07;\nconst FILTER_BCJ_ARMT = 0x08;\nconst FILTER_BCJ_SPARC = 0x09;\nconst FILTER_BCJ_ARM64 = 0x0a;\nconst FILTER_LZMA2 = 0x21;\n\n// Filter info for parsing\ninterface FilterInfo {\n id: number;\n props: Buffer;\n}\n\n// Re-export BufferLike for public API\nexport type { BufferLike } from 'extract-base-iterator';\n\n/**\n * Read a byte from Buffer or BufferList\n */\nfunction readByte(buf: BufferLike, offset: number): number {\n return Buffer.isBuffer(buf) ? buf[offset] : buf.readByte(offset);\n}\n\n/**\n * Read UInt32LE from Buffer or BufferList (returns null if out of bounds)\n */\nfunction readUInt32LE(buf: BufferLike, offset: number): number | null {\n if (Buffer.isBuffer(buf)) {\n if (offset < 0 || offset + 4 > buf.length) return null;\n return buf.readUInt32LE(offset);\n }\n return buf.readUInt32LEAt(offset);\n}\n\n/**\n * Compare buffer contents at offset with expected byte sequence\n * Works with both Buffer and BufferList\n */\nfunction bufferEquals(buf: BufferLike, offset: number, expected: number[]): boolean {\n if (offset + expected.length > buf.length) {\n return false;\n }\n for (let i = 0; i < expected.length; i++) {\n if (readByte(buf, offset + i) !== expected[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Decode variable-length integer (XZ multibyte encoding)\n * Works with both Buffer and BufferList\n */\nfunction decodeMultibyte(buf: BufferLike, offset: number): { value: number; bytesRead: number } {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= buf.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = readByte(buf, offset + i);\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n}\n\n/**\n * Apply a preprocessing filter (BCJ/Delta) to decompressed data\n */\nfunction applyFilter(data: Buffer, filter: FilterInfo): Buffer {\n switch (filter.id) {\n case FILTER_BCJ_X86:\n return decodeBcj(data, filter.props);\n case FILTER_BCJ_ARM:\n return decodeBcjArm(data, filter.props);\n case FILTER_BCJ_ARM64:\n return decodeBcjArm64(data, filter.props);\n case FILTER_BCJ_ARMT:\n return decodeBcjArmt(data, filter.props);\n case FILTER_BCJ_PPC:\n return decodeBcjPpc(data, filter.props);\n case FILTER_BCJ_SPARC:\n return decodeBcjSparc(data, filter.props);\n case FILTER_BCJ_IA64:\n return decodeBcjIa64(data, filter.props);\n case FILTER_DELTA:\n return decodeDelta(data, filter.props);\n default:\n throw new Error(`Unsupported filter: 0x${filter.id.toString(16)}`);\n }\n}\n\n/**\n * Parse XZ Block Header to extract filters and LZMA2 properties\n */\nfunction parseBlockHeader(\n input: Buffer,\n offset: number,\n _checkSize: number\n): {\n filters: FilterInfo[];\n lzma2Props: Buffer;\n headerSize: number;\n dataStart: number;\n dataEnd: number;\n nextOffset: number;\n} {\n // Block header size\n const blockHeaderSizeRaw = input[offset];\n if (blockHeaderSizeRaw === 0) {\n throw new Error('Invalid block header size (index indicator found instead of block)');\n }\n const blockHeaderSize = (blockHeaderSizeRaw + 1) * 4;\n\n // Parse block header\n const blockHeaderStart = offset;\n offset++; // skip size byte\n\n const blockFlags = input[offset++];\n const numFilters = (blockFlags & 0x03) + 1;\n const hasCompressedSize = (blockFlags & 0x40) !== 0;\n const hasUncompressedSize = (blockFlags & 0x80) !== 0;\n\n // Skip optional sizes\n if (hasCompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n if (hasUncompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n // Parse all filters\n const filters: FilterInfo[] = [];\n let lzma2Props: Buffer | null = null;\n\n for (let i = 0; i < numFilters; i++) {\n const filterIdResult = decodeMultibyte(input, offset);\n const filterId = filterIdResult.value;\n offset += filterIdResult.bytesRead;\n\n const propsSizeResult = decodeMultibyte(input, offset);\n offset += propsSizeResult.bytesRead;\n\n const filterProps = input.slice(offset, offset + propsSizeResult.value);\n offset += propsSizeResult.value;\n\n if (filterId === FILTER_LZMA2) {\n // LZMA2 must be the last filter\n lzma2Props = filterProps;\n } else if (filterId === FILTER_DELTA || (filterId >= FILTER_BCJ_X86 && filterId <= FILTER_BCJ_ARM64)) {\n // Preprocessing filter - store for later application\n filters.push({ id: filterId, props: filterProps });\n } else {\n throw new Error(`Unsupported filter: 0x${filterId.toString(16)}`);\n }\n }\n\n if (!lzma2Props) {\n throw new Error('No LZMA2 filter found in XZ block');\n }\n\n // Skip to end of block header (must be aligned to 4 bytes)\n const blockDataStart = blockHeaderStart + blockHeaderSize;\n\n return {\n filters,\n lzma2Props,\n headerSize: blockHeaderSize,\n dataStart: blockDataStart,\n dataEnd: input.length,\n nextOffset: blockDataStart,\n };\n}\n\n/**\n * Parse XZ Index to get block positions\n * Works with both Buffer and BufferList\n */\nfunction parseIndex(\n input: BufferLike,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n // One-time binding for buffer access (avoids repeated Buffer.isBuffer checks)\n const getByte = Buffer.isBuffer(input) ? (offset: number) => input[offset] : (offset: number) => input.readByte(offset);\n\n // Local multibyte decoder using bound getByte\n const decodeMultibyteLocal = (offset: number): { value: number; bytesRead: number } => {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= input.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = getByte(offset + i);\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n };\n\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (getByte(offset) !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyteLocal(offset);\n const recordCount = countResult.value;\n offset += countResult.bytesRead;\n\n const records: Array<{\n compressedPos: number;\n unpaddedSize: number;\n compressedDataSize: number;\n uncompressedSize: number;\n }> = [];\n\n // Parse each record\n for (let i = 0; i < recordCount; i++) {\n // Unpadded Size (header + compressed data + check)\n const unpaddedResult = decodeMultibyteLocal(offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyteLocal(offset);\n offset += uncompressedResult.bytesRead;\n\n records.push({\n compressedPos: 0, // will be calculated\n unpaddedSize: unpaddedResult.value,\n compressedDataSize: 0, // will be calculated\n uncompressedSize: uncompressedResult.value,\n });\n }\n\n // Calculate actual positions by walking through blocks\n let currentPos = 12; // After stream header\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n // Record where this block's header starts\n record.compressedPos = currentPos;\n\n // Get block header size from the actual data\n const headerSizeRaw = getByte(currentPos);\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n record.compressedDataSize = record.unpaddedSize - headerSize - checkSize;\n\n // Move to next block: unpaddedSize + padding to 4-byte boundary\n const paddedSize = Math.ceil(record.unpaddedSize / 4) * 4;\n currentPos += paddedSize;\n }\n\n return records;\n}\n\n/**\n * Pure JS XZ decompression (handles all XZ spec features)\n * Returns BufferList for memory efficiency with large files.\n */\nfunction decodeXZPure(input: Buffer): Buffer | BufferList {\n // Verify XZ magic\n if (input.length < 12 || !bufferEquals(input, 0, XZ_MAGIC)) {\n throw new Error('Invalid XZ magic bytes');\n }\n\n // Stream flags at offset 6-7\n const checkType = readByte(input, 7) & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n // Stream padding must be multiple of 4 bytes\n let footerEnd = input.length;\n while (footerEnd > 12 && readByte(input, footerEnd - 1) === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary (stream padding rules)\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {\n throw new Error('Invalid XZ footer magic');\n }\n\n // Get backward size (tells us where index starts) - at footerEnd - 8\n const backwardSizeLE = readUInt32LE(input, footerEnd - 8);\n if (backwardSizeLE === null) {\n throw new Error('Invalid backward size');\n }\n const backwardSize = (backwardSizeLE + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Calculate total uncompressed size for multi-block decision\n let totalUncompressedSize = 0;\n for (let i = 0; i < blockRecords.length; i++) {\n totalUncompressedSize += blockRecords[i].uncompressedSize;\n }\n\n // Small multi-block files: use Buffer.concat directly (avoids BufferList overhead)\n // Threshold of 64KB: below this, the overhead of linked list nodes isn't worth it\n const BUFFERLIST_THRESHOLD = 64 * 1024; // 64KB\n\n // Single block OR small multi-block: return Buffer directly\n if (blockRecords.length === 1 || totalUncompressedSize < BUFFERLIST_THRESHOLD) {\n const record = blockRecords[0];\n const recordStart = record.compressedPos;\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n const dataStart = recordStart + blockInfo.headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n const compressedData = input.slice(dataStart, dataEnd);\n\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n return blockOutput;\n }\n\n // Multi-block (large): use BufferList to avoid large contiguous allocation\n const output = new BufferList();\n\n for (let i = 0; i < blockRecords.length; i++) {\n const record = blockRecords[i];\n const recordStart = record.compressedPos;\n\n // Parse block header\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + blockInfo.headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n\n // Note: XZ blocks have padding AFTER the check field to align to 4 bytes,\n // but the compressedSize from index is exact - no need to strip padding.\n // LZMA2 data includes a 0x00 end marker which must NOT be stripped.\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block with LZMA2 (fast path, no buffering)\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n // Apply preprocessing filters in reverse order (BCJ/Delta applied after LZMA2)\n // Filters are stored in order they were applied during compression,\n // so we need to reverse for decompression\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n // Append block to BufferList\n output.append(blockOutput);\n }\n\n return output;\n}\n\n/** Callback invoked when an async decode completes */\nexport type XzDecodeCallback = DecodeCallback<BufferLike>;\n\n/**\n * Decompress XZ data. With a callback the result is provided asynchronously;\n * otherwise a Promise resolves with the decoded data.\n *\n * Returns Buffer for single-block files (most small files).\n * Returns BufferList for multi-block files (avoids large contiguous allocation).\n */\nexport function decodeXZ(input: Buffer, callback: XzDecodeCallback): void;\nexport function decodeXZ(input: Buffer): Promise<BufferLike>;\nexport function decodeXZ(input: Buffer, callback?: XzDecodeCallback): Promise<BufferLike> | void {\n const worker = (cb: XzDecodeCallback) => {\n const fallback = () => {\n try {\n cb(null, decodeXZPure(input));\n } catch (err) {\n cb(err as Error);\n }\n };\n\n const native = tryLoadNative();\n if (native?.xz?.decompress) {\n try {\n const promise = native.xz.decompress(input);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value as BufferLike), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as BufferLike))));\n}\n\n// Callback-based LZMA2 decoder type (for Node 0.8+ compatibility - no promises)\ntype Lzma2DecodeCallback = (err: Error | null, result?: Buffer) => void;\ntype Lzma2Decoder = (data: Buffer, props: Buffer, size: number, callback: Lzma2DecodeCallback) => void;\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n *\n * Uses native lzma-native bindings when available for better performance.\n * Falls back to pure JS implementation on older Node versions or when native is unavailable.\n */\nexport function createXZDecoder(): TransformType {\n const bufferList = new BufferList();\n // Cache native module lookup (only done once)\n const native = tryLoadNative();\n\n // Choose decoder: native (async via callback) or pure JS (sync wrapped in callback)\n const decodeLzma2Block: Lzma2Decoder = native?.lzma2\n ? (data, props, size, cb) => {\n native.lzma2?.(data, props, size).then(\n (result) => cb(null, result),\n (err) => cb(err)\n );\n }\n : (data, props, size, cb) => {\n try {\n cb(null, decodeLzma2(data, props, size) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n };\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n bufferList.append(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n const input: BufferLike = bufferList;\n\n // One-time binding for buffer access (avoids repeated Buffer.isBuffer checks)\n const getByte = Buffer.isBuffer(input) ? (offset: number) => input[offset] : (offset: number) => input.readByte(offset);\n\n const getUInt32LE = Buffer.isBuffer(input) ? (offset: number) => (offset < 0 || offset + 4 > input.length ? null : input.readUInt32LE(offset)) : (offset: number) => input.readUInt32LEAt(offset);\n\n const equals = (offset: number, expected: number[]): boolean => {\n if (offset + expected.length > input.length) return false;\n for (let i = 0; i < expected.length; i++) {\n if (getByte(offset + i) !== expected[i]) return false;\n }\n return true;\n };\n\n // Verify XZ magic (need at least 12 bytes)\n if (input.length < 12 || !equals(0, XZ_MAGIC)) {\n callback(new Error('Invalid XZ magic bytes'));\n return;\n }\n\n // Stream flags at offset 6-7\n const checkType = getByte(7) & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n let footerEnd = input.length;\n while (footerEnd > 12 && getByte(footerEnd - 1) === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!equals(footerEnd - 2, XZ_FOOTER_MAGIC)) {\n callback(new Error('Invalid XZ footer magic'));\n return;\n }\n\n // Get backward size (at footerEnd - 8)\n const backwardSizeLE = getUInt32LE(footerEnd - 8);\n if (backwardSizeLE === null) {\n callback(new Error('Invalid backward size'));\n return;\n }\n const backwardSize = (backwardSizeLE + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Decompress blocks sequentially (native is async)\n let blockIndex = 0;\n const pushBlock = (err: Error | null) => {\n if (err) {\n callback(err);\n return;\n }\n\n if (blockIndex >= blockRecords.length) {\n // All blocks processed - purge input BufferList to free memory\n if (!Buffer.isBuffer(input)) input.clear();\n callback(null);\n return;\n }\n\n const record = blockRecords[blockIndex++];\n const recordStart = record.compressedPos;\n\n // Parse block header (need to get the header bytes)\n // Read header size byte first\n const headerSizeRaw = getByte(recordStart);\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Read the full header to parse filters\n const headerData = input.slice(recordStart, recordStart + headerSize);\n const blockInfo = parseBlockHeader(headerData, 0, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block (native or pure JS, callback-based)\n decodeLzma2Block(compressedData, blockInfo.lzma2Props, record.uncompressedSize, (decodeErr, blockOutput) => {\n if (decodeErr || !blockOutput) {\n pushBlock(decodeErr || new Error('Decode returned no data'));\n return;\n }\n\n // Apply preprocessing filters in reverse order\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n // Push the block output immediately (streaming)\n this.push(blockOutput);\n\n // Continue with next block\n pushBlock(null);\n });\n };\n\n // Start processing blocks\n pushBlock(null);\n },\n });\n}\n"],"names":["createXZDecoder","decodeXZ","XZ_MAGIC","XZ_FOOTER_MAGIC","FILTER_DELTA","FILTER_BCJ_X86","FILTER_BCJ_PPC","FILTER_BCJ_IA64","FILTER_BCJ_ARM","FILTER_BCJ_ARMT","FILTER_BCJ_SPARC","FILTER_BCJ_ARM64","FILTER_LZMA2","readByte","buf","offset","Buffer","isBuffer","readUInt32LE","length","readUInt32LEAt","bufferEquals","expected","i","decodeMultibyte","value","byte","Error","bytesRead","applyFilter","data","filter","id","decodeBcj","props","decodeBcjArm","decodeBcjArm64","decodeBcjArmt","decodeBcjPpc","decodeBcjSparc","decodeBcjIa64","decodeDelta","toString","parseBlockHeader","input","_checkSize","blockHeaderSizeRaw","blockHeaderSize","blockHeaderStart","blockFlags","numFilters","hasCompressedSize","hasUncompressedSize","result","filters","lzma2Props","filterIdResult","filterId","propsSizeResult","filterProps","slice","push","blockDataStart","headerSize","dataStart","dataEnd","nextOffset","parseIndex","indexStart","checkSize","getByte","decodeMultibyteLocal","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","decodeXZPure","checkSizes","checkType","footerEnd","backwardSizeLE","backwardSize","blockRecords","totalUncompressedSize","BUFFERLIST_THRESHOLD","recordStart","blockInfo","compressedData","blockOutput","decodeLzma2","j","output","BufferList","append","callback","worker","cb","native","fallback","err","tryLoadNative","xz","decompress","promise","then","Promise","resolve","reject","bufferList","decodeLzma2Block","lzma2","size","Transform","transform","chunk","_encoding","flush","getUInt32LE","equals","blockIndex","pushBlock","clear","headerData","decodeErr"],"mappings":"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"}
|
package/dist/esm/xz/Decoder.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare function decodeXZ(input: Buffer): Promise<BufferLike>;
|
|
|
37
37
|
* Create an XZ decompression Transform stream
|
|
38
38
|
* @returns Transform stream that decompresses XZ data
|
|
39
39
|
*
|
|
40
|
-
* Uses
|
|
41
|
-
*
|
|
40
|
+
* Uses native lzma-native bindings when available for better performance.
|
|
41
|
+
* Falls back to pure JS implementation on older Node versions or when native is unavailable.
|
|
42
42
|
*/
|
|
43
43
|
export declare function createXZDecoder(): TransformType;
|
package/dist/esm/xz/Decoder.js
CHANGED
|
@@ -301,9 +301,16 @@ const FILTER_LZMA2 = 0x21;
|
|
|
301
301
|
const indexStart = footerEnd - 12 - backwardSize;
|
|
302
302
|
// Parse Index to get block information
|
|
303
303
|
const blockRecords = parseIndex(input, indexStart, checkSize);
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
|
|
304
|
+
// Calculate total uncompressed size for multi-block decision
|
|
305
|
+
let totalUncompressedSize = 0;
|
|
306
|
+
for(let i = 0; i < blockRecords.length; i++){
|
|
307
|
+
totalUncompressedSize += blockRecords[i].uncompressedSize;
|
|
308
|
+
}
|
|
309
|
+
// Small multi-block files: use Buffer.concat directly (avoids BufferList overhead)
|
|
310
|
+
// Threshold of 64KB: below this, the overhead of linked list nodes isn't worth it
|
|
311
|
+
const BUFFERLIST_THRESHOLD = 64 * 1024; // 64KB
|
|
312
|
+
// Single block OR small multi-block: return Buffer directly
|
|
313
|
+
if (blockRecords.length === 1 || totalUncompressedSize < BUFFERLIST_THRESHOLD) {
|
|
307
314
|
const record = blockRecords[0];
|
|
308
315
|
const recordStart = record.compressedPos;
|
|
309
316
|
const blockInfo = parseBlockHeader(input, recordStart, checkSize);
|
|
@@ -316,7 +323,7 @@ const FILTER_LZMA2 = 0x21;
|
|
|
316
323
|
}
|
|
317
324
|
return blockOutput;
|
|
318
325
|
}
|
|
319
|
-
// Multi-block: use BufferList to avoid large contiguous allocation
|
|
326
|
+
// Multi-block (large): use BufferList to avoid large contiguous allocation
|
|
320
327
|
const output = new BufferList();
|
|
321
328
|
for(let i = 0; i < blockRecords.length; i++){
|
|
322
329
|
const record = blockRecords[i];
|
|
@@ -374,10 +381,23 @@ export function decodeXZ(input, callback) {
|
|
|
374
381
|
* Create an XZ decompression Transform stream
|
|
375
382
|
* @returns Transform stream that decompresses XZ data
|
|
376
383
|
*
|
|
377
|
-
* Uses
|
|
378
|
-
*
|
|
384
|
+
* Uses native lzma-native bindings when available for better performance.
|
|
385
|
+
* Falls back to pure JS implementation on older Node versions or when native is unavailable.
|
|
379
386
|
*/ export function createXZDecoder() {
|
|
380
387
|
const bufferList = new BufferList();
|
|
388
|
+
// Cache native module lookup (only done once)
|
|
389
|
+
const native = tryLoadNative();
|
|
390
|
+
// Choose decoder: native (async via callback) or pure JS (sync wrapped in callback)
|
|
391
|
+
const decodeLzma2Block = (native === null || native === void 0 ? void 0 : native.lzma2) ? (data, props, size, cb)=>{
|
|
392
|
+
var _native_lzma2;
|
|
393
|
+
(_native_lzma2 = native.lzma2) === null || _native_lzma2 === void 0 ? void 0 : _native_lzma2.call(native, data, props, size).then((result)=>cb(null, result), (err)=>cb(err));
|
|
394
|
+
} : (data, props, size, cb)=>{
|
|
395
|
+
try {
|
|
396
|
+
cb(null, decodeLzma2(data, props, size));
|
|
397
|
+
} catch (err) {
|
|
398
|
+
cb(err);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
381
401
|
return new Transform({
|
|
382
402
|
transform (chunk, _encoding, callback) {
|
|
383
403
|
bufferList.append(chunk);
|
|
@@ -435,7 +455,7 @@ export function decodeXZ(input, callback) {
|
|
|
435
455
|
const indexStart = footerEnd - 12 - backwardSize;
|
|
436
456
|
// Parse Index to get block information
|
|
437
457
|
const blockRecords = parseIndex(input, indexStart, checkSize);
|
|
438
|
-
// Decompress
|
|
458
|
+
// Decompress blocks sequentially (native is async)
|
|
439
459
|
let blockIndex = 0;
|
|
440
460
|
const pushBlock = (err)=>{
|
|
441
461
|
if (err) {
|
|
@@ -443,7 +463,8 @@ export function decodeXZ(input, callback) {
|
|
|
443
463
|
return;
|
|
444
464
|
}
|
|
445
465
|
if (blockIndex >= blockRecords.length) {
|
|
446
|
-
// All blocks processed
|
|
466
|
+
// All blocks processed - purge input BufferList to free memory
|
|
467
|
+
if (!Buffer.isBuffer(input)) input.clear();
|
|
447
468
|
callback(null);
|
|
448
469
|
return;
|
|
449
470
|
}
|
|
@@ -460,16 +481,21 @@ export function decodeXZ(input, callback) {
|
|
|
460
481
|
const dataStart = recordStart + headerSize;
|
|
461
482
|
const dataEnd = dataStart + record.compressedDataSize;
|
|
462
483
|
const compressedData = input.slice(dataStart, dataEnd);
|
|
463
|
-
// Decompress this block
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
484
|
+
// Decompress this block (native or pure JS, callback-based)
|
|
485
|
+
decodeLzma2Block(compressedData, blockInfo.lzma2Props, record.uncompressedSize, (decodeErr, blockOutput)=>{
|
|
486
|
+
if (decodeErr || !blockOutput) {
|
|
487
|
+
pushBlock(decodeErr || new Error('Decode returned no data'));
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
// Apply preprocessing filters in reverse order
|
|
491
|
+
for(let j = blockInfo.filters.length - 1; j >= 0; j--){
|
|
492
|
+
blockOutput = applyFilter(blockOutput, blockInfo.filters[j]);
|
|
493
|
+
}
|
|
494
|
+
// Push the block output immediately (streaming)
|
|
495
|
+
this.push(blockOutput);
|
|
496
|
+
// Continue with next block
|
|
497
|
+
pushBlock(null);
|
|
498
|
+
});
|
|
473
499
|
};
|
|
474
500
|
// Start processing blocks
|
|
475
501
|
pushBlock(null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/iterators/xz-compat/src/xz/Decoder.ts"],"sourcesContent":["/**\n * XZ Decompression Module\n *\n * XZ is a container format that wraps LZMA2 compressed data.\n * This module provides both synchronous and streaming XZ decoders.\n *\n * Pure JavaScript implementation, works on Node.js 0.8+\n *\n * IMPORTANT: Buffer Management Pattern\n *\n * When calling decodeLzma2(), use the direct return pattern:\n *\n * ✅ CORRECT - Fast path:\n * const output = decodeLzma2(data, props, size) as Buffer;\n *\n * ❌ WRONG - Slow path (do NOT buffer):\n * const chunks: Buffer[] = [];\n * decodeLzma2(data, props, size, { write: c => chunks.push(c) });\n * return Buffer.concat(chunks); // ← Unnecessary copies!\n */\n\nimport { type BufferLike, BufferList, Transform } from 'extract-base-iterator';\nimport type { Transform as TransformType } from 'stream';\nimport { decodeBcj } from '../filters/bcj/Bcj.ts';\nimport { decodeBcjArm } from '../filters/bcj/BcjArm.ts';\nimport { decodeBcjArm64 } from '../filters/bcj/BcjArm64.ts';\nimport { decodeBcjArmt } from '../filters/bcj/BcjArmt.ts';\nimport { decodeBcjIa64 } from '../filters/bcj/BcjIa64.ts';\nimport { decodeBcjPpc } from '../filters/bcj/BcjPpc.ts';\nimport { decodeBcjSparc } from '../filters/bcj/BcjSparc.ts';\nimport { decodeDelta } from '../filters/delta/Delta.ts';\nimport { decodeLzma2 } from '../lzma/index.ts';\nimport { tryLoadNative } from '../native.ts';\nimport type { DecodeCallback } from '../sevenz.ts';\n\n// XZ magic bytes\nconst XZ_MAGIC = [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00];\nconst XZ_FOOTER_MAGIC = [0x59, 0x5a]; // \"YZ\"\n\n// Filter IDs (from XZ specification)\nconst FILTER_DELTA = 0x03;\nconst FILTER_BCJ_X86 = 0x04;\nconst FILTER_BCJ_PPC = 0x05;\nconst FILTER_BCJ_IA64 = 0x06;\nconst FILTER_BCJ_ARM = 0x07;\nconst FILTER_BCJ_ARMT = 0x08;\nconst FILTER_BCJ_SPARC = 0x09;\nconst FILTER_BCJ_ARM64 = 0x0a;\nconst FILTER_LZMA2 = 0x21;\n\n// Filter info for parsing\ninterface FilterInfo {\n id: number;\n props: Buffer;\n}\n\n// Re-export BufferLike for public API\nexport type { BufferLike } from 'extract-base-iterator';\n\n/**\n * Read a byte from Buffer or BufferList\n */\nfunction readByte(buf: BufferLike, offset: number): number {\n return Buffer.isBuffer(buf) ? buf[offset] : buf.readByte(offset);\n}\n\n/**\n * Read UInt32LE from Buffer or BufferList (returns null if out of bounds)\n */\nfunction readUInt32LE(buf: BufferLike, offset: number): number | null {\n if (Buffer.isBuffer(buf)) {\n if (offset < 0 || offset + 4 > buf.length) return null;\n return buf.readUInt32LE(offset);\n }\n return buf.readUInt32LEAt(offset);\n}\n\n/**\n * Compare buffer contents at offset with expected byte sequence\n * Works with both Buffer and BufferList\n */\nfunction bufferEquals(buf: BufferLike, offset: number, expected: number[]): boolean {\n if (offset + expected.length > buf.length) {\n return false;\n }\n for (let i = 0; i < expected.length; i++) {\n if (readByte(buf, offset + i) !== expected[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Decode variable-length integer (XZ multibyte encoding)\n * Works with both Buffer and BufferList\n */\nfunction decodeMultibyte(buf: BufferLike, offset: number): { value: number; bytesRead: number } {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= buf.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = readByte(buf, offset + i);\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n}\n\n/**\n * Apply a preprocessing filter (BCJ/Delta) to decompressed data\n */\nfunction applyFilter(data: Buffer, filter: FilterInfo): Buffer {\n switch (filter.id) {\n case FILTER_BCJ_X86:\n return decodeBcj(data, filter.props);\n case FILTER_BCJ_ARM:\n return decodeBcjArm(data, filter.props);\n case FILTER_BCJ_ARM64:\n return decodeBcjArm64(data, filter.props);\n case FILTER_BCJ_ARMT:\n return decodeBcjArmt(data, filter.props);\n case FILTER_BCJ_PPC:\n return decodeBcjPpc(data, filter.props);\n case FILTER_BCJ_SPARC:\n return decodeBcjSparc(data, filter.props);\n case FILTER_BCJ_IA64:\n return decodeBcjIa64(data, filter.props);\n case FILTER_DELTA:\n return decodeDelta(data, filter.props);\n default:\n throw new Error(`Unsupported filter: 0x${filter.id.toString(16)}`);\n }\n}\n\n/**\n * Parse XZ Block Header to extract filters and LZMA2 properties\n */\nfunction parseBlockHeader(\n input: Buffer,\n offset: number,\n _checkSize: number\n): {\n filters: FilterInfo[];\n lzma2Props: Buffer;\n headerSize: number;\n dataStart: number;\n dataEnd: number;\n nextOffset: number;\n} {\n // Block header size\n const blockHeaderSizeRaw = input[offset];\n if (blockHeaderSizeRaw === 0) {\n throw new Error('Invalid block header size (index indicator found instead of block)');\n }\n const blockHeaderSize = (blockHeaderSizeRaw + 1) * 4;\n\n // Parse block header\n const blockHeaderStart = offset;\n offset++; // skip size byte\n\n const blockFlags = input[offset++];\n const numFilters = (blockFlags & 0x03) + 1;\n const hasCompressedSize = (blockFlags & 0x40) !== 0;\n const hasUncompressedSize = (blockFlags & 0x80) !== 0;\n\n // Skip optional sizes\n if (hasCompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n if (hasUncompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n // Parse all filters\n const filters: FilterInfo[] = [];\n let lzma2Props: Buffer | null = null;\n\n for (let i = 0; i < numFilters; i++) {\n const filterIdResult = decodeMultibyte(input, offset);\n const filterId = filterIdResult.value;\n offset += filterIdResult.bytesRead;\n\n const propsSizeResult = decodeMultibyte(input, offset);\n offset += propsSizeResult.bytesRead;\n\n const filterProps = input.slice(offset, offset + propsSizeResult.value);\n offset += propsSizeResult.value;\n\n if (filterId === FILTER_LZMA2) {\n // LZMA2 must be the last filter\n lzma2Props = filterProps;\n } else if (filterId === FILTER_DELTA || (filterId >= FILTER_BCJ_X86 && filterId <= FILTER_BCJ_ARM64)) {\n // Preprocessing filter - store for later application\n filters.push({ id: filterId, props: filterProps });\n } else {\n throw new Error(`Unsupported filter: 0x${filterId.toString(16)}`);\n }\n }\n\n if (!lzma2Props) {\n throw new Error('No LZMA2 filter found in XZ block');\n }\n\n // Skip to end of block header (must be aligned to 4 bytes)\n const blockDataStart = blockHeaderStart + blockHeaderSize;\n\n return {\n filters,\n lzma2Props,\n headerSize: blockHeaderSize,\n dataStart: blockDataStart,\n dataEnd: input.length,\n nextOffset: blockDataStart,\n };\n}\n\n/**\n * Parse XZ Index to get block positions\n * Works with both Buffer and BufferList\n */\nfunction parseIndex(\n input: BufferLike,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n // One-time binding for buffer access (avoids repeated Buffer.isBuffer checks)\n const getByte = Buffer.isBuffer(input) ? (offset: number) => input[offset] : (offset: number) => input.readByte(offset);\n\n // Local multibyte decoder using bound getByte\n const decodeMultibyteLocal = (offset: number): { value: number; bytesRead: number } => {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= input.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = getByte(offset + i);\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n };\n\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (getByte(offset) !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyteLocal(offset);\n const recordCount = countResult.value;\n offset += countResult.bytesRead;\n\n const records: Array<{\n compressedPos: number;\n unpaddedSize: number;\n compressedDataSize: number;\n uncompressedSize: number;\n }> = [];\n\n // Parse each record\n for (let i = 0; i < recordCount; i++) {\n // Unpadded Size (header + compressed data + check)\n const unpaddedResult = decodeMultibyteLocal(offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyteLocal(offset);\n offset += uncompressedResult.bytesRead;\n\n records.push({\n compressedPos: 0, // will be calculated\n unpaddedSize: unpaddedResult.value,\n compressedDataSize: 0, // will be calculated\n uncompressedSize: uncompressedResult.value,\n });\n }\n\n // Calculate actual positions by walking through blocks\n let currentPos = 12; // After stream header\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n // Record where this block's header starts\n record.compressedPos = currentPos;\n\n // Get block header size from the actual data\n const headerSizeRaw = getByte(currentPos);\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n record.compressedDataSize = record.unpaddedSize - headerSize - checkSize;\n\n // Move to next block: unpaddedSize + padding to 4-byte boundary\n const paddedSize = Math.ceil(record.unpaddedSize / 4) * 4;\n currentPos += paddedSize;\n }\n\n return records;\n}\n\n/**\n * Pure JS XZ decompression (handles all XZ spec features)\n * Returns BufferList for memory efficiency with large files.\n */\nfunction decodeXZPure(input: Buffer): Buffer | BufferList {\n // Verify XZ magic\n if (input.length < 12 || !bufferEquals(input, 0, XZ_MAGIC)) {\n throw new Error('Invalid XZ magic bytes');\n }\n\n // Stream flags at offset 6-7\n const checkType = readByte(input, 7) & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n // Stream padding must be multiple of 4 bytes\n let footerEnd = input.length;\n while (footerEnd > 12 && readByte(input, footerEnd - 1) === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary (stream padding rules)\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {\n throw new Error('Invalid XZ footer magic');\n }\n\n // Get backward size (tells us where index starts) - at footerEnd - 8\n const backwardSizeLE = readUInt32LE(input, footerEnd - 8);\n if (backwardSizeLE === null) {\n throw new Error('Invalid backward size');\n }\n const backwardSize = (backwardSizeLE + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Single block optimization: return Buffer directly (avoids BufferList overhead)\n // Most small files have only one block\n if (blockRecords.length === 1) {\n const record = blockRecords[0];\n const recordStart = record.compressedPos;\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n const dataStart = recordStart + blockInfo.headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n const compressedData = input.slice(dataStart, dataEnd);\n\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n return blockOutput;\n }\n\n // Multi-block: use BufferList to avoid large contiguous allocation\n const output = new BufferList();\n\n for (let i = 0; i < blockRecords.length; i++) {\n const record = blockRecords[i];\n const recordStart = record.compressedPos;\n\n // Parse block header\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + blockInfo.headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n\n // Note: XZ blocks have padding AFTER the check field to align to 4 bytes,\n // but the compressedSize from index is exact - no need to strip padding.\n // LZMA2 data includes a 0x00 end marker which must NOT be stripped.\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block with LZMA2 (fast path, no buffering)\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n // Apply preprocessing filters in reverse order (BCJ/Delta applied after LZMA2)\n // Filters are stored in order they were applied during compression,\n // so we need to reverse for decompression\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n // Append block to BufferList\n output.append(blockOutput);\n }\n\n return output;\n}\n\n/** Callback invoked when an async decode completes */\nexport type XzDecodeCallback = DecodeCallback<BufferLike>;\n\n/**\n * Decompress XZ data. With a callback the result is provided asynchronously;\n * otherwise a Promise resolves with the decoded data.\n *\n * Returns Buffer for single-block files (most small files).\n * Returns BufferList for multi-block files (avoids large contiguous allocation).\n */\nexport function decodeXZ(input: Buffer, callback: XzDecodeCallback): void;\nexport function decodeXZ(input: Buffer): Promise<BufferLike>;\nexport function decodeXZ(input: Buffer, callback?: XzDecodeCallback): Promise<BufferLike> | void {\n const worker = (cb: XzDecodeCallback) => {\n const fallback = () => {\n try {\n cb(null, decodeXZPure(input));\n } catch (err) {\n cb(err as Error);\n }\n };\n\n const native = tryLoadNative();\n if (native?.xz?.decompress) {\n try {\n const promise = native.xz.decompress(input);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value as BufferLike), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as BufferLike))));\n}\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n *\n * Uses BufferList to avoid large contiguous buffer allocations.\n * Decompresses and pushes blocks one at a time for streaming output.\n */\nexport function createXZDecoder(): TransformType {\n const bufferList = new BufferList();\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n bufferList.append(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n const input: BufferLike = bufferList;\n\n // One-time binding for buffer access (avoids repeated Buffer.isBuffer checks)\n const getByte = Buffer.isBuffer(input) ? (offset: number) => input[offset] : (offset: number) => input.readByte(offset);\n\n const getUInt32LE = Buffer.isBuffer(input) ? (offset: number) => (offset < 0 || offset + 4 > input.length ? null : input.readUInt32LE(offset)) : (offset: number) => input.readUInt32LEAt(offset);\n\n const equals = (offset: number, expected: number[]): boolean => {\n if (offset + expected.length > input.length) return false;\n for (let i = 0; i < expected.length; i++) {\n if (getByte(offset + i) !== expected[i]) return false;\n }\n return true;\n };\n\n // Verify XZ magic (need at least 12 bytes)\n if (input.length < 12 || !equals(0, XZ_MAGIC)) {\n callback(new Error('Invalid XZ magic bytes'));\n return;\n }\n\n // Stream flags at offset 6-7\n const checkType = getByte(7) & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n let footerEnd = input.length;\n while (footerEnd > 12 && getByte(footerEnd - 1) === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!equals(footerEnd - 2, XZ_FOOTER_MAGIC)) {\n callback(new Error('Invalid XZ footer magic'));\n return;\n }\n\n // Get backward size (at footerEnd - 8)\n const backwardSizeLE = getUInt32LE(footerEnd - 8);\n if (backwardSizeLE === null) {\n callback(new Error('Invalid backward size'));\n return;\n }\n const backwardSize = (backwardSizeLE + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Decompress and push each block (streaming, no large allocations)\n let blockIndex = 0;\n const pushBlock = (err: Error | null) => {\n if (err) {\n callback(err);\n return;\n }\n\n if (blockIndex >= blockRecords.length) {\n // All blocks processed\n callback(null);\n return;\n }\n\n const record = blockRecords[blockIndex++];\n const recordStart = record.compressedPos;\n\n // Parse block header (need to get the header bytes)\n // Read header size byte first\n const headerSizeRaw = getByte(recordStart);\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Read the full header to parse filters\n const headerData = input.slice(recordStart, recordStart + headerSize);\n const blockInfo = parseBlockHeader(headerData, 0, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n // Apply preprocessing filters in reverse order\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n // Push the block output immediately (streaming)\n this.push(blockOutput);\n\n // Continue with next block\n pushBlock(null);\n };\n\n // Start processing blocks\n pushBlock(null);\n },\n });\n}\n"],"names":["BufferList","Transform","decodeBcj","decodeBcjArm","decodeBcjArm64","decodeBcjArmt","decodeBcjIa64","decodeBcjPpc","decodeBcjSparc","decodeDelta","decodeLzma2","tryLoadNative","XZ_MAGIC","XZ_FOOTER_MAGIC","FILTER_DELTA","FILTER_BCJ_X86","FILTER_BCJ_PPC","FILTER_BCJ_IA64","FILTER_BCJ_ARM","FILTER_BCJ_ARMT","FILTER_BCJ_SPARC","FILTER_BCJ_ARM64","FILTER_LZMA2","readByte","buf","offset","Buffer","isBuffer","readUInt32LE","length","readUInt32LEAt","bufferEquals","expected","i","decodeMultibyte","value","byte","Error","bytesRead","applyFilter","data","filter","id","props","toString","parseBlockHeader","input","_checkSize","blockHeaderSizeRaw","blockHeaderSize","blockHeaderStart","blockFlags","numFilters","hasCompressedSize","hasUncompressedSize","result","filters","lzma2Props","filterIdResult","filterId","propsSizeResult","filterProps","slice","push","blockDataStart","headerSize","dataStart","dataEnd","nextOffset","parseIndex","indexStart","checkSize","getByte","decodeMultibyteLocal","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","decodeXZPure","checkSizes","checkType","footerEnd","backwardSizeLE","backwardSize","blockRecords","recordStart","blockInfo","compressedData","blockOutput","j","output","append","decodeXZ","callback","worker","cb","native","fallback","err","xz","decompress","promise","then","Promise","resolve","reject","createXZDecoder","bufferList","transform","chunk","_encoding","flush","getUInt32LE","equals","blockIndex","pushBlock","headerData"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/iterators/xz-compat/src/xz/Decoder.ts"],"sourcesContent":["/**\n * XZ Decompression Module\n *\n * XZ is a container format that wraps LZMA2 compressed data.\n * This module provides both synchronous and streaming XZ decoders.\n *\n * Pure JavaScript implementation, works on Node.js 0.8+\n *\n * IMPORTANT: Buffer Management Pattern\n *\n * When calling decodeLzma2(), use the direct return pattern:\n *\n * ✅ CORRECT - Fast path:\n * const output = decodeLzma2(data, props, size) as Buffer;\n *\n * ❌ WRONG - Slow path (do NOT buffer):\n * const chunks: Buffer[] = [];\n * decodeLzma2(data, props, size, { write: c => chunks.push(c) });\n * return Buffer.concat(chunks); // ← Unnecessary copies!\n */\n\nimport { type BufferLike, BufferList, Transform } from 'extract-base-iterator';\nimport type { Transform as TransformType } from 'stream';\nimport { decodeBcj } from '../filters/bcj/Bcj.ts';\nimport { decodeBcjArm } from '../filters/bcj/BcjArm.ts';\nimport { decodeBcjArm64 } from '../filters/bcj/BcjArm64.ts';\nimport { decodeBcjArmt } from '../filters/bcj/BcjArmt.ts';\nimport { decodeBcjIa64 } from '../filters/bcj/BcjIa64.ts';\nimport { decodeBcjPpc } from '../filters/bcj/BcjPpc.ts';\nimport { decodeBcjSparc } from '../filters/bcj/BcjSparc.ts';\nimport { decodeDelta } from '../filters/delta/Delta.ts';\nimport { decodeLzma2 } from '../lzma/index.ts';\nimport { tryLoadNative } from '../native.ts';\nimport type { DecodeCallback } from '../sevenz.ts';\n\n// XZ magic bytes\nconst XZ_MAGIC = [0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00];\nconst XZ_FOOTER_MAGIC = [0x59, 0x5a]; // \"YZ\"\n\n// Filter IDs (from XZ specification)\nconst FILTER_DELTA = 0x03;\nconst FILTER_BCJ_X86 = 0x04;\nconst FILTER_BCJ_PPC = 0x05;\nconst FILTER_BCJ_IA64 = 0x06;\nconst FILTER_BCJ_ARM = 0x07;\nconst FILTER_BCJ_ARMT = 0x08;\nconst FILTER_BCJ_SPARC = 0x09;\nconst FILTER_BCJ_ARM64 = 0x0a;\nconst FILTER_LZMA2 = 0x21;\n\n// Filter info for parsing\ninterface FilterInfo {\n id: number;\n props: Buffer;\n}\n\n// Re-export BufferLike for public API\nexport type { BufferLike } from 'extract-base-iterator';\n\n/**\n * Read a byte from Buffer or BufferList\n */\nfunction readByte(buf: BufferLike, offset: number): number {\n return Buffer.isBuffer(buf) ? buf[offset] : buf.readByte(offset);\n}\n\n/**\n * Read UInt32LE from Buffer or BufferList (returns null if out of bounds)\n */\nfunction readUInt32LE(buf: BufferLike, offset: number): number | null {\n if (Buffer.isBuffer(buf)) {\n if (offset < 0 || offset + 4 > buf.length) return null;\n return buf.readUInt32LE(offset);\n }\n return buf.readUInt32LEAt(offset);\n}\n\n/**\n * Compare buffer contents at offset with expected byte sequence\n * Works with both Buffer and BufferList\n */\nfunction bufferEquals(buf: BufferLike, offset: number, expected: number[]): boolean {\n if (offset + expected.length > buf.length) {\n return false;\n }\n for (let i = 0; i < expected.length; i++) {\n if (readByte(buf, offset + i) !== expected[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Decode variable-length integer (XZ multibyte encoding)\n * Works with both Buffer and BufferList\n */\nfunction decodeMultibyte(buf: BufferLike, offset: number): { value: number; bytesRead: number } {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= buf.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = readByte(buf, offset + i);\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n}\n\n/**\n * Apply a preprocessing filter (BCJ/Delta) to decompressed data\n */\nfunction applyFilter(data: Buffer, filter: FilterInfo): Buffer {\n switch (filter.id) {\n case FILTER_BCJ_X86:\n return decodeBcj(data, filter.props);\n case FILTER_BCJ_ARM:\n return decodeBcjArm(data, filter.props);\n case FILTER_BCJ_ARM64:\n return decodeBcjArm64(data, filter.props);\n case FILTER_BCJ_ARMT:\n return decodeBcjArmt(data, filter.props);\n case FILTER_BCJ_PPC:\n return decodeBcjPpc(data, filter.props);\n case FILTER_BCJ_SPARC:\n return decodeBcjSparc(data, filter.props);\n case FILTER_BCJ_IA64:\n return decodeBcjIa64(data, filter.props);\n case FILTER_DELTA:\n return decodeDelta(data, filter.props);\n default:\n throw new Error(`Unsupported filter: 0x${filter.id.toString(16)}`);\n }\n}\n\n/**\n * Parse XZ Block Header to extract filters and LZMA2 properties\n */\nfunction parseBlockHeader(\n input: Buffer,\n offset: number,\n _checkSize: number\n): {\n filters: FilterInfo[];\n lzma2Props: Buffer;\n headerSize: number;\n dataStart: number;\n dataEnd: number;\n nextOffset: number;\n} {\n // Block header size\n const blockHeaderSizeRaw = input[offset];\n if (blockHeaderSizeRaw === 0) {\n throw new Error('Invalid block header size (index indicator found instead of block)');\n }\n const blockHeaderSize = (blockHeaderSizeRaw + 1) * 4;\n\n // Parse block header\n const blockHeaderStart = offset;\n offset++; // skip size byte\n\n const blockFlags = input[offset++];\n const numFilters = (blockFlags & 0x03) + 1;\n const hasCompressedSize = (blockFlags & 0x40) !== 0;\n const hasUncompressedSize = (blockFlags & 0x80) !== 0;\n\n // Skip optional sizes\n if (hasCompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n if (hasUncompressedSize) {\n const result = decodeMultibyte(input, offset);\n offset += result.bytesRead;\n }\n\n // Parse all filters\n const filters: FilterInfo[] = [];\n let lzma2Props: Buffer | null = null;\n\n for (let i = 0; i < numFilters; i++) {\n const filterIdResult = decodeMultibyte(input, offset);\n const filterId = filterIdResult.value;\n offset += filterIdResult.bytesRead;\n\n const propsSizeResult = decodeMultibyte(input, offset);\n offset += propsSizeResult.bytesRead;\n\n const filterProps = input.slice(offset, offset + propsSizeResult.value);\n offset += propsSizeResult.value;\n\n if (filterId === FILTER_LZMA2) {\n // LZMA2 must be the last filter\n lzma2Props = filterProps;\n } else if (filterId === FILTER_DELTA || (filterId >= FILTER_BCJ_X86 && filterId <= FILTER_BCJ_ARM64)) {\n // Preprocessing filter - store for later application\n filters.push({ id: filterId, props: filterProps });\n } else {\n throw new Error(`Unsupported filter: 0x${filterId.toString(16)}`);\n }\n }\n\n if (!lzma2Props) {\n throw new Error('No LZMA2 filter found in XZ block');\n }\n\n // Skip to end of block header (must be aligned to 4 bytes)\n const blockDataStart = blockHeaderStart + blockHeaderSize;\n\n return {\n filters,\n lzma2Props,\n headerSize: blockHeaderSize,\n dataStart: blockDataStart,\n dataEnd: input.length,\n nextOffset: blockDataStart,\n };\n}\n\n/**\n * Parse XZ Index to get block positions\n * Works with both Buffer and BufferList\n */\nfunction parseIndex(\n input: BufferLike,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n // One-time binding for buffer access (avoids repeated Buffer.isBuffer checks)\n const getByte = Buffer.isBuffer(input) ? (offset: number) => input[offset] : (offset: number) => input.readByte(offset);\n\n // Local multibyte decoder using bound getByte\n const decodeMultibyteLocal = (offset: number): { value: number; bytesRead: number } => {\n let value = 0;\n let i = 0;\n let byte: number;\n do {\n if (offset + i >= input.length) {\n throw new Error('Truncated multibyte integer');\n }\n byte = getByte(offset + i);\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n throw new Error('Multibyte integer too large');\n }\n } while (byte & 0x80);\n return { value, bytesRead: i };\n };\n\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (getByte(offset) !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyteLocal(offset);\n const recordCount = countResult.value;\n offset += countResult.bytesRead;\n\n const records: Array<{\n compressedPos: number;\n unpaddedSize: number;\n compressedDataSize: number;\n uncompressedSize: number;\n }> = [];\n\n // Parse each record\n for (let i = 0; i < recordCount; i++) {\n // Unpadded Size (header + compressed data + check)\n const unpaddedResult = decodeMultibyteLocal(offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyteLocal(offset);\n offset += uncompressedResult.bytesRead;\n\n records.push({\n compressedPos: 0, // will be calculated\n unpaddedSize: unpaddedResult.value,\n compressedDataSize: 0, // will be calculated\n uncompressedSize: uncompressedResult.value,\n });\n }\n\n // Calculate actual positions by walking through blocks\n let currentPos = 12; // After stream header\n for (let i = 0; i < records.length; i++) {\n const record = records[i];\n // Record where this block's header starts\n record.compressedPos = currentPos;\n\n // Get block header size from the actual data\n const headerSizeRaw = getByte(currentPos);\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n record.compressedDataSize = record.unpaddedSize - headerSize - checkSize;\n\n // Move to next block: unpaddedSize + padding to 4-byte boundary\n const paddedSize = Math.ceil(record.unpaddedSize / 4) * 4;\n currentPos += paddedSize;\n }\n\n return records;\n}\n\n/**\n * Pure JS XZ decompression (handles all XZ spec features)\n * Returns BufferList for memory efficiency with large files.\n */\nfunction decodeXZPure(input: Buffer): Buffer | BufferList {\n // Verify XZ magic\n if (input.length < 12 || !bufferEquals(input, 0, XZ_MAGIC)) {\n throw new Error('Invalid XZ magic bytes');\n }\n\n // Stream flags at offset 6-7\n const checkType = readByte(input, 7) & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n // Stream padding must be multiple of 4 bytes\n let footerEnd = input.length;\n while (footerEnd > 12 && readByte(input, footerEnd - 1) === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary (stream padding rules)\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {\n throw new Error('Invalid XZ footer magic');\n }\n\n // Get backward size (tells us where index starts) - at footerEnd - 8\n const backwardSizeLE = readUInt32LE(input, footerEnd - 8);\n if (backwardSizeLE === null) {\n throw new Error('Invalid backward size');\n }\n const backwardSize = (backwardSizeLE + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Calculate total uncompressed size for multi-block decision\n let totalUncompressedSize = 0;\n for (let i = 0; i < blockRecords.length; i++) {\n totalUncompressedSize += blockRecords[i].uncompressedSize;\n }\n\n // Small multi-block files: use Buffer.concat directly (avoids BufferList overhead)\n // Threshold of 64KB: below this, the overhead of linked list nodes isn't worth it\n const BUFFERLIST_THRESHOLD = 64 * 1024; // 64KB\n\n // Single block OR small multi-block: return Buffer directly\n if (blockRecords.length === 1 || totalUncompressedSize < BUFFERLIST_THRESHOLD) {\n const record = blockRecords[0];\n const recordStart = record.compressedPos;\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n const dataStart = recordStart + blockInfo.headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n const compressedData = input.slice(dataStart, dataEnd);\n\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n return blockOutput;\n }\n\n // Multi-block (large): use BufferList to avoid large contiguous allocation\n const output = new BufferList();\n\n for (let i = 0; i < blockRecords.length; i++) {\n const record = blockRecords[i];\n const recordStart = record.compressedPos;\n\n // Parse block header\n const blockInfo = parseBlockHeader(input, recordStart, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + blockInfo.headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n\n // Note: XZ blocks have padding AFTER the check field to align to 4 bytes,\n // but the compressedSize from index is exact - no need to strip padding.\n // LZMA2 data includes a 0x00 end marker which must NOT be stripped.\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block with LZMA2 (fast path, no buffering)\n let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize) as Buffer;\n\n // Apply preprocessing filters in reverse order (BCJ/Delta applied after LZMA2)\n // Filters are stored in order they were applied during compression,\n // so we need to reverse for decompression\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n // Append block to BufferList\n output.append(blockOutput);\n }\n\n return output;\n}\n\n/** Callback invoked when an async decode completes */\nexport type XzDecodeCallback = DecodeCallback<BufferLike>;\n\n/**\n * Decompress XZ data. With a callback the result is provided asynchronously;\n * otherwise a Promise resolves with the decoded data.\n *\n * Returns Buffer for single-block files (most small files).\n * Returns BufferList for multi-block files (avoids large contiguous allocation).\n */\nexport function decodeXZ(input: Buffer, callback: XzDecodeCallback): void;\nexport function decodeXZ(input: Buffer): Promise<BufferLike>;\nexport function decodeXZ(input: Buffer, callback?: XzDecodeCallback): Promise<BufferLike> | void {\n const worker = (cb: XzDecodeCallback) => {\n const fallback = () => {\n try {\n cb(null, decodeXZPure(input));\n } catch (err) {\n cb(err as Error);\n }\n };\n\n const native = tryLoadNative();\n if (native?.xz?.decompress) {\n try {\n const promise = native.xz.decompress(input);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value as BufferLike), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as BufferLike))));\n}\n\n// Callback-based LZMA2 decoder type (for Node 0.8+ compatibility - no promises)\ntype Lzma2DecodeCallback = (err: Error | null, result?: Buffer) => void;\ntype Lzma2Decoder = (data: Buffer, props: Buffer, size: number, callback: Lzma2DecodeCallback) => void;\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n *\n * Uses native lzma-native bindings when available for better performance.\n * Falls back to pure JS implementation on older Node versions or when native is unavailable.\n */\nexport function createXZDecoder(): TransformType {\n const bufferList = new BufferList();\n // Cache native module lookup (only done once)\n const native = tryLoadNative();\n\n // Choose decoder: native (async via callback) or pure JS (sync wrapped in callback)\n const decodeLzma2Block: Lzma2Decoder = native?.lzma2\n ? (data, props, size, cb) => {\n native.lzma2?.(data, props, size).then(\n (result) => cb(null, result),\n (err) => cb(err)\n );\n }\n : (data, props, size, cb) => {\n try {\n cb(null, decodeLzma2(data, props, size) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n };\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n bufferList.append(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n const input: BufferLike = bufferList;\n\n // One-time binding for buffer access (avoids repeated Buffer.isBuffer checks)\n const getByte = Buffer.isBuffer(input) ? (offset: number) => input[offset] : (offset: number) => input.readByte(offset);\n\n const getUInt32LE = Buffer.isBuffer(input) ? (offset: number) => (offset < 0 || offset + 4 > input.length ? null : input.readUInt32LE(offset)) : (offset: number) => input.readUInt32LEAt(offset);\n\n const equals = (offset: number, expected: number[]): boolean => {\n if (offset + expected.length > input.length) return false;\n for (let i = 0; i < expected.length; i++) {\n if (getByte(offset + i) !== expected[i]) return false;\n }\n return true;\n };\n\n // Verify XZ magic (need at least 12 bytes)\n if (input.length < 12 || !equals(0, XZ_MAGIC)) {\n callback(new Error('Invalid XZ magic bytes'));\n return;\n }\n\n // Stream flags at offset 6-7\n const checkType = getByte(7) & 0x0f;\n\n // Check sizes based on check type\n const checkSizes: { [key: number]: number } = {\n 0: 0, // None\n 1: 4, // CRC32\n 4: 8, // CRC64\n 10: 32, // SHA-256\n };\n const checkSize = checkSizes[checkType] ?? 0;\n\n // Find footer by skipping stream padding (null bytes at end before footer)\n let footerEnd = input.length;\n while (footerEnd > 12 && getByte(footerEnd - 1) === 0x00) {\n footerEnd--;\n }\n // Align to 4-byte boundary\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic (at footerEnd - 2)\n if (!equals(footerEnd - 2, XZ_FOOTER_MAGIC)) {\n callback(new Error('Invalid XZ footer magic'));\n return;\n }\n\n // Get backward size (at footerEnd - 8)\n const backwardSizeLE = getUInt32LE(footerEnd - 8);\n if (backwardSizeLE === null) {\n callback(new Error('Invalid backward size'));\n return;\n }\n const backwardSize = (backwardSizeLE + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n const blockRecords = parseIndex(input, indexStart, checkSize);\n\n // Decompress blocks sequentially (native is async)\n let blockIndex = 0;\n const pushBlock = (err: Error | null) => {\n if (err) {\n callback(err);\n return;\n }\n\n if (blockIndex >= blockRecords.length) {\n // All blocks processed - purge input BufferList to free memory\n if (!Buffer.isBuffer(input)) input.clear();\n callback(null);\n return;\n }\n\n const record = blockRecords[blockIndex++];\n const recordStart = record.compressedPos;\n\n // Parse block header (need to get the header bytes)\n // Read header size byte first\n const headerSizeRaw = getByte(recordStart);\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Read the full header to parse filters\n const headerData = input.slice(recordStart, recordStart + headerSize);\n const blockInfo = parseBlockHeader(headerData, 0, checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + headerSize;\n const dataEnd = dataStart + record.compressedDataSize;\n const compressedData = input.slice(dataStart, dataEnd);\n\n // Decompress this block (native or pure JS, callback-based)\n decodeLzma2Block(compressedData, blockInfo.lzma2Props, record.uncompressedSize, (decodeErr, blockOutput) => {\n if (decodeErr || !blockOutput) {\n pushBlock(decodeErr || new Error('Decode returned no data'));\n return;\n }\n\n // Apply preprocessing filters in reverse order\n for (let j = blockInfo.filters.length - 1; j >= 0; j--) {\n blockOutput = applyFilter(blockOutput, blockInfo.filters[j]) as Buffer;\n }\n\n // Push the block output immediately (streaming)\n this.push(blockOutput);\n\n // Continue with next block\n pushBlock(null);\n });\n };\n\n // Start processing blocks\n pushBlock(null);\n },\n });\n}\n"],"names":["BufferList","Transform","decodeBcj","decodeBcjArm","decodeBcjArm64","decodeBcjArmt","decodeBcjIa64","decodeBcjPpc","decodeBcjSparc","decodeDelta","decodeLzma2","tryLoadNative","XZ_MAGIC","XZ_FOOTER_MAGIC","FILTER_DELTA","FILTER_BCJ_X86","FILTER_BCJ_PPC","FILTER_BCJ_IA64","FILTER_BCJ_ARM","FILTER_BCJ_ARMT","FILTER_BCJ_SPARC","FILTER_BCJ_ARM64","FILTER_LZMA2","readByte","buf","offset","Buffer","isBuffer","readUInt32LE","length","readUInt32LEAt","bufferEquals","expected","i","decodeMultibyte","value","byte","Error","bytesRead","applyFilter","data","filter","id","props","toString","parseBlockHeader","input","_checkSize","blockHeaderSizeRaw","blockHeaderSize","blockHeaderStart","blockFlags","numFilters","hasCompressedSize","hasUncompressedSize","result","filters","lzma2Props","filterIdResult","filterId","propsSizeResult","filterProps","slice","push","blockDataStart","headerSize","dataStart","dataEnd","nextOffset","parseIndex","indexStart","checkSize","getByte","decodeMultibyteLocal","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","decodeXZPure","checkSizes","checkType","footerEnd","backwardSizeLE","backwardSize","blockRecords","totalUncompressedSize","BUFFERLIST_THRESHOLD","recordStart","blockInfo","compressedData","blockOutput","j","output","append","decodeXZ","callback","worker","cb","native","fallback","err","xz","decompress","promise","then","Promise","resolve","reject","createXZDecoder","bufferList","decodeLzma2Block","lzma2","size","transform","chunk","_encoding","flush","getUInt32LE","equals","blockIndex","pushBlock","clear","headerData","decodeErr"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;CAmBC,GAED,SAA0BA,UAAU,EAAEC,SAAS,QAAQ,wBAAwB;AAE/E,SAASC,SAAS,QAAQ,wBAAwB;AAClD,SAASC,YAAY,QAAQ,2BAA2B;AACxD,SAASC,cAAc,QAAQ,6BAA6B;AAC5D,SAASC,aAAa,QAAQ,4BAA4B;AAC1D,SAASC,aAAa,QAAQ,4BAA4B;AAC1D,SAASC,YAAY,QAAQ,2BAA2B;AACxD,SAASC,cAAc,QAAQ,6BAA6B;AAC5D,SAASC,WAAW,QAAQ,4BAA4B;AACxD,SAASC,WAAW,QAAQ,mBAAmB;AAC/C,SAASC,aAAa,QAAQ,eAAe;AAG7C,iBAAiB;AACjB,MAAMC,WAAW;IAAC;IAAM;IAAM;IAAM;IAAM;IAAM;CAAK;AACrD,MAAMC,kBAAkB;IAAC;IAAM;CAAK,EAAE,OAAO;AAE7C,qCAAqC;AACrC,MAAMC,eAAe;AACrB,MAAMC,iBAAiB;AACvB,MAAMC,iBAAiB;AACvB,MAAMC,kBAAkB;AACxB,MAAMC,iBAAiB;AACvB,MAAMC,kBAAkB;AACxB,MAAMC,mBAAmB;AACzB,MAAMC,mBAAmB;AACzB,MAAMC,eAAe;AAWrB;;CAEC,GACD,SAASC,SAASC,GAAe,EAAEC,MAAc;IAC/C,OAAOC,OAAOC,QAAQ,CAACH,OAAOA,GAAG,CAACC,OAAO,GAAGD,IAAID,QAAQ,CAACE;AAC3D;AAEA;;CAEC,GACD,SAASG,aAAaJ,GAAe,EAAEC,MAAc;IACnD,IAAIC,OAAOC,QAAQ,CAACH,MAAM;QACxB,IAAIC,SAAS,KAAKA,SAAS,IAAID,IAAIK,MAAM,EAAE,OAAO;QAClD,OAAOL,IAAII,YAAY,CAACH;IAC1B;IACA,OAAOD,IAAIM,cAAc,CAACL;AAC5B;AAEA;;;CAGC,GACD,SAASM,aAAaP,GAAe,EAAEC,MAAc,EAAEO,QAAkB;IACvE,IAAIP,SAASO,SAASH,MAAM,GAAGL,IAAIK,MAAM,EAAE;QACzC,OAAO;IACT;IACA,IAAK,IAAII,IAAI,GAAGA,IAAID,SAASH,MAAM,EAAEI,IAAK;QACxC,IAAIV,SAASC,KAAKC,SAASQ,OAAOD,QAAQ,CAACC,EAAE,EAAE;YAC7C,OAAO;QACT;IACF;IACA,OAAO;AACT;AAEA;;;CAGC,GACD,SAASC,gBAAgBV,GAAe,EAAEC,MAAc;IACtD,IAAIU,QAAQ;IACZ,IAAIF,IAAI;IACR,IAAIG;IACJ,GAAG;QACD,IAAIX,SAASQ,KAAKT,IAAIK,MAAM,EAAE;YAC5B,MAAM,IAAIQ,MAAM;QAClB;QACAD,OAAOb,SAASC,KAAKC,SAASQ;QAC9BE,SAAS,AAACC,CAAAA,OAAO,IAAG,KAAOH,IAAI;QAC/BA;QACA,IAAIA,IAAI,GAAG;YACT,MAAM,IAAII,MAAM;QAClB;IACF,QAASD,OAAO,KAAM;IACtB,OAAO;QAAED;QAAOG,WAAWL;IAAE;AAC/B;AAEA;;CAEC,GACD,SAASM,YAAYC,IAAY,EAAEC,MAAkB;IACnD,OAAQA,OAAOC,EAAE;QACf,KAAK3B;YACH,OAAOb,UAAUsC,MAAMC,OAAOE,KAAK;QACrC,KAAKzB;YACH,OAAOf,aAAaqC,MAAMC,OAAOE,KAAK;QACxC,KAAKtB;YACH,OAAOjB,eAAeoC,MAAMC,OAAOE,KAAK;QAC1C,KAAKxB;YACH,OAAOd,cAAcmC,MAAMC,OAAOE,KAAK;QACzC,KAAK3B;YACH,OAAOT,aAAaiC,MAAMC,OAAOE,KAAK;QACxC,KAAKvB;YACH,OAAOZ,eAAegC,MAAMC,OAAOE,KAAK;QAC1C,KAAK1B;YACH,OAAOX,cAAckC,MAAMC,OAAOE,KAAK;QACzC,KAAK7B;YACH,OAAOL,YAAY+B,MAAMC,OAAOE,KAAK;QACvC;YACE,MAAM,IAAIN,MAAM,CAAC,sBAAsB,EAAEI,OAAOC,EAAE,CAACE,QAAQ,CAAC,KAAK;IACrE;AACF;AAEA;;CAEC,GACD,SAASC,iBACPC,KAAa,EACbrB,MAAc,EACdsB,UAAkB;IASlB,oBAAoB;IACpB,MAAMC,qBAAqBF,KAAK,CAACrB,OAAO;IACxC,IAAIuB,uBAAuB,GAAG;QAC5B,MAAM,IAAIX,MAAM;IAClB;IACA,MAAMY,kBAAkB,AAACD,CAAAA,qBAAqB,CAAA,IAAK;IAEnD,qBAAqB;IACrB,MAAME,mBAAmBzB;IACzBA,UAAU,iBAAiB;IAE3B,MAAM0B,aAAaL,KAAK,CAACrB,SAAS;IAClC,MAAM2B,aAAa,AAACD,CAAAA,aAAa,IAAG,IAAK;IACzC,MAAME,oBAAoB,AAACF,CAAAA,aAAa,IAAG,MAAO;IAClD,MAAMG,sBAAsB,AAACH,CAAAA,aAAa,IAAG,MAAO;IAEpD,sBAAsB;IACtB,IAAIE,mBAAmB;QACrB,MAAME,SAASrB,gBAAgBY,OAAOrB;QACtCA,UAAU8B,OAAOjB,SAAS;IAC5B;IAEA,IAAIgB,qBAAqB;QACvB,MAAMC,SAASrB,gBAAgBY,OAAOrB;QACtCA,UAAU8B,OAAOjB,SAAS;IAC5B;IAEA,oBAAoB;IACpB,MAAMkB,UAAwB,EAAE;IAChC,IAAIC,aAA4B;IAEhC,IAAK,IAAIxB,IAAI,GAAGA,IAAImB,YAAYnB,IAAK;QACnC,MAAMyB,iBAAiBxB,gBAAgBY,OAAOrB;QAC9C,MAAMkC,WAAWD,eAAevB,KAAK;QACrCV,UAAUiC,eAAepB,SAAS;QAElC,MAAMsB,kBAAkB1B,gBAAgBY,OAAOrB;QAC/CA,UAAUmC,gBAAgBtB,SAAS;QAEnC,MAAMuB,cAAcf,MAAMgB,KAAK,CAACrC,QAAQA,SAASmC,gBAAgBzB,KAAK;QACtEV,UAAUmC,gBAAgBzB,KAAK;QAE/B,IAAIwB,aAAarC,cAAc;YAC7B,gCAAgC;YAChCmC,aAAaI;QACf,OAAO,IAAIF,aAAa7C,gBAAiB6C,YAAY5C,kBAAkB4C,YAAYtC,kBAAmB;YACpG,qDAAqD;YACrDmC,QAAQO,IAAI,CAAC;gBAAErB,IAAIiB;gBAAUhB,OAAOkB;YAAY;QAClD,OAAO;YACL,MAAM,IAAIxB,MAAM,CAAC,sBAAsB,EAAEsB,SAASf,QAAQ,CAAC,KAAK;QAClE;IACF;IAEA,IAAI,CAACa,YAAY;QACf,MAAM,IAAIpB,MAAM;IAClB;IAEA,2DAA2D;IAC3D,MAAM2B,iBAAiBd,mBAAmBD;IAE1C,OAAO;QACLO;QACAC;QACAQ,YAAYhB;QACZiB,WAAWF;QACXG,SAASrB,MAAMjB,MAAM;QACrBuC,YAAYJ;IACd;AACF;AAEA;;;CAGC,GACD,SAASK,WACPvB,KAAiB,EACjBwB,UAAkB,EAClBC,SAAiB;IAMjB,8EAA8E;IAC9E,MAAMC,UAAU9C,OAAOC,QAAQ,CAACmB,SAAS,CAACrB,SAAmBqB,KAAK,CAACrB,OAAO,GAAG,CAACA,SAAmBqB,MAAMvB,QAAQ,CAACE;IAEhH,8CAA8C;IAC9C,MAAMgD,uBAAuB,CAAChD;QAC5B,IAAIU,QAAQ;QACZ,IAAIF,IAAI;QACR,IAAIG;QACJ,GAAG;YACD,IAAIX,SAASQ,KAAKa,MAAMjB,MAAM,EAAE;gBAC9B,MAAM,IAAIQ,MAAM;YAClB;YACAD,OAAOoC,QAAQ/C,SAASQ;YACxBE,SAAS,AAACC,CAAAA,OAAO,IAAG,KAAOH,IAAI;YAC/BA;YACA,IAAIA,IAAI,GAAG;gBACT,MAAM,IAAII,MAAM;YAClB;QACF,QAASD,OAAO,KAAM;QACtB,OAAO;YAAED;YAAOG,WAAWL;QAAE;IAC/B;IAEA,IAAIR,SAAS6C;IAEb,yBAAyB;IACzB,IAAIE,QAAQ/C,YAAY,MAAM;QAC5B,MAAM,IAAIY,MAAM;IAClB;IACAZ;IAEA,oBAAoB;IACpB,MAAMiD,cAAcD,qBAAqBhD;IACzC,MAAMkD,cAAcD,YAAYvC,KAAK;IACrCV,UAAUiD,YAAYpC,SAAS;IAE/B,MAAMsC,UAKD,EAAE;IAEP,oBAAoB;IACpB,IAAK,IAAI3C,IAAI,GAAGA,IAAI0C,aAAa1C,IAAK;QACpC,mDAAmD;QACnD,MAAM4C,iBAAiBJ,qBAAqBhD;QAC5CA,UAAUoD,eAAevC,SAAS;QAElC,oBAAoB;QACpB,MAAMwC,qBAAqBL,qBAAqBhD;QAChDA,UAAUqD,mBAAmBxC,SAAS;QAEtCsC,QAAQb,IAAI,CAAC;YACXgB,eAAe;YACfC,cAAcH,eAAe1C,KAAK;YAClC8C,oBAAoB;YACpBC,kBAAkBJ,mBAAmB3C,KAAK;QAC5C;IACF;IAEA,uDAAuD;IACvD,IAAIgD,aAAa,IAAI,sBAAsB;IAC3C,IAAK,IAAIlD,IAAI,GAAGA,IAAI2C,QAAQ/C,MAAM,EAAEI,IAAK;QACvC,MAAMmD,SAASR,OAAO,CAAC3C,EAAE;QACzB,0CAA0C;QAC1CmD,OAAOL,aAAa,GAAGI;QAEvB,6CAA6C;QAC7C,MAAME,gBAAgBb,QAAQW;QAC9B,MAAMlB,aAAa,AAACoB,CAAAA,gBAAgB,CAAA,IAAK;QAEzC,oDAAoD;QACpDD,OAAOH,kBAAkB,GAAGG,OAAOJ,YAAY,GAAGf,aAAaM;QAE/D,gEAAgE;QAChE,MAAMe,aAAaC,KAAKC,IAAI,CAACJ,OAAOJ,YAAY,GAAG,KAAK;QACxDG,cAAcG;IAChB;IAEA,OAAOV;AACT;AAEA;;;CAGC,GACD,SAASa,aAAa3C,KAAa;QAgBf4C;IAflB,kBAAkB;IAClB,IAAI5C,MAAMjB,MAAM,GAAG,MAAM,CAACE,aAAae,OAAO,GAAGlC,WAAW;QAC1D,MAAM,IAAIyB,MAAM;IAClB;IAEA,6BAA6B;IAC7B,MAAMsD,YAAYpE,SAASuB,OAAO,KAAK;IAEvC,kCAAkC;IAClC,MAAM4C,aAAwC;QAC5C,GAAG;QACH,GAAG;QACH,GAAG;QACH,IAAI;IACN;IACA,MAAMnB,aAAYmB,wBAAAA,UAAU,CAACC,UAAU,cAArBD,mCAAAA,wBAAyB;IAE3C,2EAA2E;IAC3E,6CAA6C;IAC7C,IAAIE,YAAY9C,MAAMjB,MAAM;IAC5B,MAAO+D,YAAY,MAAMrE,SAASuB,OAAO8C,YAAY,OAAO,KAAM;QAChEA;IACF;IACA,kDAAkD;IAClD,MAAOA,YAAY,MAAM,KAAKA,YAAY,GAAI;QAC5CA;IACF;IAEA,yCAAyC;IACzC,IAAI,CAAC7D,aAAae,OAAO8C,YAAY,GAAG/E,kBAAkB;QACxD,MAAM,IAAIwB,MAAM;IAClB;IAEA,qEAAqE;IACrE,MAAMwD,iBAAiBjE,aAAakB,OAAO8C,YAAY;IACvD,IAAIC,mBAAmB,MAAM;QAC3B,MAAM,IAAIxD,MAAM;IAClB;IACA,MAAMyD,eAAe,AAACD,CAAAA,iBAAiB,CAAA,IAAK;IAC5C,MAAMvB,aAAasB,YAAY,KAAKE;IAEpC,uCAAuC;IACvC,MAAMC,eAAe1B,WAAWvB,OAAOwB,YAAYC;IAEnD,6DAA6D;IAC7D,IAAIyB,wBAAwB;IAC5B,IAAK,IAAI/D,IAAI,GAAGA,IAAI8D,aAAalE,MAAM,EAAEI,IAAK;QAC5C+D,yBAAyBD,YAAY,CAAC9D,EAAE,CAACiD,gBAAgB;IAC3D;IAEA,mFAAmF;IACnF,kFAAkF;IAClF,MAAMe,uBAAuB,KAAK,MAAM,OAAO;IAE/C,4DAA4D;IAC5D,IAAIF,aAAalE,MAAM,KAAK,KAAKmE,wBAAwBC,sBAAsB;QAC7E,MAAMb,SAASW,YAAY,CAAC,EAAE;QAC9B,MAAMG,cAAcd,OAAOL,aAAa;QACxC,MAAMoB,YAAYtD,iBAAiBC,OAAOoD,aAAa3B;QACvD,MAAML,YAAYgC,cAAcC,UAAUlC,UAAU;QACpD,MAAME,UAAUD,YAAYkB,OAAOH,kBAAkB;QACrD,MAAMmB,iBAAiBtD,MAAMgB,KAAK,CAACI,WAAWC;QAE9C,IAAIkC,cAAc3F,YAAY0F,gBAAgBD,UAAU1C,UAAU,EAAE2B,OAAOF,gBAAgB;QAE3F,IAAK,IAAIoB,IAAIH,UAAU3C,OAAO,CAAC3B,MAAM,GAAG,GAAGyE,KAAK,GAAGA,IAAK;YACtDD,cAAc9D,YAAY8D,aAAaF,UAAU3C,OAAO,CAAC8C,EAAE;QAC7D;QAEA,OAAOD;IACT;IAEA,2EAA2E;IAC3E,MAAME,SAAS,IAAIvG;IAEnB,IAAK,IAAIiC,IAAI,GAAGA,IAAI8D,aAAalE,MAAM,EAAEI,IAAK;QAC5C,MAAMmD,SAASW,YAAY,CAAC9D,EAAE;QAC9B,MAAMiE,cAAcd,OAAOL,aAAa;QAExC,qBAAqB;QACrB,MAAMoB,YAAYtD,iBAAiBC,OAAOoD,aAAa3B;QAEvD,yCAAyC;QACzC,MAAML,YAAYgC,cAAcC,UAAUlC,UAAU;QACpD,MAAME,UAAUD,YAAYkB,OAAOH,kBAAkB;QAErD,0EAA0E;QAC1E,yEAAyE;QACzE,oEAAoE;QACpE,MAAMmB,iBAAiBtD,MAAMgB,KAAK,CAACI,WAAWC;QAE9C,6DAA6D;QAC7D,IAAIkC,cAAc3F,YAAY0F,gBAAgBD,UAAU1C,UAAU,EAAE2B,OAAOF,gBAAgB;QAE3F,+EAA+E;QAC/E,oEAAoE;QACpE,0CAA0C;QAC1C,IAAK,IAAIoB,IAAIH,UAAU3C,OAAO,CAAC3B,MAAM,GAAG,GAAGyE,KAAK,GAAGA,IAAK;YACtDD,cAAc9D,YAAY8D,aAAaF,UAAU3C,OAAO,CAAC8C,EAAE;QAC7D;QAEA,6BAA6B;QAC7BC,OAAOC,MAAM,CAACH;IAChB;IAEA,OAAOE;AACT;AAcA,OAAO,SAASE,SAAS3D,KAAa,EAAE4D,QAA2B;IACjE,MAAMC,SAAS,CAACC;YAUVC;QATJ,MAAMC,WAAW;YACf,IAAI;gBACFF,GAAG,MAAMnB,aAAa3C;YACxB,EAAE,OAAOiE,KAAK;gBACZH,GAAGG;YACL;QACF;QAEA,MAAMF,SAASlG;QACf,IAAIkG,mBAAAA,8BAAAA,aAAAA,OAAQG,EAAE,cAAVH,iCAAAA,WAAYI,UAAU,EAAE;YAC1B,IAAI;gBACF,MAAMC,UAAUL,OAAOG,EAAE,CAACC,UAAU,CAACnE;gBACrC,IAAIoE,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,CAAChF,QAAUyE,GAAG,MAAMzE,QAAsB2E;oBACvD;gBACF;YACF,EAAE,OAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOJ,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIU,QAAQ,CAACC,SAASC,SAAWX,OAAO,CAACI,KAAK5E,QAAW4E,MAAMO,OAAOP,OAAOM,QAAQlF;AAC9F;AAMA;;;;;;CAMC,GACD,OAAO,SAASoF;IACd,MAAMC,aAAa,IAAIxH;IACvB,8CAA8C;IAC9C,MAAM6G,SAASlG;IAEf,oFAAoF;IACpF,MAAM8G,mBAAiCZ,CAAAA,mBAAAA,6BAAAA,OAAQa,KAAK,IAChD,CAAClF,MAAMG,OAAOgF,MAAMf;YAClBC;SAAAA,gBAAAA,OAAOa,KAAK,cAAZb,oCAAAA,mBAAAA,QAAerE,MAAMG,OAAOgF,MAAMR,IAAI,CACpC,CAAC5D,SAAWqD,GAAG,MAAMrD,SACrB,CAACwD,MAAQH,GAAGG;IAEhB,IACA,CAACvE,MAAMG,OAAOgF,MAAMf;QAClB,IAAI;YACFA,GAAG,MAAMlG,YAAY8B,MAAMG,OAAOgF;QACpC,EAAE,OAAOZ,KAAK;YACZH,GAAGG;QACL;IACF;IAEJ,OAAO,IAAI9G,UAAU;QACnB2H,WAAUC,KAAa,EAAEC,SAAiB,EAAEpB,QAAwC;YAClFc,WAAWhB,MAAM,CAACqB;YAClBnB;QACF;QAEAqB,OAAMrB,QAAwC;gBAgC1BhB;YA/BlB,MAAM5C,QAAoB0E;YAE1B,8EAA8E;YAC9E,MAAMhD,UAAU9C,OAAOC,QAAQ,CAACmB,SAAS,CAACrB,SAAmBqB,KAAK,CAACrB,OAAO,GAAG,CAACA,SAAmBqB,MAAMvB,QAAQ,CAACE;YAEhH,MAAMuG,cAActG,OAAOC,QAAQ,CAACmB,SAAS,CAACrB,SAAoBA,SAAS,KAAKA,SAAS,IAAIqB,MAAMjB,MAAM,GAAG,OAAOiB,MAAMlB,YAAY,CAACH,UAAW,CAACA,SAAmBqB,MAAMhB,cAAc,CAACL;YAE1L,MAAMwG,SAAS,CAACxG,QAAgBO;gBAC9B,IAAIP,SAASO,SAASH,MAAM,GAAGiB,MAAMjB,MAAM,EAAE,OAAO;gBACpD,IAAK,IAAII,IAAI,GAAGA,IAAID,SAASH,MAAM,EAAEI,IAAK;oBACxC,IAAIuC,QAAQ/C,SAASQ,OAAOD,QAAQ,CAACC,EAAE,EAAE,OAAO;gBAClD;gBACA,OAAO;YACT;YAEA,2CAA2C;YAC3C,IAAIa,MAAMjB,MAAM,GAAG,MAAM,CAACoG,OAAO,GAAGrH,WAAW;gBAC7C8F,SAAS,IAAIrE,MAAM;gBACnB;YACF;YAEA,6BAA6B;YAC7B,MAAMsD,YAAYnB,QAAQ,KAAK;YAE/B,kCAAkC;YAClC,MAAMkB,aAAwC;gBAC5C,GAAG;gBACH,GAAG;gBACH,GAAG;gBACH,IAAI;YACN;YACA,MAAMnB,aAAYmB,wBAAAA,UAAU,CAACC,UAAU,cAArBD,mCAAAA,wBAAyB;YAE3C,2EAA2E;YAC3E,IAAIE,YAAY9C,MAAMjB,MAAM;YAC5B,MAAO+D,YAAY,MAAMpB,QAAQoB,YAAY,OAAO,KAAM;gBACxDA;YACF;YACA,2BAA2B;YAC3B,MAAOA,YAAY,MAAM,KAAKA,YAAY,GAAI;gBAC5CA;YACF;YAEA,yCAAyC;YACzC,IAAI,CAACqC,OAAOrC,YAAY,GAAG/E,kBAAkB;gBAC3C6F,SAAS,IAAIrE,MAAM;gBACnB;YACF;YAEA,uCAAuC;YACvC,MAAMwD,iBAAiBmC,YAAYpC,YAAY;YAC/C,IAAIC,mBAAmB,MAAM;gBAC3Ba,SAAS,IAAIrE,MAAM;gBACnB;YACF;YACA,MAAMyD,eAAe,AAACD,CAAAA,iBAAiB,CAAA,IAAK;YAC5C,MAAMvB,aAAasB,YAAY,KAAKE;YAEpC,uCAAuC;YACvC,MAAMC,eAAe1B,WAAWvB,OAAOwB,YAAYC;YAEnD,mDAAmD;YACnD,IAAI2D,aAAa;YACjB,MAAMC,YAAY,CAACpB;gBACjB,IAAIA,KAAK;oBACPL,SAASK;oBACT;gBACF;gBAEA,IAAImB,cAAcnC,aAAalE,MAAM,EAAE;oBACrC,+DAA+D;oBAC/D,IAAI,CAACH,OAAOC,QAAQ,CAACmB,QAAQA,MAAMsF,KAAK;oBACxC1B,SAAS;oBACT;gBACF;gBAEA,MAAMtB,SAASW,YAAY,CAACmC,aAAa;gBACzC,MAAMhC,cAAcd,OAAOL,aAAa;gBAExC,oDAAoD;gBACpD,8BAA8B;gBAC9B,MAAMM,gBAAgBb,QAAQ0B;gBAC9B,MAAMjC,aAAa,AAACoB,CAAAA,gBAAgB,CAAA,IAAK;gBAEzC,wCAAwC;gBACxC,MAAMgD,aAAavF,MAAMgB,KAAK,CAACoC,aAAaA,cAAcjC;gBAC1D,MAAMkC,YAAYtD,iBAAiBwF,YAAY,GAAG9D;gBAElD,yCAAyC;gBACzC,MAAML,YAAYgC,cAAcjC;gBAChC,MAAME,UAAUD,YAAYkB,OAAOH,kBAAkB;gBACrD,MAAMmB,iBAAiBtD,MAAMgB,KAAK,CAACI,WAAWC;gBAE9C,4DAA4D;gBAC5DsD,iBAAiBrB,gBAAgBD,UAAU1C,UAAU,EAAE2B,OAAOF,gBAAgB,EAAE,CAACoD,WAAWjC;oBAC1F,IAAIiC,aAAa,CAACjC,aAAa;wBAC7B8B,UAAUG,aAAa,IAAIjG,MAAM;wBACjC;oBACF;oBAEA,+CAA+C;oBAC/C,IAAK,IAAIiE,IAAIH,UAAU3C,OAAO,CAAC3B,MAAM,GAAG,GAAGyE,KAAK,GAAGA,IAAK;wBACtDD,cAAc9D,YAAY8D,aAAaF,UAAU3C,OAAO,CAAC8C,EAAE;oBAC7D;oBAEA,gDAAgD;oBAChD,IAAI,CAACvC,IAAI,CAACsC;oBAEV,2BAA2B;oBAC3B8B,UAAU;gBACZ;YACF;YAEA,0BAA0B;YAC1BA,UAAU;QACZ;IACF;AACF"}
|