xz-compat 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/native.js +64 -11
- package/dist/cjs/native.js.map +1 -1
- package/dist/cjs/xz/Decoder.d.cts +1 -1
- package/dist/cjs/xz/Decoder.d.ts +1 -1
- package/dist/cjs/xz/Decoder.js +139 -8
- package/dist/cjs/xz/Decoder.js.map +1 -1
- package/dist/esm/native.js +52 -4
- package/dist/esm/native.js.map +1 -1
- package/dist/esm/xz/Decoder.d.ts +1 -1
- package/dist/esm/xz/Decoder.js +91 -13
- package/dist/esm/xz/Decoder.js.map +1 -1
- package/package.json +2 -4
package/dist/cjs/native.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Native Acceleration Module
|
|
3
|
+
*
|
|
4
|
+
* Provides optional native acceleration via @napi-rs/lzma on Node.js 14+.
|
|
5
|
+
* Falls back gracefully to pure JS implementation on older Node versions
|
|
6
|
+
* or when the native module is not available.
|
|
7
|
+
*/ "use strict";
|
|
2
8
|
Object.defineProperty(exports, "__esModule", {
|
|
3
9
|
value: true
|
|
4
10
|
});
|
|
@@ -16,16 +22,24 @@ _export(exports, {
|
|
|
16
22
|
return tryLoadNative;
|
|
17
23
|
}
|
|
18
24
|
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
var _module = /*#__PURE__*/ _interop_require_default(require("module"));
|
|
26
|
+
var _path = /*#__PURE__*/ _interop_require_default(require("path"));
|
|
27
|
+
var _url = /*#__PURE__*/ _interop_require_default(require("url"));
|
|
28
|
+
function _interop_require_default(obj) {
|
|
29
|
+
return obj && obj.__esModule ? obj : {
|
|
30
|
+
default: obj
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Get __dirname for ES modules
|
|
34
|
+
var _require = typeof require === 'undefined' ? _module.default.createRequire(require("url").pathToFileURL(__filename).toString()) : require;
|
|
35
|
+
var __dirname = _path.default.dirname(typeof __filename !== 'undefined' ? __filename : _url.default.fileURLToPath(require("url").pathToFileURL(__filename).toString()));
|
|
36
|
+
// Get node_modules path (go up from dist/cjs to package root, then to node_modules)
|
|
37
|
+
var nodeModulesPath = _path.default.join(__dirname, '..', '..', 'node_modules');
|
|
38
|
+
// Cache for native module loading result
|
|
26
39
|
var nativeModule;
|
|
27
40
|
var nodeVersionChecked = false;
|
|
28
41
|
var nodeVersionSupported = false;
|
|
42
|
+
var installationAttempted = false;
|
|
29
43
|
/**
|
|
30
44
|
* Check if Node.js version supports native module (14+)
|
|
31
45
|
*/ function checkNodeVersion() {
|
|
@@ -40,6 +54,31 @@ var nodeVersionSupported = false;
|
|
|
40
54
|
}
|
|
41
55
|
return nodeVersionSupported;
|
|
42
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Install @napi-rs/lzma using install-module-linked
|
|
59
|
+
*/ function installNativeModule(callback) {
|
|
60
|
+
// Only attempt installation once
|
|
61
|
+
if (installationAttempted) {
|
|
62
|
+
callback(new Error('Installation already attempted'));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
installationAttempted = true;
|
|
66
|
+
try {
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
68
|
+
var installModule = _require('install-module-linked').default;
|
|
69
|
+
console.log('Installing @napi-rs/lzma for native acceleration...');
|
|
70
|
+
installModule('@napi-rs/lzma', nodeModulesPath, {}, function(err) {
|
|
71
|
+
if (err) {
|
|
72
|
+
console.warn('Failed to install @napi-rs/lzma:', err.message);
|
|
73
|
+
} else {
|
|
74
|
+
console.log('Successfully installed @napi-rs/lzma');
|
|
75
|
+
}
|
|
76
|
+
callback(err);
|
|
77
|
+
});
|
|
78
|
+
} catch (err) {
|
|
79
|
+
callback(err);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
43
82
|
function tryLoadNative() {
|
|
44
83
|
// Return cached result
|
|
45
84
|
if (nativeModule !== undefined) return nativeModule;
|
|
@@ -48,17 +87,31 @@ function tryLoadNative() {
|
|
|
48
87
|
nativeModule = null;
|
|
49
88
|
return null;
|
|
50
89
|
}
|
|
51
|
-
// Try to load native module
|
|
90
|
+
// Try to load native module (it should be installed at module load time)
|
|
52
91
|
try {
|
|
53
|
-
// Use require to load optional dependency
|
|
54
92
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
55
|
-
nativeModule =
|
|
93
|
+
nativeModule = _require('@napi-rs/lzma');
|
|
56
94
|
return nativeModule;
|
|
57
95
|
} catch (unused) {
|
|
96
|
+
// Module not installed yet - return null
|
|
58
97
|
nativeModule = null;
|
|
59
98
|
return null;
|
|
60
99
|
}
|
|
61
100
|
}
|
|
101
|
+
// At module load time, attempt to install @napi-rs/lzma on Node 14+
|
|
102
|
+
// This is done asynchronously so it doesn't block module initialization
|
|
103
|
+
if (checkNodeVersion()) {
|
|
104
|
+
installNativeModule(function() {
|
|
105
|
+
// Installation complete - clear cache and try to load
|
|
106
|
+
nativeModule = undefined; // Clear cache to force re-check
|
|
107
|
+
try {
|
|
108
|
+
nativeModule = _require('@napi-rs/lzma');
|
|
109
|
+
} catch (unused) {
|
|
110
|
+
// Module still not available
|
|
111
|
+
nativeModule = null;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
62
115
|
function isNativeAvailable() {
|
|
63
116
|
return tryLoadNative() !== null;
|
|
64
117
|
}
|
package/dist/cjs/native.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/native.ts"],"sourcesContent":["/**\n * Native Acceleration Module\n *\n * Provides optional native acceleration via @napi-rs/lzma on Node.js 14+.\n * Falls back gracefully to pure JS implementation on older Node versions\n * or when the native module is not available.\n */\n\n// Cache for native module loading result\nlet nativeModule: NativeModule | null | undefined;\nlet nodeVersionChecked = false;\nlet nodeVersionSupported = false;\n\ninterface NativeModule {\n xz: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n lzma: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n lzma2: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n}\n\n/**\n * Check if Node.js version supports native module (14+)\n */\nfunction checkNodeVersion(): boolean {\n if (nodeVersionChecked) return nodeVersionSupported;\n nodeVersionChecked = true;\n\n try {\n const version = process.versions.node;\n const major = parseInt(version.split('.')[0], 10);\n nodeVersionSupported = major >= 14;\n } catch {\n nodeVersionSupported = false;\n }\n\n return nodeVersionSupported;\n}\n\n/**\n * Try to load the native @napi-rs/lzma module\n * Returns null if not available or Node version is too old\n */\nexport function tryLoadNative(): NativeModule | null {\n // Return cached result\n if (nativeModule !== undefined) return nativeModule;\n\n // Check Node version first\n if (!checkNodeVersion()) {\n nativeModule = null;\n return null;\n }\n\n // Try to load native module
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/native.ts"],"sourcesContent":["/**\n * Native Acceleration Module\n *\n * Provides optional native acceleration via @napi-rs/lzma on Node.js 14+.\n * Falls back gracefully to pure JS implementation on older Node versions\n * or when the native module is not available.\n */\n\nimport Module from 'module';\nimport path from 'path';\nimport url from 'url';\n\n// Get __dirname for ES modules\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\nconst __dirname = path.dirname(typeof __filename !== 'undefined' ? __filename : url.fileURLToPath(import.meta.url));\n\n// Get node_modules path (go up from dist/cjs to package root, then to node_modules)\nconst nodeModulesPath = path.join(__dirname, '..', '..', 'node_modules');\n\n// Cache for native module loading result\nlet nativeModule: NativeModule | null | undefined;\nlet nodeVersionChecked = false;\nlet nodeVersionSupported = false;\nlet installationAttempted = false;\n\ninterface NativeModule {\n xz: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n lzma: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n lzma2: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n}\n\n/**\n * Check if Node.js version supports native module (14+)\n */\nfunction checkNodeVersion(): boolean {\n if (nodeVersionChecked) return nodeVersionSupported;\n nodeVersionChecked = true;\n\n try {\n const version = process.versions.node;\n const major = parseInt(version.split('.')[0], 10);\n nodeVersionSupported = major >= 14;\n } catch {\n nodeVersionSupported = false;\n }\n\n return nodeVersionSupported;\n}\n\n/**\n * Install @napi-rs/lzma using install-module-linked\n */\nfunction installNativeModule(callback: (err: Error | null) => void): void {\n // Only attempt installation once\n if (installationAttempted) {\n callback(new Error('Installation already attempted'));\n return;\n }\n installationAttempted = true;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const installModule = _require('install-module-linked').default;\n\n console.log('Installing @napi-rs/lzma for native acceleration...');\n installModule('@napi-rs/lzma', nodeModulesPath, {}, (err: Error | null) => {\n if (err) {\n console.warn('Failed to install @napi-rs/lzma:', err.message);\n } else {\n console.log('Successfully installed @napi-rs/lzma');\n }\n callback(err);\n });\n } catch (err) {\n callback(err as Error);\n }\n}\n\n/**\n * Try to load the native @napi-rs/lzma module\n * Returns null if not available or Node version is too old\n */\nexport function tryLoadNative(): NativeModule | null {\n // Return cached result\n if (nativeModule !== undefined) return nativeModule;\n\n // Check Node version first\n if (!checkNodeVersion()) {\n nativeModule = null;\n return null;\n }\n\n // Try to load native module (it should be installed at module load time)\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n nativeModule = _require('@napi-rs/lzma') as NativeModule;\n return nativeModule;\n } catch {\n // Module not installed yet - return null\n nativeModule = null;\n return null;\n }\n}\n\n// At module load time, attempt to install @napi-rs/lzma on Node 14+\n// This is done asynchronously so it doesn't block module initialization\nif (checkNodeVersion()) {\n installNativeModule(() => {\n // Installation complete - clear cache and try to load\n nativeModule = undefined; // Clear cache to force re-check\n try {\n nativeModule = _require('@napi-rs/lzma') as NativeModule;\n } catch {\n // Module still not available\n nativeModule = null;\n }\n });\n}\n\n/**\n * Check if native acceleration is available\n */\nexport function isNativeAvailable(): boolean {\n return tryLoadNative() !== null;\n}\n"],"names":["isNativeAvailable","tryLoadNative","_require","require","Module","createRequire","__dirname","path","dirname","__filename","url","fileURLToPath","nodeModulesPath","join","nativeModule","nodeVersionChecked","nodeVersionSupported","installationAttempted","checkNodeVersion","version","process","versions","node","major","parseInt","split","installNativeModule","callback","Error","installModule","default","console","log","err","warn","message","undefined"],"mappings":"AAAA;;;;;;CAMC;;;;;;;;;;;QA6HeA;eAAAA;;QAxCAC;eAAAA;;;6DAnFG;2DACF;0DACD;;;;;;AAEhB,+BAA+B;AAC/B,IAAMC,WAAW,OAAOC,YAAY,cAAcC,eAAM,CAACC,aAAa,CAAC,uDAAmBF;AAC1F,IAAMG,YAAYC,aAAI,CAACC,OAAO,CAAC,OAAOC,eAAe,cAAcA,aAAaC,YAAG,CAACC,aAAa,CAAC;AAElG,oFAAoF;AACpF,IAAMC,kBAAkBL,aAAI,CAACM,IAAI,CAACP,WAAW,MAAM,MAAM;AAEzD,yCAAyC;AACzC,IAAIQ;AACJ,IAAIC,qBAAqB;AACzB,IAAIC,uBAAuB;AAC3B,IAAIC,wBAAwB;AAiB5B;;CAEC,GACD,SAASC;IACP,IAAIH,oBAAoB,OAAOC;IAC/BD,qBAAqB;IAErB,IAAI;QACF,IAAMI,UAAUC,QAAQC,QAAQ,CAACC,IAAI;QACrC,IAAMC,QAAQC,SAASL,QAAQM,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE;QAC9CT,uBAAuBO,SAAS;IAClC,EAAE,eAAM;QACNP,uBAAuB;IACzB;IAEA,OAAOA;AACT;AAEA;;CAEC,GACD,SAASU,oBAAoBC,QAAqC;IAChE,iCAAiC;IACjC,IAAIV,uBAAuB;QACzBU,SAAS,IAAIC,MAAM;QACnB;IACF;IACAX,wBAAwB;IAExB,IAAI;QACF,8DAA8D;QAC9D,IAAMY,gBAAgB3B,SAAS,yBAAyB4B,OAAO;QAE/DC,QAAQC,GAAG,CAAC;QACZH,cAAc,iBAAiBjB,iBAAiB,CAAC,GAAG,SAACqB;YACnD,IAAIA,KAAK;gBACPF,QAAQG,IAAI,CAAC,oCAAoCD,IAAIE,OAAO;YAC9D,OAAO;gBACLJ,QAAQC,GAAG,CAAC;YACd;YACAL,SAASM;QACX;IACF,EAAE,OAAOA,KAAK;QACZN,SAASM;IACX;AACF;AAMO,SAAShC;IACd,uBAAuB;IACvB,IAAIa,iBAAiBsB,WAAW,OAAOtB;IAEvC,2BAA2B;IAC3B,IAAI,CAACI,oBAAoB;QACvBJ,eAAe;QACf,OAAO;IACT;IAEA,yEAAyE;IACzE,IAAI;QACF,iEAAiE;QACjEA,eAAeZ,SAAS;QACxB,OAAOY;IACT,EAAE,eAAM;QACN,yCAAyC;QACzCA,eAAe;QACf,OAAO;IACT;AACF;AAEA,oEAAoE;AACpE,wEAAwE;AACxE,IAAII,oBAAoB;IACtBQ,oBAAoB;QAClB,sDAAsD;QACtDZ,eAAesB,WAAW,gCAAgC;QAC1D,IAAI;YACFtB,eAAeZ,SAAS;QAC1B,EAAE,eAAM;YACN,6BAA6B;YAC7BY,eAAe;QACjB;IACF;AACF;AAKO,SAASd;IACd,OAAOC,oBAAoB;AAC7B"}
|
|
@@ -22,7 +22,7 @@ import type { Transform as TransformType } from 'stream';
|
|
|
22
22
|
/**
|
|
23
23
|
* Decompress XZ data synchronously
|
|
24
24
|
* Uses @napi-rs/lzma if available on Node 14+, falls back to pure JS
|
|
25
|
-
* Properly handles multi-block XZ files and
|
|
25
|
+
* Properly handles multi-block XZ files, stream padding, and concatenated streams
|
|
26
26
|
* @param input - XZ compressed data
|
|
27
27
|
* @returns Decompressed data
|
|
28
28
|
*/
|
package/dist/cjs/xz/Decoder.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ import type { Transform as TransformType } from 'stream';
|
|
|
22
22
|
/**
|
|
23
23
|
* Decompress XZ data synchronously
|
|
24
24
|
* Uses @napi-rs/lzma if available on Node 14+, falls back to pure JS
|
|
25
|
-
* Properly handles multi-block XZ files and
|
|
25
|
+
* Properly handles multi-block XZ files, stream padding, and concatenated streams
|
|
26
26
|
* @param input - XZ compressed data
|
|
27
27
|
* @returns Decompressed data
|
|
28
28
|
*/
|
package/dist/cjs/xz/Decoder.js
CHANGED
|
@@ -46,6 +46,58 @@ var _BcjSparcts = require("../filters/bcj/BcjSparc.js");
|
|
|
46
46
|
var _Deltats = require("../filters/delta/Delta.js");
|
|
47
47
|
var _indexts = require("../lzma/index.js");
|
|
48
48
|
var _nativets = require("../native.js");
|
|
49
|
+
function _define_property(obj, key, value) {
|
|
50
|
+
if (key in obj) {
|
|
51
|
+
Object.defineProperty(obj, key, {
|
|
52
|
+
value: value,
|
|
53
|
+
enumerable: true,
|
|
54
|
+
configurable: true,
|
|
55
|
+
writable: true
|
|
56
|
+
});
|
|
57
|
+
} else {
|
|
58
|
+
obj[key] = value;
|
|
59
|
+
}
|
|
60
|
+
return obj;
|
|
61
|
+
}
|
|
62
|
+
function _object_spread(target) {
|
|
63
|
+
for(var i = 1; i < arguments.length; i++){
|
|
64
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
65
|
+
var ownKeys = Object.keys(source);
|
|
66
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
67
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
68
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
ownKeys.forEach(function(key) {
|
|
72
|
+
_define_property(target, key, source[key]);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return target;
|
|
76
|
+
}
|
|
77
|
+
function ownKeys(object, enumerableOnly) {
|
|
78
|
+
var keys = Object.keys(object);
|
|
79
|
+
if (Object.getOwnPropertySymbols) {
|
|
80
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
81
|
+
if (enumerableOnly) {
|
|
82
|
+
symbols = symbols.filter(function(sym) {
|
|
83
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
keys.push.apply(keys, symbols);
|
|
87
|
+
}
|
|
88
|
+
return keys;
|
|
89
|
+
}
|
|
90
|
+
function _object_spread_props(target, source) {
|
|
91
|
+
source = source != null ? source : {};
|
|
92
|
+
if (Object.getOwnPropertyDescriptors) {
|
|
93
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
94
|
+
} else {
|
|
95
|
+
ownKeys(Object(source)).forEach(function(key) {
|
|
96
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return target;
|
|
100
|
+
}
|
|
49
101
|
// XZ magic bytes
|
|
50
102
|
var XZ_MAGIC = [
|
|
51
103
|
0xfd,
|
|
@@ -244,13 +296,10 @@ var FILTER_LZMA2 = 0x21;
|
|
|
244
296
|
}
|
|
245
297
|
return records;
|
|
246
298
|
}
|
|
247
|
-
|
|
299
|
+
/**
|
|
300
|
+
* Pure JS XZ decompression (handles all XZ spec features)
|
|
301
|
+
*/ function decodeXZPure(input) {
|
|
248
302
|
var _checkSizes_checkType;
|
|
249
|
-
// Try native acceleration first (Node 14+ with @napi-rs/lzma installed)
|
|
250
|
-
var native = (0, _nativets.tryLoadNative)();
|
|
251
|
-
if (native) {
|
|
252
|
-
return native.xz.decompressSync(input);
|
|
253
|
-
}
|
|
254
303
|
// Verify XZ magic
|
|
255
304
|
if (input.length < 12 || !bufferEquals(input, 0, XZ_MAGIC)) {
|
|
256
305
|
throw new Error('Invalid XZ magic bytes');
|
|
@@ -313,6 +362,70 @@ function decodeXZ(input) {
|
|
|
313
362
|
}
|
|
314
363
|
return Buffer.concat(outputChunks);
|
|
315
364
|
}
|
|
365
|
+
function decodeXZ(input) {
|
|
366
|
+
// Try native acceleration first (Node 14+ with @napi-rs/lzma installed)
|
|
367
|
+
var native = (0, _nativets.tryLoadNative)();
|
|
368
|
+
if (native) {
|
|
369
|
+
try {
|
|
370
|
+
return native.xz.decompressSync(input);
|
|
371
|
+
} catch (nativeErr) {
|
|
372
|
+
// Native failed - try pure JS (handles more edge cases like
|
|
373
|
+
// stream padding, concatenated streams, SHA-256 checksums)
|
|
374
|
+
try {
|
|
375
|
+
return decodeXZPure(input);
|
|
376
|
+
} catch (unused) {
|
|
377
|
+
// Both failed - throw the native error (usually more informative)
|
|
378
|
+
throw nativeErr;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return decodeXZPure(input);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Parse XZ stream to get block information (without decompressing)
|
|
386
|
+
* This allows streaming decompression by processing blocks one at a time.
|
|
387
|
+
*/ function parseXZIndex(input) {
|
|
388
|
+
var _checkSizes_checkType;
|
|
389
|
+
// Stream header validation
|
|
390
|
+
if (input.length < 12) {
|
|
391
|
+
throw new Error('XZ file too small');
|
|
392
|
+
}
|
|
393
|
+
// Stream magic bytes (0xFD, '7zXZ', 0x00)
|
|
394
|
+
if (input[0] !== 0xfd || input[1] !== 0x37 || input[2] !== 0x7a || input[3] !== 0x58 || input[4] !== 0x5a || input[5] !== 0x00) {
|
|
395
|
+
throw new Error('Invalid XZ magic bytes');
|
|
396
|
+
}
|
|
397
|
+
// Stream flags at offset 6-7
|
|
398
|
+
var checkType = input[7] & 0x0f;
|
|
399
|
+
// Check sizes based on check type
|
|
400
|
+
var checkSizes = {
|
|
401
|
+
0: 0,
|
|
402
|
+
1: 4,
|
|
403
|
+
4: 8,
|
|
404
|
+
10: 32
|
|
405
|
+
};
|
|
406
|
+
var checkSize = (_checkSizes_checkType = checkSizes[checkType]) !== null && _checkSizes_checkType !== void 0 ? _checkSizes_checkType : 0;
|
|
407
|
+
// Find footer by skipping stream padding
|
|
408
|
+
var footerEnd = input.length;
|
|
409
|
+
while(footerEnd > 12 && input[footerEnd - 1] === 0x00){
|
|
410
|
+
footerEnd--;
|
|
411
|
+
}
|
|
412
|
+
while(footerEnd % 4 !== 0 && footerEnd > 12){
|
|
413
|
+
footerEnd++;
|
|
414
|
+
}
|
|
415
|
+
// Verify footer magic
|
|
416
|
+
if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {
|
|
417
|
+
throw new Error('Invalid XZ footer magic');
|
|
418
|
+
}
|
|
419
|
+
// Get backward size
|
|
420
|
+
var backwardSize = (input.readUInt32LE(footerEnd - 8) + 1) * 4;
|
|
421
|
+
var indexStart = footerEnd - 12 - backwardSize;
|
|
422
|
+
// Parse Index to get block information
|
|
423
|
+
return parseIndex(input, indexStart, checkSize).map(function(record) {
|
|
424
|
+
return _object_spread_props(_object_spread({}, record), {
|
|
425
|
+
checkSize: checkSize
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
}
|
|
316
429
|
function createXZDecoder() {
|
|
317
430
|
var chunks = [];
|
|
318
431
|
return new _extractbaseiterator.Transform({
|
|
@@ -323,8 +436,26 @@ function createXZDecoder() {
|
|
|
323
436
|
flush: function flush(callback) {
|
|
324
437
|
try {
|
|
325
438
|
var input = Buffer.concat(chunks);
|
|
326
|
-
|
|
327
|
-
|
|
439
|
+
// Stream decode each block instead of buffering all output
|
|
440
|
+
var blockRecords = parseXZIndex(input);
|
|
441
|
+
for(var i = 0; i < blockRecords.length; i++){
|
|
442
|
+
var record = blockRecords[i];
|
|
443
|
+
var recordStart = record.compressedPos;
|
|
444
|
+
// Parse block header
|
|
445
|
+
var blockInfo = parseBlockHeader(input, recordStart, blockRecords[i].checkSize);
|
|
446
|
+
// Extract compressed data for this block
|
|
447
|
+
var dataStart = recordStart + blockInfo.headerSize;
|
|
448
|
+
var dataEnd = dataStart + record.compressedDataSize;
|
|
449
|
+
var compressedData = input.slice(dataStart, dataEnd);
|
|
450
|
+
// Decompress this block
|
|
451
|
+
var blockOutput = (0, _indexts.decodeLzma2)(compressedData, blockInfo.lzma2Props, record.uncompressedSize);
|
|
452
|
+
// Apply preprocessing filters in reverse order
|
|
453
|
+
for(var j = blockInfo.filters.length - 1; j >= 0; j--){
|
|
454
|
+
blockOutput = applyFilter(blockOutput, blockInfo.filters[j]);
|
|
455
|
+
}
|
|
456
|
+
// Push block output immediately instead of buffering
|
|
457
|
+
this.push(blockOutput);
|
|
458
|
+
}
|
|
328
459
|
callback();
|
|
329
460
|
} catch (err) {
|
|
330
461
|
callback(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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 { 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';\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/**\n * Simple buffer comparison\n */\nfunction bufferEquals(buf: Buffer, 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 (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 * Returns number, but limits to 32-bit to work on Node 0.8+\n */\nfunction decodeMultibyte(buf: Buffer, 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 = buf[offset + i];\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n // Reduced to prevent overflow on Node 0.8\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 *\n * XZ Index stores \"Unpadded Size\" for each block which equals:\n * Block Header Size + Compressed Data Size + Check Size\n * (does NOT include padding to 4-byte boundary)\n */\nfunction parseIndex(\n input: Buffer,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (input[offset] !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyte(input, 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 = decodeMultibyte(input, offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyte(input, 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 = input[currentPos];\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n // unpaddedSize = headerSize + compressedDataSize + checkSize\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 * Decompress XZ data synchronously\n * Uses @napi-rs/lzma if available on Node 14+, falls back to pure JS\n * Properly handles multi-block XZ files and stream padding\n * @param input - XZ compressed data\n * @returns Decompressed data\n */\nexport function decodeXZ(input: Buffer): Buffer {\n // Try native acceleration first (Node 14+ with @napi-rs/lzma installed)\n const native = tryLoadNative();\n if (native) {\n return native.xz.decompressSync(input);\n }\n\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 = 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 && 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 backwardSize = (input.readUInt32LE(footerEnd - 8) + 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 each block\n const outputChunks: Buffer[] = [];\n let _totalOutputSize = 0;\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 // compressedDataSize is calculated from the Index's Unpadded Size minus header and check\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 outputChunks.push(blockOutput);\n _totalOutputSize += blockOutput.length;\n }\n\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n */\nexport function createXZDecoder(): TransformType {\n const chunks: Buffer[] = [];\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n chunks.push(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n try {\n const input = Buffer.concat(chunks);\n const output = decodeXZ(input);\n this.push(output);\n callback();\n } catch (err) {\n callback(err as Error);\n }\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","bufferEquals","buf","offset","expected","length","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","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","checkSizes","native","tryLoadNative","xz","decompressSync","checkType","footerEnd","backwardSize","readUInt32LE","blockRecords","outputChunks","_totalOutputSize","recordStart","blockInfo","compressedData","blockOutput","decodeLzma2","j","Buffer","concat","chunks","Transform","transform","chunk","_encoding","callback","flush","output","err"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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 { 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';\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/**\n * Simple buffer comparison\n */\nfunction bufferEquals(buf: Buffer, 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 (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 * Returns number, but limits to 32-bit to work on Node 0.8+\n */\nfunction decodeMultibyte(buf: Buffer, 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 = buf[offset + i];\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n // Reduced to prevent overflow on Node 0.8\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 *\n * XZ Index stores \"Unpadded Size\" for each block which equals:\n * Block Header Size + Compressed Data Size + Check Size\n * (does NOT include padding to 4-byte boundary)\n */\nfunction parseIndex(\n input: Buffer,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (input[offset] !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyte(input, 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 = decodeMultibyte(input, offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyte(input, 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 = input[currentPos];\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n // unpaddedSize = headerSize + compressedDataSize + checkSize\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 */\nfunction decodeXZPure(input: Buffer): Buffer {\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 = 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 && 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 backwardSize = (input.readUInt32LE(footerEnd - 8) + 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 each block\n const outputChunks: Buffer[] = [];\n let _totalOutputSize = 0;\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 // compressedDataSize is calculated from the Index's Unpadded Size minus header and check\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 outputChunks.push(blockOutput);\n _totalOutputSize += blockOutput.length;\n }\n\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Decompress XZ data synchronously\n * Uses @napi-rs/lzma if available on Node 14+, falls back to pure JS\n * Properly handles multi-block XZ files, stream padding, and concatenated streams\n * @param input - XZ compressed data\n * @returns Decompressed data\n */\nexport function decodeXZ(input: Buffer): Buffer {\n // Try native acceleration first (Node 14+ with @napi-rs/lzma installed)\n const native = tryLoadNative();\n if (native) {\n try {\n return native.xz.decompressSync(input);\n } catch (nativeErr) {\n // Native failed - try pure JS (handles more edge cases like\n // stream padding, concatenated streams, SHA-256 checksums)\n try {\n return decodeXZPure(input);\n } catch {\n // Both failed - throw the native error (usually more informative)\n throw nativeErr;\n }\n }\n }\n return decodeXZPure(input);\n}\n\n/**\n * Parse XZ stream to get block information (without decompressing)\n * This allows streaming decompression by processing blocks one at a time.\n */\nfunction parseXZIndex(input: Buffer): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n checkSize: number;\n}> {\n // Stream header validation\n if (input.length < 12) {\n throw new Error('XZ file too small');\n }\n\n // Stream magic bytes (0xFD, '7zXZ', 0x00)\n if (input[0] !== 0xfd || input[1] !== 0x37 || input[2] !== 0x7a || input[3] !== 0x58 || input[4] !== 0x5a || input[5] !== 0x00) {\n throw new Error('Invalid XZ magic bytes');\n }\n\n // Stream flags at offset 6-7\n const checkType = 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\n let footerEnd = input.length;\n while (footerEnd > 12 && input[footerEnd - 1] === 0x00) {\n footerEnd--;\n }\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic\n if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {\n throw new Error('Invalid XZ footer magic');\n }\n\n // Get backward size\n const backwardSize = (input.readUInt32LE(footerEnd - 8) + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n return parseIndex(input, indexStart, checkSize).map((record) => ({\n ...record,\n checkSize,\n }));\n}\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n */\nexport function createXZDecoder(): TransformType {\n const chunks: Buffer[] = [];\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n chunks.push(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n try {\n const input = Buffer.concat(chunks);\n\n // Stream decode each block instead of buffering all output\n const blockRecords = parseXZIndex(input);\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, blockRecords[i].checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + blockInfo.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 block output immediately instead of buffering\n this.push(blockOutput);\n }\n\n callback();\n } catch (err) {\n callback(err as Error);\n }\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","bufferEquals","buf","offset","expected","length","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","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","decodeXZPure","checkSizes","checkType","footerEnd","backwardSize","readUInt32LE","blockRecords","outputChunks","_totalOutputSize","recordStart","blockInfo","compressedData","blockOutput","decodeLzma2","j","Buffer","concat","native","tryLoadNative","xz","decompressSync","nativeErr","parseXZIndex","map","chunks","Transform","transform","chunk","_encoding","callback","flush","err"],"mappings":"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"}
|
package/dist/esm/native.js
CHANGED
|
@@ -4,10 +4,19 @@
|
|
|
4
4
|
* Provides optional native acceleration via @napi-rs/lzma on Node.js 14+.
|
|
5
5
|
* Falls back gracefully to pure JS implementation on older Node versions
|
|
6
6
|
* or when the native module is not available.
|
|
7
|
-
*/
|
|
7
|
+
*/ import Module from 'module';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
import url from 'url';
|
|
10
|
+
// Get __dirname for ES modules
|
|
11
|
+
const _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;
|
|
12
|
+
const __dirname = path.dirname(typeof __filename !== 'undefined' ? __filename : url.fileURLToPath(import.meta.url));
|
|
13
|
+
// Get node_modules path (go up from dist/cjs to package root, then to node_modules)
|
|
14
|
+
const nodeModulesPath = path.join(__dirname, '..', '..', 'node_modules');
|
|
15
|
+
// Cache for native module loading result
|
|
8
16
|
let nativeModule;
|
|
9
17
|
let nodeVersionChecked = false;
|
|
10
18
|
let nodeVersionSupported = false;
|
|
19
|
+
let installationAttempted = false;
|
|
11
20
|
/**
|
|
12
21
|
* Check if Node.js version supports native module (14+)
|
|
13
22
|
*/ function checkNodeVersion() {
|
|
@@ -22,6 +31,31 @@ let nodeVersionSupported = false;
|
|
|
22
31
|
}
|
|
23
32
|
return nodeVersionSupported;
|
|
24
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Install @napi-rs/lzma using install-module-linked
|
|
36
|
+
*/ function installNativeModule(callback) {
|
|
37
|
+
// Only attempt installation once
|
|
38
|
+
if (installationAttempted) {
|
|
39
|
+
callback(new Error('Installation already attempted'));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
installationAttempted = true;
|
|
43
|
+
try {
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
45
|
+
const installModule = _require('install-module-linked').default;
|
|
46
|
+
console.log('Installing @napi-rs/lzma for native acceleration...');
|
|
47
|
+
installModule('@napi-rs/lzma', nodeModulesPath, {}, (err)=>{
|
|
48
|
+
if (err) {
|
|
49
|
+
console.warn('Failed to install @napi-rs/lzma:', err.message);
|
|
50
|
+
} else {
|
|
51
|
+
console.log('Successfully installed @napi-rs/lzma');
|
|
52
|
+
}
|
|
53
|
+
callback(err);
|
|
54
|
+
});
|
|
55
|
+
} catch (err) {
|
|
56
|
+
callback(err);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
25
59
|
/**
|
|
26
60
|
* Try to load the native @napi-rs/lzma module
|
|
27
61
|
* Returns null if not available or Node version is too old
|
|
@@ -33,17 +67,31 @@ let nodeVersionSupported = false;
|
|
|
33
67
|
nativeModule = null;
|
|
34
68
|
return null;
|
|
35
69
|
}
|
|
36
|
-
// Try to load native module
|
|
70
|
+
// Try to load native module (it should be installed at module load time)
|
|
37
71
|
try {
|
|
38
|
-
// Use require to load optional dependency
|
|
39
72
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
40
|
-
nativeModule =
|
|
73
|
+
nativeModule = _require('@napi-rs/lzma');
|
|
41
74
|
return nativeModule;
|
|
42
75
|
} catch {
|
|
76
|
+
// Module not installed yet - return null
|
|
43
77
|
nativeModule = null;
|
|
44
78
|
return null;
|
|
45
79
|
}
|
|
46
80
|
}
|
|
81
|
+
// At module load time, attempt to install @napi-rs/lzma on Node 14+
|
|
82
|
+
// This is done asynchronously so it doesn't block module initialization
|
|
83
|
+
if (checkNodeVersion()) {
|
|
84
|
+
installNativeModule(()=>{
|
|
85
|
+
// Installation complete - clear cache and try to load
|
|
86
|
+
nativeModule = undefined; // Clear cache to force re-check
|
|
87
|
+
try {
|
|
88
|
+
nativeModule = _require('@napi-rs/lzma');
|
|
89
|
+
} catch {
|
|
90
|
+
// Module still not available
|
|
91
|
+
nativeModule = null;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
47
95
|
/**
|
|
48
96
|
* Check if native acceleration is available
|
|
49
97
|
*/ export function isNativeAvailable() {
|
package/dist/esm/native.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/native.ts"],"sourcesContent":["/**\n * Native Acceleration Module\n *\n * Provides optional native acceleration via @napi-rs/lzma on Node.js 14+.\n * Falls back gracefully to pure JS implementation on older Node versions\n * or when the native module is not available.\n */\n\n// Cache for native module loading result\nlet nativeModule: NativeModule | null | undefined;\nlet nodeVersionChecked = false;\nlet nodeVersionSupported = false;\n\ninterface NativeModule {\n xz: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n lzma: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n lzma2: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n}\n\n/**\n * Check if Node.js version supports native module (14+)\n */\nfunction checkNodeVersion(): boolean {\n if (nodeVersionChecked) return nodeVersionSupported;\n nodeVersionChecked = true;\n\n try {\n const version = process.versions.node;\n const major = parseInt(version.split('.')[0], 10);\n nodeVersionSupported = major >= 14;\n } catch {\n nodeVersionSupported = false;\n }\n\n return nodeVersionSupported;\n}\n\n/**\n * Try to load the native @napi-rs/lzma module\n * Returns null if not available or Node version is too old\n */\nexport function tryLoadNative(): NativeModule | null {\n // Return cached result\n if (nativeModule !== undefined) return nativeModule;\n\n // Check Node version first\n if (!checkNodeVersion()) {\n nativeModule = null;\n return null;\n }\n\n // Try to load native module
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/native.ts"],"sourcesContent":["/**\n * Native Acceleration Module\n *\n * Provides optional native acceleration via @napi-rs/lzma on Node.js 14+.\n * Falls back gracefully to pure JS implementation on older Node versions\n * or when the native module is not available.\n */\n\nimport Module from 'module';\nimport path from 'path';\nimport url from 'url';\n\n// Get __dirname for ES modules\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\nconst __dirname = path.dirname(typeof __filename !== 'undefined' ? __filename : url.fileURLToPath(import.meta.url));\n\n// Get node_modules path (go up from dist/cjs to package root, then to node_modules)\nconst nodeModulesPath = path.join(__dirname, '..', '..', 'node_modules');\n\n// Cache for native module loading result\nlet nativeModule: NativeModule | null | undefined;\nlet nodeVersionChecked = false;\nlet nodeVersionSupported = false;\nlet installationAttempted = false;\n\ninterface NativeModule {\n xz: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n lzma: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n lzma2: {\n decompressSync(input: Uint8Array): Buffer;\n decompress(input: Uint8Array, signal?: AbortSignal | null): Promise<Buffer>;\n };\n}\n\n/**\n * Check if Node.js version supports native module (14+)\n */\nfunction checkNodeVersion(): boolean {\n if (nodeVersionChecked) return nodeVersionSupported;\n nodeVersionChecked = true;\n\n try {\n const version = process.versions.node;\n const major = parseInt(version.split('.')[0], 10);\n nodeVersionSupported = major >= 14;\n } catch {\n nodeVersionSupported = false;\n }\n\n return nodeVersionSupported;\n}\n\n/**\n * Install @napi-rs/lzma using install-module-linked\n */\nfunction installNativeModule(callback: (err: Error | null) => void): void {\n // Only attempt installation once\n if (installationAttempted) {\n callback(new Error('Installation already attempted'));\n return;\n }\n installationAttempted = true;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const installModule = _require('install-module-linked').default;\n\n console.log('Installing @napi-rs/lzma for native acceleration...');\n installModule('@napi-rs/lzma', nodeModulesPath, {}, (err: Error | null) => {\n if (err) {\n console.warn('Failed to install @napi-rs/lzma:', err.message);\n } else {\n console.log('Successfully installed @napi-rs/lzma');\n }\n callback(err);\n });\n } catch (err) {\n callback(err as Error);\n }\n}\n\n/**\n * Try to load the native @napi-rs/lzma module\n * Returns null if not available or Node version is too old\n */\nexport function tryLoadNative(): NativeModule | null {\n // Return cached result\n if (nativeModule !== undefined) return nativeModule;\n\n // Check Node version first\n if (!checkNodeVersion()) {\n nativeModule = null;\n return null;\n }\n\n // Try to load native module (it should be installed at module load time)\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n nativeModule = _require('@napi-rs/lzma') as NativeModule;\n return nativeModule;\n } catch {\n // Module not installed yet - return null\n nativeModule = null;\n return null;\n }\n}\n\n// At module load time, attempt to install @napi-rs/lzma on Node 14+\n// This is done asynchronously so it doesn't block module initialization\nif (checkNodeVersion()) {\n installNativeModule(() => {\n // Installation complete - clear cache and try to load\n nativeModule = undefined; // Clear cache to force re-check\n try {\n nativeModule = _require('@napi-rs/lzma') as NativeModule;\n } catch {\n // Module still not available\n nativeModule = null;\n }\n });\n}\n\n/**\n * Check if native acceleration is available\n */\nexport function isNativeAvailable(): boolean {\n return tryLoadNative() !== null;\n}\n"],"names":["Module","path","url","_require","require","createRequire","__dirname","dirname","__filename","fileURLToPath","nodeModulesPath","join","nativeModule","nodeVersionChecked","nodeVersionSupported","installationAttempted","checkNodeVersion","version","process","versions","node","major","parseInt","split","installNativeModule","callback","Error","installModule","default","console","log","err","warn","message","tryLoadNative","undefined","isNativeAvailable"],"mappings":"AAAA;;;;;;CAMC,GAED,OAAOA,YAAY,SAAS;AAC5B,OAAOC,UAAU,OAAO;AACxB,OAAOC,SAAS,MAAM;AAEtB,+BAA+B;AAC/B,MAAMC,WAAW,OAAOC,YAAY,cAAcJ,OAAOK,aAAa,CAAC,YAAYH,GAAG,IAAIE;AAC1F,MAAME,YAAYL,KAAKM,OAAO,CAAC,OAAOC,eAAe,cAAcA,aAAaN,IAAIO,aAAa,CAAC,YAAYP,GAAG;AAEjH,oFAAoF;AACpF,MAAMQ,kBAAkBT,KAAKU,IAAI,CAACL,WAAW,MAAM,MAAM;AAEzD,yCAAyC;AACzC,IAAIM;AACJ,IAAIC,qBAAqB;AACzB,IAAIC,uBAAuB;AAC3B,IAAIC,wBAAwB;AAiB5B;;CAEC,GACD,SAASC;IACP,IAAIH,oBAAoB,OAAOC;IAC/BD,qBAAqB;IAErB,IAAI;QACF,MAAMI,UAAUC,QAAQC,QAAQ,CAACC,IAAI;QACrC,MAAMC,QAAQC,SAASL,QAAQM,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE;QAC9CT,uBAAuBO,SAAS;IAClC,EAAE,OAAM;QACNP,uBAAuB;IACzB;IAEA,OAAOA;AACT;AAEA;;CAEC,GACD,SAASU,oBAAoBC,QAAqC;IAChE,iCAAiC;IACjC,IAAIV,uBAAuB;QACzBU,SAAS,IAAIC,MAAM;QACnB;IACF;IACAX,wBAAwB;IAExB,IAAI;QACF,8DAA8D;QAC9D,MAAMY,gBAAgBxB,SAAS,yBAAyByB,OAAO;QAE/DC,QAAQC,GAAG,CAAC;QACZH,cAAc,iBAAiBjB,iBAAiB,CAAC,GAAG,CAACqB;YACnD,IAAIA,KAAK;gBACPF,QAAQG,IAAI,CAAC,oCAAoCD,IAAIE,OAAO;YAC9D,OAAO;gBACLJ,QAAQC,GAAG,CAAC;YACd;YACAL,SAASM;QACX;IACF,EAAE,OAAOA,KAAK;QACZN,SAASM;IACX;AACF;AAEA;;;CAGC,GACD,OAAO,SAASG;IACd,uBAAuB;IACvB,IAAItB,iBAAiBuB,WAAW,OAAOvB;IAEvC,2BAA2B;IAC3B,IAAI,CAACI,oBAAoB;QACvBJ,eAAe;QACf,OAAO;IACT;IAEA,yEAAyE;IACzE,IAAI;QACF,iEAAiE;QACjEA,eAAeT,SAAS;QACxB,OAAOS;IACT,EAAE,OAAM;QACN,yCAAyC;QACzCA,eAAe;QACf,OAAO;IACT;AACF;AAEA,oEAAoE;AACpE,wEAAwE;AACxE,IAAII,oBAAoB;IACtBQ,oBAAoB;QAClB,sDAAsD;QACtDZ,eAAeuB,WAAW,gCAAgC;QAC1D,IAAI;YACFvB,eAAeT,SAAS;QAC1B,EAAE,OAAM;YACN,6BAA6B;YAC7BS,eAAe;QACjB;IACF;AACF;AAEA;;CAEC,GACD,OAAO,SAASwB;IACd,OAAOF,oBAAoB;AAC7B"}
|
package/dist/esm/xz/Decoder.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ import type { Transform as TransformType } from 'stream';
|
|
|
22
22
|
/**
|
|
23
23
|
* Decompress XZ data synchronously
|
|
24
24
|
* Uses @napi-rs/lzma if available on Node 14+, falls back to pure JS
|
|
25
|
-
* Properly handles multi-block XZ files and
|
|
25
|
+
* Properly handles multi-block XZ files, stream padding, and concatenated streams
|
|
26
26
|
* @param input - XZ compressed data
|
|
27
27
|
* @returns Decompressed data
|
|
28
28
|
*/
|
package/dist/esm/xz/Decoder.js
CHANGED
|
@@ -227,18 +227,9 @@ const FILTER_LZMA2 = 0x21;
|
|
|
227
227
|
return records;
|
|
228
228
|
}
|
|
229
229
|
/**
|
|
230
|
-
*
|
|
231
|
-
|
|
232
|
-
* Properly handles multi-block XZ files and stream padding
|
|
233
|
-
* @param input - XZ compressed data
|
|
234
|
-
* @returns Decompressed data
|
|
235
|
-
*/ export function decodeXZ(input) {
|
|
230
|
+
* Pure JS XZ decompression (handles all XZ spec features)
|
|
231
|
+
*/ function decodeXZPure(input) {
|
|
236
232
|
var _checkSizes_checkType;
|
|
237
|
-
// Try native acceleration first (Node 14+ with @napi-rs/lzma installed)
|
|
238
|
-
const native = tryLoadNative();
|
|
239
|
-
if (native) {
|
|
240
|
-
return native.xz.decompressSync(input);
|
|
241
|
-
}
|
|
242
233
|
// Verify XZ magic
|
|
243
234
|
if (input.length < 12 || !bufferEquals(input, 0, XZ_MAGIC)) {
|
|
244
235
|
throw new Error('Invalid XZ magic bytes');
|
|
@@ -301,6 +292,75 @@ const FILTER_LZMA2 = 0x21;
|
|
|
301
292
|
}
|
|
302
293
|
return Buffer.concat(outputChunks);
|
|
303
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Decompress XZ data synchronously
|
|
297
|
+
* Uses @napi-rs/lzma if available on Node 14+, falls back to pure JS
|
|
298
|
+
* Properly handles multi-block XZ files, stream padding, and concatenated streams
|
|
299
|
+
* @param input - XZ compressed data
|
|
300
|
+
* @returns Decompressed data
|
|
301
|
+
*/ export function decodeXZ(input) {
|
|
302
|
+
// Try native acceleration first (Node 14+ with @napi-rs/lzma installed)
|
|
303
|
+
const native = tryLoadNative();
|
|
304
|
+
if (native) {
|
|
305
|
+
try {
|
|
306
|
+
return native.xz.decompressSync(input);
|
|
307
|
+
} catch (nativeErr) {
|
|
308
|
+
// Native failed - try pure JS (handles more edge cases like
|
|
309
|
+
// stream padding, concatenated streams, SHA-256 checksums)
|
|
310
|
+
try {
|
|
311
|
+
return decodeXZPure(input);
|
|
312
|
+
} catch {
|
|
313
|
+
// Both failed - throw the native error (usually more informative)
|
|
314
|
+
throw nativeErr;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return decodeXZPure(input);
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Parse XZ stream to get block information (without decompressing)
|
|
322
|
+
* This allows streaming decompression by processing blocks one at a time.
|
|
323
|
+
*/ function parseXZIndex(input) {
|
|
324
|
+
var _checkSizes_checkType;
|
|
325
|
+
// Stream header validation
|
|
326
|
+
if (input.length < 12) {
|
|
327
|
+
throw new Error('XZ file too small');
|
|
328
|
+
}
|
|
329
|
+
// Stream magic bytes (0xFD, '7zXZ', 0x00)
|
|
330
|
+
if (input[0] !== 0xfd || input[1] !== 0x37 || input[2] !== 0x7a || input[3] !== 0x58 || input[4] !== 0x5a || input[5] !== 0x00) {
|
|
331
|
+
throw new Error('Invalid XZ magic bytes');
|
|
332
|
+
}
|
|
333
|
+
// Stream flags at offset 6-7
|
|
334
|
+
const checkType = input[7] & 0x0f;
|
|
335
|
+
// Check sizes based on check type
|
|
336
|
+
const checkSizes = {
|
|
337
|
+
0: 0,
|
|
338
|
+
1: 4,
|
|
339
|
+
4: 8,
|
|
340
|
+
10: 32
|
|
341
|
+
};
|
|
342
|
+
const checkSize = (_checkSizes_checkType = checkSizes[checkType]) !== null && _checkSizes_checkType !== void 0 ? _checkSizes_checkType : 0;
|
|
343
|
+
// Find footer by skipping stream padding
|
|
344
|
+
let footerEnd = input.length;
|
|
345
|
+
while(footerEnd > 12 && input[footerEnd - 1] === 0x00){
|
|
346
|
+
footerEnd--;
|
|
347
|
+
}
|
|
348
|
+
while(footerEnd % 4 !== 0 && footerEnd > 12){
|
|
349
|
+
footerEnd++;
|
|
350
|
+
}
|
|
351
|
+
// Verify footer magic
|
|
352
|
+
if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {
|
|
353
|
+
throw new Error('Invalid XZ footer magic');
|
|
354
|
+
}
|
|
355
|
+
// Get backward size
|
|
356
|
+
const backwardSize = (input.readUInt32LE(footerEnd - 8) + 1) * 4;
|
|
357
|
+
const indexStart = footerEnd - 12 - backwardSize;
|
|
358
|
+
// Parse Index to get block information
|
|
359
|
+
return parseIndex(input, indexStart, checkSize).map((record)=>({
|
|
360
|
+
...record,
|
|
361
|
+
checkSize
|
|
362
|
+
}));
|
|
363
|
+
}
|
|
304
364
|
/**
|
|
305
365
|
* Create an XZ decompression Transform stream
|
|
306
366
|
* @returns Transform stream that decompresses XZ data
|
|
@@ -314,8 +374,26 @@ const FILTER_LZMA2 = 0x21;
|
|
|
314
374
|
flush (callback) {
|
|
315
375
|
try {
|
|
316
376
|
const input = Buffer.concat(chunks);
|
|
317
|
-
|
|
318
|
-
|
|
377
|
+
// Stream decode each block instead of buffering all output
|
|
378
|
+
const blockRecords = parseXZIndex(input);
|
|
379
|
+
for(let i = 0; i < blockRecords.length; i++){
|
|
380
|
+
const record = blockRecords[i];
|
|
381
|
+
const recordStart = record.compressedPos;
|
|
382
|
+
// Parse block header
|
|
383
|
+
const blockInfo = parseBlockHeader(input, recordStart, blockRecords[i].checkSize);
|
|
384
|
+
// Extract compressed data for this block
|
|
385
|
+
const dataStart = recordStart + blockInfo.headerSize;
|
|
386
|
+
const dataEnd = dataStart + record.compressedDataSize;
|
|
387
|
+
const compressedData = input.slice(dataStart, dataEnd);
|
|
388
|
+
// Decompress this block
|
|
389
|
+
let blockOutput = decodeLzma2(compressedData, blockInfo.lzma2Props, record.uncompressedSize);
|
|
390
|
+
// Apply preprocessing filters in reverse order
|
|
391
|
+
for(let j = blockInfo.filters.length - 1; j >= 0; j--){
|
|
392
|
+
blockOutput = applyFilter(blockOutput, blockInfo.filters[j]);
|
|
393
|
+
}
|
|
394
|
+
// Push block output immediately instead of buffering
|
|
395
|
+
this.push(blockOutput);
|
|
396
|
+
}
|
|
319
397
|
callback();
|
|
320
398
|
} catch (err) {
|
|
321
399
|
callback(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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 { 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';\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/**\n * Simple buffer comparison\n */\nfunction bufferEquals(buf: Buffer, 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 (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 * Returns number, but limits to 32-bit to work on Node 0.8+\n */\nfunction decodeMultibyte(buf: Buffer, 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 = buf[offset + i];\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n // Reduced to prevent overflow on Node 0.8\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 *\n * XZ Index stores \"Unpadded Size\" for each block which equals:\n * Block Header Size + Compressed Data Size + Check Size\n * (does NOT include padding to 4-byte boundary)\n */\nfunction parseIndex(\n input: Buffer,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (input[offset] !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyte(input, 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 = decodeMultibyte(input, offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyte(input, 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 = input[currentPos];\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n // unpaddedSize = headerSize + compressedDataSize + checkSize\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 * Decompress XZ data synchronously\n * Uses @napi-rs/lzma if available on Node 14+, falls back to pure JS\n * Properly handles multi-block XZ files and stream padding\n * @param input - XZ compressed data\n * @returns Decompressed data\n */\nexport function decodeXZ(input: Buffer): Buffer {\n // Try native acceleration first (Node 14+ with @napi-rs/lzma installed)\n const native = tryLoadNative();\n if (native) {\n return native.xz.decompressSync(input);\n }\n\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 = 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 && 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 backwardSize = (input.readUInt32LE(footerEnd - 8) + 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 each block\n const outputChunks: Buffer[] = [];\n let _totalOutputSize = 0;\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 // compressedDataSize is calculated from the Index's Unpadded Size minus header and check\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 outputChunks.push(blockOutput);\n _totalOutputSize += blockOutput.length;\n }\n\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n */\nexport function createXZDecoder(): TransformType {\n const chunks: Buffer[] = [];\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n chunks.push(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n try {\n const input = Buffer.concat(chunks);\n const output = decodeXZ(input);\n this.push(output);\n callback();\n } catch (err) {\n callback(err as Error);\n }\n },\n });\n}\n"],"names":["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","bufferEquals","buf","offset","expected","length","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","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","decodeXZ","checkSizes","native","xz","decompressSync","checkType","footerEnd","backwardSize","readUInt32LE","blockRecords","outputChunks","_totalOutputSize","recordStart","blockInfo","compressedData","blockOutput","j","Buffer","concat","createXZDecoder","chunks","transform","chunk","_encoding","callback","flush","output","err"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/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 { 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';\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/**\n * Simple buffer comparison\n */\nfunction bufferEquals(buf: Buffer, 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 (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 * Returns number, but limits to 32-bit to work on Node 0.8+\n */\nfunction decodeMultibyte(buf: Buffer, 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 = buf[offset + i];\n value |= (byte & 0x7f) << (i * 7);\n i++;\n if (i > 4) {\n // Reduced to prevent overflow on Node 0.8\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 *\n * XZ Index stores \"Unpadded Size\" for each block which equals:\n * Block Header Size + Compressed Data Size + Check Size\n * (does NOT include padding to 4-byte boundary)\n */\nfunction parseIndex(\n input: Buffer,\n indexStart: number,\n checkSize: number\n): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n}> {\n let offset = indexStart;\n\n // Index indicator (0x00)\n if (input[offset] !== 0x00) {\n throw new Error('Invalid index indicator');\n }\n offset++;\n\n // Number of records\n const countResult = decodeMultibyte(input, 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 = decodeMultibyte(input, offset);\n offset += unpaddedResult.bytesRead;\n\n // Uncompressed size\n const uncompressedResult = decodeMultibyte(input, 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 = input[currentPos];\n const headerSize = (headerSizeRaw + 1) * 4;\n\n // Calculate compressed data size from unpadded size\n // unpaddedSize = headerSize + compressedDataSize + checkSize\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 */\nfunction decodeXZPure(input: Buffer): Buffer {\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 = 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 && 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 backwardSize = (input.readUInt32LE(footerEnd - 8) + 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 each block\n const outputChunks: Buffer[] = [];\n let _totalOutputSize = 0;\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 // compressedDataSize is calculated from the Index's Unpadded Size minus header and check\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 outputChunks.push(blockOutput);\n _totalOutputSize += blockOutput.length;\n }\n\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Decompress XZ data synchronously\n * Uses @napi-rs/lzma if available on Node 14+, falls back to pure JS\n * Properly handles multi-block XZ files, stream padding, and concatenated streams\n * @param input - XZ compressed data\n * @returns Decompressed data\n */\nexport function decodeXZ(input: Buffer): Buffer {\n // Try native acceleration first (Node 14+ with @napi-rs/lzma installed)\n const native = tryLoadNative();\n if (native) {\n try {\n return native.xz.decompressSync(input);\n } catch (nativeErr) {\n // Native failed - try pure JS (handles more edge cases like\n // stream padding, concatenated streams, SHA-256 checksums)\n try {\n return decodeXZPure(input);\n } catch {\n // Both failed - throw the native error (usually more informative)\n throw nativeErr;\n }\n }\n }\n return decodeXZPure(input);\n}\n\n/**\n * Parse XZ stream to get block information (without decompressing)\n * This allows streaming decompression by processing blocks one at a time.\n */\nfunction parseXZIndex(input: Buffer): Array<{\n compressedPos: number;\n compressedDataSize: number;\n uncompressedSize: number;\n checkSize: number;\n}> {\n // Stream header validation\n if (input.length < 12) {\n throw new Error('XZ file too small');\n }\n\n // Stream magic bytes (0xFD, '7zXZ', 0x00)\n if (input[0] !== 0xfd || input[1] !== 0x37 || input[2] !== 0x7a || input[3] !== 0x58 || input[4] !== 0x5a || input[5] !== 0x00) {\n throw new Error('Invalid XZ magic bytes');\n }\n\n // Stream flags at offset 6-7\n const checkType = 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\n let footerEnd = input.length;\n while (footerEnd > 12 && input[footerEnd - 1] === 0x00) {\n footerEnd--;\n }\n while (footerEnd % 4 !== 0 && footerEnd > 12) {\n footerEnd++;\n }\n\n // Verify footer magic\n if (!bufferEquals(input, footerEnd - 2, XZ_FOOTER_MAGIC)) {\n throw new Error('Invalid XZ footer magic');\n }\n\n // Get backward size\n const backwardSize = (input.readUInt32LE(footerEnd - 8) + 1) * 4;\n const indexStart = footerEnd - 12 - backwardSize;\n\n // Parse Index to get block information\n return parseIndex(input, indexStart, checkSize).map((record) => ({\n ...record,\n checkSize,\n }));\n}\n\n/**\n * Create an XZ decompression Transform stream\n * @returns Transform stream that decompresses XZ data\n */\nexport function createXZDecoder(): TransformType {\n const chunks: Buffer[] = [];\n\n return new Transform({\n transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null) => void) {\n chunks.push(chunk);\n callback();\n },\n\n flush(callback: (error?: Error | null) => void) {\n try {\n const input = Buffer.concat(chunks);\n\n // Stream decode each block instead of buffering all output\n const blockRecords = parseXZIndex(input);\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, blockRecords[i].checkSize);\n\n // Extract compressed data for this block\n const dataStart = recordStart + blockInfo.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 block output immediately instead of buffering\n this.push(blockOutput);\n }\n\n callback();\n } catch (err) {\n callback(err as Error);\n }\n },\n });\n}\n"],"names":["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","bufferEquals","buf","offset","expected","length","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","countResult","recordCount","records","unpaddedResult","uncompressedResult","compressedPos","unpaddedSize","compressedDataSize","uncompressedSize","currentPos","record","headerSizeRaw","paddedSize","Math","ceil","decodeXZPure","checkSizes","checkType","footerEnd","backwardSize","readUInt32LE","blockRecords","outputChunks","_totalOutputSize","recordStart","blockInfo","compressedData","blockOutput","j","Buffer","concat","decodeXZ","native","xz","decompressSync","nativeErr","parseXZIndex","map","createXZDecoder","chunks","transform","chunk","_encoding","callback","flush","err"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xz-compat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "XZ Decompression Library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"extract",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"extract-base-iterator": "^3.0.0",
|
|
57
|
+
"install-module-linked": "^1.3.16",
|
|
57
58
|
"os-shim": "^0.1.3"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
@@ -69,9 +70,6 @@
|
|
|
69
70
|
"ts-dev-stack": "*",
|
|
70
71
|
"tsds-config": "*"
|
|
71
72
|
},
|
|
72
|
-
"optionalDependencies": {
|
|
73
|
-
"@napi-rs/lzma": "^1.4.0"
|
|
74
|
-
},
|
|
75
73
|
"engines": {
|
|
76
74
|
"node": ">=0.8"
|
|
77
75
|
}
|