node-liblzma 1.1.9 → 2.0.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.
Files changed (76) hide show
  1. package/.claude/settings.local.json +92 -0
  2. package/.gitattributes +3 -0
  3. package/.release-it.json +6 -0
  4. package/CHANGELOG.md +209 -0
  5. package/History.md +20 -0
  6. package/README.md +750 -30
  7. package/RELEASING.md +131 -0
  8. package/binding.gyp +159 -438
  9. package/biome.json +81 -0
  10. package/coverage/base.css +224 -0
  11. package/coverage/block-navigation.js +87 -0
  12. package/coverage/errors.ts.html +586 -0
  13. package/coverage/favicon.png +0 -0
  14. package/coverage/index.html +146 -0
  15. package/coverage/lcov-report/base.css +224 -0
  16. package/coverage/lcov-report/block-navigation.js +87 -0
  17. package/coverage/lcov-report/errors.ts.html +586 -0
  18. package/coverage/lcov-report/favicon.png +0 -0
  19. package/coverage/lcov-report/index.html +146 -0
  20. package/coverage/lcov-report/lzma.ts.html +2596 -0
  21. package/coverage/lcov-report/pool.ts.html +769 -0
  22. package/coverage/lcov-report/prettify.css +1 -0
  23. package/coverage/lcov-report/prettify.js +2 -0
  24. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  25. package/coverage/lcov-report/sorter.js +210 -0
  26. package/coverage/lcov.info +636 -0
  27. package/coverage/lzma.ts.html +2596 -0
  28. package/coverage/pool.ts.html +769 -0
  29. package/coverage/prettify.css +1 -0
  30. package/coverage/prettify.js +2 -0
  31. package/coverage/sort-arrow-sprite.png +0 -0
  32. package/coverage/sorter.js +210 -0
  33. package/coverage-reports/assets/monocart-coverage-app.js +2 -0
  34. package/coverage-reports/coverage-data.js +1 -0
  35. package/coverage-reports/index.html +48 -0
  36. package/err.log +26 -0
  37. package/index.d.ts +254 -0
  38. package/lib/errors.d.ts +72 -0
  39. package/lib/errors.d.ts.map +1 -0
  40. package/lib/errors.js +153 -0
  41. package/lib/errors.js.map +1 -0
  42. package/lib/lzma.d.ts +245 -0
  43. package/lib/lzma.d.ts.map +1 -0
  44. package/lib/lzma.js +626 -345
  45. package/lib/lzma.js.map +1 -0
  46. package/lib/pool.d.ts +123 -0
  47. package/lib/pool.d.ts.map +1 -0
  48. package/lib/pool.js +188 -0
  49. package/lib/pool.js.map +1 -0
  50. package/lib/types.d.ts +27 -0
  51. package/lib/types.d.ts.map +1 -0
  52. package/lib/types.js +5 -0
  53. package/lib/types.js.map +1 -0
  54. package/package.json +60 -21
  55. package/pnpm-workspace.yaml +3 -0
  56. package/scripts/analyze-coverage.js +132 -0
  57. package/scripts/build_xz_with_cmake.py +390 -0
  58. package/scripts/compare-coverage-tools.js +93 -0
  59. package/scripts/copy_dll.py +51 -0
  60. package/scripts/download_xz_from_github.py +375 -0
  61. package/src/bindings/node-liblzma.cpp +411 -229
  62. package/src/bindings/node-liblzma.hpp +101 -48
  63. package/src/errors.ts +167 -0
  64. package/src/lzma.ts +839 -0
  65. package/src/pool.ts +228 -0
  66. package/src/types.ts +30 -0
  67. package/tsconfig.json +50 -0
  68. package/vitest.config.istanbul.ts +29 -0
  69. package/vitest.config.monocart.ts +44 -0
  70. package/vitest.config.ts +44 -0
  71. package/xz-version.json +8 -0
  72. package/prebuilds/darwin-x64/node.napi.node +0 -0
  73. package/prebuilds/linux-x64/node.napi.node +0 -0
  74. package/prebuilds/win32-x64/node.napi.node +0 -0
  75. package/scripts/download_extract_deps.py +0 -29
  76. package/src/lzma.coffee +0 -344
package/lib/lzma.js CHANGED
@@ -1,5 +1,4 @@
1
- // Generated by CoffeeScript 2.6.1
2
- /*
1
+ /**
3
2
  * node-liblzma - Node.js bindings for liblzma
4
3
  * Copyright (C) Olivier Orabona <olivier.orabona@gmail.com>
5
4
  *
@@ -16,366 +15,648 @@
16
15
  * You should have received a copy of the GNU Lesser General Public License
17
16
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18
17
  */
19
- var Transform, Unxz, Xz, XzStream, assert, binding_path, liblzma, maxThreads, os, path, util, xzBuffer, xzBufferSync;
20
-
21
- path = require('path');
22
-
23
- binding_path = path.resolve(path.join(__dirname, '..'));
24
-
25
- liblzma = require('node-gyp-build')(binding_path);
26
-
27
- util = require('util');
28
-
29
- assert = require('assert');
30
-
31
- os = require('os');
32
-
33
- ({Transform} = require('stream'));
34
-
18
+ import * as assert from 'node:assert';
19
+ import { createRequire } from 'node:module';
20
+ import * as os from 'node:os';
21
+ import * as path from 'node:path';
22
+ import { Transform } from 'node:stream';
23
+ import { fileURLToPath } from 'node:url';
24
+ import { createLZMAError, LZMABufferError, LZMADataError, LZMAError, LZMAFormatError, LZMAMemoryError, LZMAMemoryLimitError, LZMAOptionsError, LZMAProgrammingError, } from './errors.js';
25
+ // Re-export error classes for public API
26
+ export { LZMAError, LZMAMemoryError, LZMAMemoryLimitError, LZMAFormatError, LZMAOptionsError, LZMADataError, LZMABufferError, LZMAProgrammingError, };
27
+ // Re-export pool for concurrency control
28
+ export { LZMAPool } from './pool.js';
29
+ // Helper to safely access Node.js internal _writableState using official properties
30
+ function getWritableState(stream) {
31
+ return {
32
+ /* v8 ignore next 2 - Node.js version compatibility fallback */
33
+ ending: stream._writableState?.ending ?? false,
34
+ ended: stream._writableState?.ended ?? false,
35
+ length: stream.writableLength,
36
+ needDrain: stream.writableNeedDrain,
37
+ };
38
+ }
39
+ const __filename = fileURLToPath(import.meta.url);
40
+ const __dirname = path.dirname(__filename);
41
+ const require = createRequire(import.meta.url);
42
+ const bindingPath = path.resolve(path.join(__dirname, '..'));
43
+ const liblzma = require('node-gyp-build')(bindingPath);
35
44
  // Should not change over time... :)
36
- maxThreads = os.cpus().length;
37
-
38
- XzStream = class XzStream extends Transform {
39
- constructor(mode, _opts = {}, options) {
40
- var base, base1, base2, base3, base4;
41
- super(options);
42
- this._opts = _opts;
43
- if ((base = this._opts).check == null) {
44
- base.check = exports.check.NONE;
45
+ const maxThreads = os.cpus().length;
46
+ // Export constants grouped by category for better organization
47
+ export const check = {
48
+ NONE: liblzma.LZMA_CHECK_NONE,
49
+ CRC32: liblzma.LZMA_CHECK_CRC32,
50
+ CRC64: liblzma.LZMA_CHECK_CRC64,
51
+ SHA256: liblzma.LZMA_CHECK_SHA256,
52
+ };
53
+ export const preset = {
54
+ DEFAULT: liblzma.LZMA_PRESET_DEFAULT,
55
+ EXTREME: liblzma.LZMA_PRESET_EXTREME,
56
+ };
57
+ export const flag = {
58
+ TELL_NO_CHECK: liblzma.LZMA_TELL_NO_CHECK,
59
+ TELL_UNSUPPORTED_CHECK: liblzma.LZMA_TELL_UNSUPPORTED_CHECK,
60
+ TELL_ANY_CHECK: liblzma.LZMA_TELL_ANY_CHECK,
61
+ CONCATENATED: liblzma.LZMA_CONCATENATED,
62
+ };
63
+ export const filter = {
64
+ LZMA2: liblzma.LZMA_FILTER_LZMA2,
65
+ X86: liblzma.LZMA_FILTER_X86,
66
+ POWERPC: liblzma.LZMA_FILTER_POWERPC,
67
+ IA64: liblzma.LZMA_FILTER_IA64,
68
+ ARM: liblzma.LZMA_FILTER_ARM,
69
+ ARMTHUMB: liblzma.LZMA_FILTER_ARMTHUMB,
70
+ SPARC: liblzma.LZMA_FILTER_SPARC,
71
+ };
72
+ /* v8 ignore next */
73
+ export const mode = {
74
+ FAST: liblzma.LZMA_MODE_FAST,
75
+ NORMAL: liblzma.LZMA_MODE_NORMAL,
76
+ };
77
+ /* v8 ignore next 2 */
78
+ // LZMA action constants - grouped for better organization
79
+ export const LZMAAction = {
80
+ RUN: liblzma.LZMA_RUN,
81
+ SYNC_FLUSH: liblzma.LZMA_SYNC_FLUSH,
82
+ FULL_FLUSH: liblzma.LZMA_FULL_FLUSH,
83
+ FINISH: liblzma.LZMA_FINISH,
84
+ };
85
+ /* v8 ignore next 2 */
86
+ // LZMA status/return constants
87
+ export const LZMAStatus = {
88
+ OK: liblzma.LZMA_OK,
89
+ STREAM_END: liblzma.LZMA_STREAM_END,
90
+ NO_CHECK: liblzma.LZMA_NO_CHECK,
91
+ UNSUPPORTED_CHECK: liblzma.LZMA_UNSUPPORTED_CHECK,
92
+ GET_CHECK: liblzma.LZMA_GET_CHECK,
93
+ MEM_ERROR: liblzma.LZMA_MEM_ERROR,
94
+ MEMLIMIT_ERROR: liblzma.LZMA_MEMLIMIT_ERROR,
95
+ FORMAT_ERROR: liblzma.LZMA_FORMAT_ERROR,
96
+ OPTIONS_ERROR: liblzma.LZMA_OPTIONS_ERROR,
97
+ DATA_ERROR: liblzma.LZMA_DATA_ERROR,
98
+ BUF_ERROR: liblzma.LZMA_BUF_ERROR,
99
+ PROG_ERROR: liblzma.LZMA_PROG_ERROR,
100
+ };
101
+ // Additional filter constants
102
+ export const LZMAFilter = {
103
+ ...filter,
104
+ X86_ALT: liblzma.LZMA_FILTER_X86,
105
+ POWERPC_ALT: liblzma.LZMA_FILTER_POWERPC,
106
+ IA64_ALT: liblzma.LZMA_FILTER_IA64,
107
+ ARM_ALT: liblzma.LZMA_FILTER_ARM,
108
+ ARMTHUMB_ALT: liblzma.LZMA_FILTER_ARMTHUMB,
109
+ FILTERS_MAX: liblzma.LZMA_FILTERS_MAX,
110
+ };
111
+ // Legacy individual exports for backward compatibility
112
+ export const LZMA_RUN = LZMAAction.RUN;
113
+ export const LZMA_SYNC_FLUSH = LZMAAction.SYNC_FLUSH;
114
+ export const LZMA_FULL_FLUSH = LZMAAction.FULL_FLUSH;
115
+ export const LZMA_FINISH = LZMAAction.FINISH;
116
+ export const LZMA_OK = LZMAStatus.OK;
117
+ export const LZMA_STREAM_END = LZMAStatus.STREAM_END;
118
+ export const LZMA_NO_CHECK = LZMAStatus.NO_CHECK;
119
+ export const LZMA_UNSUPPORTED_CHECK = LZMAStatus.UNSUPPORTED_CHECK;
120
+ export const LZMA_GET_CHECK = LZMAStatus.GET_CHECK;
121
+ export const LZMA_MEM_ERROR = LZMAStatus.MEM_ERROR;
122
+ export const LZMA_MEMLIMIT_ERROR = LZMAStatus.MEMLIMIT_ERROR;
123
+ export const LZMA_FORMAT_ERROR = LZMAStatus.FORMAT_ERROR;
124
+ export const LZMA_OPTIONS_ERROR = LZMAStatus.OPTIONS_ERROR;
125
+ export const LZMA_DATA_ERROR = LZMAStatus.DATA_ERROR;
126
+ export const LZMA_BUF_ERROR = LZMAStatus.BUF_ERROR;
127
+ export const LZMA_PROG_ERROR = LZMAStatus.PROG_ERROR;
128
+ export const LZMA_FILTER_X86 = LZMAFilter.X86_ALT;
129
+ export const LZMA_FILTER_POWERPC = LZMAFilter.POWERPC_ALT;
130
+ export const LZMA_FILTER_IA64 = LZMAFilter.IA64_ALT;
131
+ export const LZMA_FILTER_ARM = LZMAFilter.ARM_ALT;
132
+ export const LZMA_FILTER_ARMTHUMB = LZMAFilter.ARMTHUMB_ALT;
133
+ export const LZMA_FILTERS_MAX = LZMAFilter.FILTERS_MAX;
134
+ export class XzStream extends Transform {
135
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Constructor needs complex validation for LZMA options
136
+ constructor(streamMode, opts = {}, options) {
137
+ super(options);
138
+ let clonedFilters;
139
+ if (opts.filters) {
140
+ if (!Array.isArray(opts.filters)) {
141
+ throw new Error('Filters need to be in an array!');
142
+ }
143
+ try {
144
+ clonedFilters = [...opts.filters];
145
+ /* v8 ignore next 3 */
146
+ }
147
+ catch (_error) {
148
+ throw new Error('Filters need to be in an array!');
149
+ }
150
+ }
151
+ else {
152
+ clonedFilters = [filter.LZMA2];
153
+ }
154
+ this._opts = {
155
+ check: opts.check ?? check.NONE,
156
+ preset: opts.preset ?? preset.DEFAULT,
157
+ filters: clonedFilters,
158
+ mode: opts.mode ?? mode.NORMAL,
159
+ threads: opts.threads ?? 1,
160
+ chunkSize: opts.chunkSize ?? liblzma.BUFSIZ,
161
+ flushFlag: opts.flushFlag ?? liblzma.LZMA_RUN,
162
+ };
163
+ this._chunkSize = this._opts.chunkSize;
164
+ this._flushFlag = this._opts.flushFlag;
165
+ assert.ok(Array.isArray(this._opts.filters), 'Filters need to be in an array!');
166
+ // Add default filter LZMA2 if none provided
167
+ /* v8 ignore next 2 */
168
+ if (this._opts.filters.indexOf(filter.LZMA2) === -1) {
169
+ this._opts.filters.push(filter.LZMA2);
170
+ }
171
+ // Ensure LZMA2 is always the last filter (requirement of liblzma)
172
+ const lzma2Index = this._opts.filters.indexOf(filter.LZMA2);
173
+ if (lzma2Index !== -1 && lzma2Index !== this._opts.filters.length - 1) {
174
+ // Remove LZMA2 from its current position and add it to the end
175
+ this._opts.filters.splice(lzma2Index, 1);
176
+ this._opts.filters.push(filter.LZMA2);
177
+ }
178
+ // Multithreading is only available for encoding, so if we are encoding, check
179
+ // opts threads value.
180
+ if (streamMode === liblzma.STREAM_ENCODE) {
181
+ /* If threads are requested but not supported, fallback to single thread */
182
+ /* c8 ignore start */
183
+ if (!liblzma.HAS_THREADS_SUPPORT) {
184
+ this._opts.threads = 1;
185
+ }
186
+ /* c8 ignore stop */
187
+ // By default set to maximum available processors
188
+ if (this._opts.threads === 0) {
189
+ this._opts.threads = maxThreads;
190
+ }
191
+ }
192
+ // Initialize engine
193
+ this.lzma = new liblzma.LZMA(streamMode, this._opts);
194
+ this._closed = false;
195
+ this._hadError = false;
196
+ this._offset = 0;
197
+ this._buffer = Buffer.alloc(this._chunkSize);
198
+ /* v8 ignore next */
199
+ this.on('onerror', (errno) => {
200
+ this._hadError = true;
201
+ const error = this._createLZMAError(errno);
202
+ // Safely emit error - ensure there's at least one listener to prevent uncaught exception
203
+ /* v8 ignore next 6 - Defensive error handling for streams without listeners */
204
+ if (this.listenerCount('error') === 0) {
205
+ // If no error listeners, add a temporary one to prevent crash
206
+ this.once('error', () => {
207
+ // Error has been handled by emitting it
208
+ });
209
+ }
210
+ this.emit('error', error);
211
+ });
212
+ /* v8 ignore next */
213
+ this.once('end', () => this.close());
45
214
  }
46
- if ((base1 = this._opts).preset == null) {
47
- base1.preset = exports.preset.DEFAULT;
215
+ _createLZMAError(errno) {
216
+ return createLZMAError(errno);
48
217
  }
49
- if ((base2 = this._opts).filters == null) {
50
- base2.filters = [exports.filter.LZMA2];
218
+ _reallocateBuffer() {
219
+ this._offset = 0;
220
+ this._buffer = Buffer.alloc(this._chunkSize);
51
221
  }
52
- if ((base3 = this._opts).mode == null) {
53
- base3.mode = exports.mode.NORMAL;
222
+ flush(kindOrCallback, callback) {
223
+ const ws = getWritableState(this);
224
+ let kind;
225
+ let cb;
226
+ /* v8 ignore next */
227
+ if (typeof kindOrCallback === 'function' ||
228
+ (typeof kindOrCallback === 'undefined' && !callback)) {
229
+ cb = kindOrCallback;
230
+ kind = liblzma.LZMA_SYNC_FLUSH;
231
+ }
232
+ else {
233
+ kind = kindOrCallback;
234
+ cb = callback;
235
+ }
236
+ if (ws.ended) {
237
+ if (cb) {
238
+ process.nextTick(cb);
239
+ }
240
+ /* v8 ignore next 4 */
241
+ }
242
+ else if (ws.ending) {
243
+ if (cb) {
244
+ this.once('end', cb);
245
+ }
246
+ /* v8 ignore next 5 - drain handling is difficult to test reliably */
247
+ }
248
+ else if (ws.needDrain) {
249
+ this.once('drain', () => {
250
+ this.flush(cb);
251
+ });
252
+ }
253
+ else {
254
+ this._flushFlag = kind;
255
+ this.write(Buffer.alloc(0), 'utf8', cb);
256
+ }
54
257
  }
55
- if ((base4 = this._opts).threads == null) {
56
- base4.threads = 1;
258
+ close(callback) {
259
+ if (callback) {
260
+ process.nextTick(callback);
261
+ }
262
+ // We will trigger this case with #xz and #unxz
263
+ if (this._closed) {
264
+ return;
265
+ }
266
+ /* v8 ignore next */
267
+ this.lzma.close();
268
+ this._closed = true;
269
+ /* v8 ignore next */
270
+ process.nextTick(() => {
271
+ this.emit('close');
272
+ });
57
273
  }
58
- this._chunkSize = this._opts.chunkSize ? this._opts.chunkSize : liblzma.BUFSIZ;
59
- // By default no flush, since there is no LZMA_NO_SYNC, we stick to
60
- // default LZMA_RUN (0)
61
- this._flushFlag = this._opts.flushFlag || liblzma.LZMA_RUN;
62
- assert(Array.isArray(this._opts.filters), "Filters need to be in an array!");
63
- // Add default filter LZMA2 if none provided
64
- if (this._opts.filters.indexOf(exports.filter.LZMA2) === -1) {
65
- this._opts.filters.push(exports.filter.LZMA2);
274
+ /* v8 ignore next */
275
+ _transform(chunk, _encoding, callback) {
276
+ const ws = getWritableState(this);
277
+ const ending = ws.ending || ws.ended;
278
+ const last = ending && (!chunk || ws.length === chunk.length);
279
+ if (chunk !== null && !(chunk instanceof Buffer)) {
280
+ callback(new Error('invalid input'));
281
+ return;
282
+ }
283
+ if (this._closed) {
284
+ callback(new Error('lzma binding closed'));
285
+ return;
286
+ }
287
+ /* v8 ignore next */
288
+ let flushFlag;
289
+ if (last) {
290
+ flushFlag = liblzma.LZMA_FINISH;
291
+ }
292
+ else {
293
+ flushFlag = this._flushFlag;
294
+ // once we've flushed the last of the queue, stop flushing and
295
+ // go back to the normal behavior.
296
+ if (chunk && chunk.length >= ws.length) {
297
+ this._flushFlag = this._opts.flushFlag;
298
+ }
299
+ }
300
+ /* v8 ignore next */
301
+ this._processChunk(chunk, flushFlag, callback);
66
302
  }
67
- // Multithreading is only available for encoding, so if we are encoding, check
68
- // opts threads value.
69
- if (mode === liblzma.STREAM_ENCODE) {
70
- if (!liblzma.HAS_THREADS_SUPPORT) {
71
- this._opts.threads = 1;
72
- }
73
- // By default set to maximum available processors
74
- if (this._opts.threads === 0) {
75
- this._opts.threads = maxThreads;
76
- }
303
+ _flush(callback) {
304
+ /* v8 ignore next 4 - Defensive check for double close scenario */
305
+ if (this._closed) {
306
+ process.nextTick(() => callback());
307
+ return;
308
+ }
309
+ this._transform(Buffer.alloc(0), 'utf8', callback);
77
310
  }
78
- // Initialize engine
79
- this.lzma = new liblzma.LZMA(mode, this._opts);
80
- this._closed = false;
81
- this._hadError = false;
82
- this._offset = 0;
83
- this._buffer = Buffer.alloc(this._chunkSize);
84
- this.on('onerror', (errno) => {
85
- var error;
86
- this._hadError = true;
87
- error = new Error(exports.messages[errno]);
88
- error.errno = errno;
89
- error.code = errno;
90
- return this.emit('error', error);
91
- });
92
- this.once('end', this.close);
93
- }
94
-
95
- flush(kind, callback) {
96
- var ws;
97
- ws = this._writableState;
98
- if (typeof kind === 'function' || (typeof kind === 'undefined' && !callback)) {
99
- [callback, kind] = [kind, liblzma.LZMA_SYNC_FLUSH];
311
+ _processChunk(chunk, flushFlag, cb) {
312
+ const async = typeof cb === 'function';
313
+ // Sanity checks
314
+ assert.ok(!this._closed, 'Stream closed!');
315
+ let availInBefore = chunk?.length;
316
+ let availOutBefore = this._chunkSize - this._offset;
317
+ let inOff = 0;
318
+ /* v8 ignore next 3 */
319
+ if (!async) {
320
+ // Doing it synchronously
321
+ const buffers = [];
322
+ let nread = 0;
323
+ let error = null;
324
+ /* v8 ignore next */
325
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Complex but necessary LZMA callback logic
326
+ const callback = (errno, availInAfter, availOutAfter) => {
327
+ /* v8 ignore start */
328
+ if (this._hadError) {
329
+ return false;
330
+ }
331
+ // if LZMA engine returned something else, we are running into trouble!
332
+ if (errno !== liblzma.LZMA_OK && errno !== liblzma.LZMA_STREAM_END) {
333
+ this.emit('onerror', errno);
334
+ return false;
335
+ }
336
+ /* v8 ignore stop */
337
+ const used = availOutBefore - availOutAfter;
338
+ assert.ok(used >= 0, `More bytes after than before! Delta = ${used}`);
339
+ if (used > 0) {
340
+ const out = this._buffer.subarray(this._offset, this._offset + used);
341
+ this._offset += used;
342
+ buffers.push(out);
343
+ nread += used;
344
+ }
345
+ /* v8 ignore start */
346
+ // exhausted the output buffer, or used all the input create a new one.
347
+ if (availOutAfter === 0 || this._offset >= this._chunkSize) {
348
+ availOutBefore = this._chunkSize;
349
+ this._reallocateBuffer();
350
+ }
351
+ if (availOutAfter === 0 || availInAfter > 0) {
352
+ inOff += (availInBefore ?? 0) - availInAfter;
353
+ availInBefore = availInAfter;
354
+ return true;
355
+ }
356
+ /* v8 ignore stop */
357
+ return false;
358
+ };
359
+ /* v8 ignore start */
360
+ this.on('error', (e) => {
361
+ error = e;
362
+ });
363
+ /* v8 ignore stop */
364
+ /* v8 ignore next - processing loop entry */
365
+ while (true) {
366
+ const [status, availInAfter, availOutAfter] = this.lzma.codeSync(flushFlag, chunk, inOff, availInBefore, this._buffer, this._offset);
367
+ /* v8 ignore start */
368
+ if (this._hadError || !callback(status, availInAfter, availOutAfter)) {
369
+ break;
370
+ }
371
+ /* v8 ignore stop */
372
+ }
373
+ /* v8 ignore start */
374
+ if (this._hadError) {
375
+ throw error ?? new Error('Unknown LZMA error');
376
+ }
377
+ /* v8 ignore stop */
378
+ /* v8 ignore next - normal cleanup path */
379
+ this.close();
380
+ const buf = Buffer.concat(buffers, nread);
381
+ return buf;
382
+ }
383
+ // Async path
384
+ const callback = (errno, availInAfter, availOutAfter) => {
385
+ /* v8 ignore next 3 - error state handling is difficult to test */
386
+ if (this._hadError) {
387
+ return false;
388
+ }
389
+ /* v8 ignore next 3 - async error path handling */
390
+ // if LZMA engine returned something else, we are running into trouble!
391
+ if (errno !== liblzma.LZMA_OK && errno !== liblzma.LZMA_STREAM_END) {
392
+ this.emit('onerror', errno);
393
+ return false;
394
+ }
395
+ /* v8 ignore next */
396
+ const used = availOutBefore - availOutAfter;
397
+ assert.ok(used >= 0, `More bytes after than before! Delta = ${used}`);
398
+ if (used > 0) {
399
+ const out = this._buffer.subarray(this._offset, this._offset + used);
400
+ this._offset += used;
401
+ this.push(out);
402
+ }
403
+ // exhausted the output buffer, or used all the input create a new one.
404
+ if (availOutAfter === 0 || this._offset >= this._chunkSize) {
405
+ availOutBefore = this._chunkSize;
406
+ this._reallocateBuffer();
407
+ }
408
+ if (availOutAfter === 0 || availInAfter > 0) {
409
+ /* v8 ignore next 2 - complex async processing continuation */
410
+ inOff += (availInBefore ?? 0) - availInAfter;
411
+ availInBefore = availInAfter;
412
+ this.lzma.code(flushFlag, chunk, inOff, availInBefore, this._buffer, this._offset, callback);
413
+ return false;
414
+ }
415
+ // Safely call callback to avoid uncaught exceptions
416
+ if (cb && !this._closed) {
417
+ try {
418
+ cb();
419
+ }
420
+ catch (error) {
421
+ // If callback throws, emit error instead of crashing
422
+ this.emit('onerror', liblzma.LZMA_PROG_ERROR);
423
+ }
424
+ }
425
+ return false;
426
+ };
427
+ this.lzma.code(flushFlag, chunk, inOff, availInBefore, this._buffer, this._offset, callback);
428
+ return undefined;
100
429
  }
101
- if (ws.ended) {
102
- if (callback) {
103
- process.nextTick(callback);
104
- }
105
- } else if (ws.ending) {
106
- if (callback) {
107
- this.once('end', callback);
108
- }
109
- } else if (ws.needDrain) {
110
- this.once('drain', () => {
111
- this.flush(callback);
112
- });
113
- } else {
114
- this._flushFlag = kind;
115
- this.write(Buffer.alloc(0), '', callback);
430
+ }
431
+ export class Xz extends XzStream {
432
+ constructor(lzmaOptions, options) {
433
+ super(liblzma.STREAM_ENCODE, lzmaOptions, options);
116
434
  }
117
- }
118
-
119
- close(callback) {
120
- if (callback) {
121
- process.nextTick(callback);
435
+ }
436
+ export class Unxz extends XzStream {
437
+ constructor(lzmaOptions, options) {
438
+ super(liblzma.STREAM_DECODE, lzmaOptions, options);
122
439
  }
123
- // We will trigger this case with #xz and #unxz
124
- if (this._closed) {
125
- return;
440
+ }
441
+ /* v8 ignore next */
442
+ // Factory functions - placed immediately after class definitions to avoid circular dependencies
443
+ export function createXz(lzmaOptions, options) {
444
+ return new Xz(lzmaOptions, options);
445
+ }
446
+ /* v8 ignore next */
447
+ export function createUnxz(lzmaOptions, options) {
448
+ return new Unxz(lzmaOptions, options);
449
+ }
450
+ /* v8 ignore next */
451
+ export function hasThreads() {
452
+ return liblzma.HAS_THREADS_SUPPORT;
453
+ }
454
+ /* v8 ignore next */
455
+ // Error messages enum for better type safety
456
+ export var LZMAErrorMessage;
457
+ (function (LZMAErrorMessage) {
458
+ LZMAErrorMessage["SUCCESS"] = "Operation completed successfully";
459
+ LZMAErrorMessage["STREAM_END"] = "End of stream was reached";
460
+ LZMAErrorMessage["NO_CHECK"] = "Input stream has no integrity check";
461
+ LZMAErrorMessage["UNSUPPORTED_CHECK"] = "Cannot calculate the integrity check";
462
+ LZMAErrorMessage["GET_CHECK"] = "Integrity check type is not available";
463
+ LZMAErrorMessage["MEM_ERROR"] = "Cannot allocate memory";
464
+ LZMAErrorMessage["MEMLIMIT_ERROR"] = "Memory usage limit was reached";
465
+ LZMAErrorMessage["FORMAT_ERROR"] = "File format not recognized";
466
+ LZMAErrorMessage["OPTIONS_ERROR"] = "Invalid or unsupported options";
467
+ LZMAErrorMessage["DATA_ERROR"] = "Data is corrupt";
468
+ LZMAErrorMessage["BUF_ERROR"] = "No progress is possible";
469
+ LZMAErrorMessage["PROG_ERROR"] = "Programming error";
470
+ })(LZMAErrorMessage || (LZMAErrorMessage = {}));
471
+ // Legacy array export for backward compatibility
472
+ export const messages = [
473
+ LZMAErrorMessage.SUCCESS,
474
+ LZMAErrorMessage.STREAM_END,
475
+ LZMAErrorMessage.NO_CHECK,
476
+ LZMAErrorMessage.UNSUPPORTED_CHECK,
477
+ LZMAErrorMessage.GET_CHECK,
478
+ LZMAErrorMessage.MEM_ERROR,
479
+ LZMAErrorMessage.MEMLIMIT_ERROR,
480
+ LZMAErrorMessage.FORMAT_ERROR,
481
+ LZMAErrorMessage.OPTIONS_ERROR,
482
+ LZMAErrorMessage.DATA_ERROR,
483
+ LZMAErrorMessage.BUF_ERROR,
484
+ LZMAErrorMessage.PROG_ERROR,
485
+ ];
486
+ export function unxz(buffer, optsOrCallback, callback) {
487
+ let opts;
488
+ let cb;
489
+ /* v8 ignore next - simple parameter parsing */
490
+ if (typeof optsOrCallback === 'function') {
491
+ cb = optsOrCallback;
492
+ opts = {};
126
493
  }
127
- this.lzma.close();
128
- this._closed = true;
129
- process.nextTick(() => {
130
- this.emit('close');
131
- });
132
- }
133
-
134
- _transform(chunk, encoding, callback) {
135
- var ending, flushFlag, last, ws;
136
- flushFlag = void 0;
137
- ws = this._writableState;
138
- ending = ws.ending || ws.ended;
139
- last = ending && (!chunk || ws.length === chunk.length);
140
- if (chunk !== null && !(chunk instanceof Buffer)) {
141
- return callback(new Error("invalid input"));
494
+ else {
495
+ opts = optsOrCallback;
496
+ cb = callback;
142
497
  }
143
- if (this._closed) {
144
- return callback(new Error("lzma binding closed"));
498
+ xzBuffer(new Unxz(opts), buffer, cb);
499
+ }
500
+ export function unxzSync(buffer, opts) {
501
+ return xzBufferSync(new Unxz(opts), buffer);
502
+ }
503
+ export function xz(buffer, optsOrCallback, callback) {
504
+ let opts;
505
+ let cb;
506
+ /* v8 ignore next - simple parameter parsing */
507
+ if (typeof optsOrCallback === 'function') {
508
+ cb = optsOrCallback;
509
+ opts = {};
145
510
  }
146
- // If it's the last chunk, or a final flush, we use the LZMA_FINISH flush flag.
147
- // If it's explicitly flushing at some other time, then we use
148
- // LZMA_SYNC_FLUSH.
149
- if (last) {
150
- flushFlag = liblzma.LZMA_FINISH;
151
- } else {
152
- flushFlag = this._flushFlag;
153
- if (chunk.length >= ws.length) {
154
- // once we've flushed the last of the queue, stop flushing and
155
- // go back to the normal behavior.
156
- this._flushFlag = this._opts.flushFlag || liblzma.LZMA_RUN;
157
- }
511
+ else {
512
+ opts = optsOrCallback;
513
+ cb = callback;
158
514
  }
159
- this._processChunk(chunk, flushFlag, callback);
160
- }
161
-
162
- _flush(callback) {
163
- this._transform(Buffer.alloc(0), '', callback);
164
- }
165
-
166
- _processChunk(chunk, flushFlag, cb) {
167
- var async, availInBefore, availOutBefore, buf, buffers, callback, error, inOff, nread, res;
168
- // If user setting async is set to true, then it will all depend on whether
169
- // we can actually be async, or not. If user set explicitly async to false
170
- // then whether we have a callback or not becomes irrelevant..
171
- // TODO: Works in v0.11
172
- //async = util.isFunction cb
173
- // until then...
174
- async = typeof cb === 'function';
175
- // Sanity checks
176
- assert(!this._closed, "Stream closed!");
177
- availInBefore = chunk && chunk.length;
178
- availOutBefore = this._chunkSize - this._offset;
179
- inOff = 0;
180
- // So far it looks like Zlib _processChunk in CoffeeScript. But to make C++
181
- // code easier when it comes to emitting events and callback calling sync/async
182
- // we handle error codes here. If anything wrong is returned, we emit event
183
- // and return false in case we are synchronous.
184
- callback = (errno, availInAfter, availOutAfter) => {
185
- var out, used;
186
- if (this._hadError) {
187
- return;
188
- }
189
- // if LZMA engine returned something else, we are running into trouble!
190
- if (errno !== liblzma.LZMA_OK && errno !== liblzma.LZMA_STREAM_END) {
191
- this.emit('onerror', errno);
192
- return false;
193
- }
194
- used = availOutBefore - availOutAfter;
195
- assert(used >= 0, `More bytes after than before! Delta = ${used}`);
196
- if (used > 0) {
197
- out = this._buffer.slice(this._offset, this._offset + used);
198
- this._offset += used;
199
- if (async) {
200
- this.push(out);
201
- } else {
202
- buffers.push(out);
203
- nread += used;
204
- }
205
- }
206
- // exhausted the output buffer, or used all the input create a new one.
207
- if (availOutAfter === 0 || this._offset >= this._chunkSize) {
208
- availOutBefore = this._chunkSize;
209
- this._offset = 0;
210
- this._buffer = Buffer.alloc(this._chunkSize);
211
- }
212
- if (availOutAfter === 0 || availInAfter > 0) {
213
- inOff += availInBefore - availInAfter;
214
- availInBefore = availInAfter;
215
- if (!async) {
216
- return true;
515
+ xzBuffer(new Xz(opts), buffer, cb);
516
+ }
517
+ export function xzSync(buffer, opts) {
518
+ return xzBufferSync(new Xz(opts), buffer);
519
+ }
520
+ // Promise-based APIs for modern async/await usage
521
+ export function xzAsync(buffer, opts) {
522
+ return new Promise((resolve, reject) => {
523
+ xz(buffer, opts || {}, (error, result) => {
524
+ /* v8 ignore next 3 - error handling is tested in callback-based tests */
525
+ if (error) {
526
+ reject(error);
527
+ }
528
+ else {
529
+ resolve(result);
530
+ }
531
+ });
532
+ });
533
+ }
534
+ export function unxzAsync(buffer, opts) {
535
+ return new Promise((resolve, reject) => {
536
+ unxz(buffer, opts || {}, (error, result) => {
537
+ /* v8 ignore next 2 - error handling is tested in callback-based tests */
538
+ if (error) {
539
+ reject(error);
540
+ }
541
+ else {
542
+ resolve(result);
543
+ }
544
+ });
545
+ });
546
+ }
547
+ function xzBuffer(engine, buffer, callback) {
548
+ const buffers = [];
549
+ let nread = 0;
550
+ const flow = () => {
551
+ let chunk;
552
+ // biome-ignore lint/suspicious/noAssignInExpressions: necessary for while loop pattern
553
+ while ((chunk = engine.read()) !== null) {
554
+ buffers.push(chunk);
555
+ nread += chunk.length;
217
556
  }
218
- this.lzma.code(flushFlag, chunk, inOff, availInBefore, this._buffer, this._offset, callback);
219
- return;
220
- }
221
- if (!async) {
222
- return false;
223
- }
224
- cb();
557
+ engine.once('readable', flow);
225
558
  };
226
- if (!async) {
227
- // Doing it synchronously
228
- buffers = [];
229
- nread = 0;
230
- error = null;
231
- this.on('error', function(e) {
232
- return error = e;
233
- });
234
- while (true) {
235
- res = this.lzma.codeSync(flushFlag, chunk, inOff, availInBefore, this._buffer, this._offset);
236
- if (!(!this._hadError && callback(res[0], res[1], res[2]))) {
237
- break;
238
- }
239
- }
240
- if (this._hadError) {
241
- throw error;
242
- }
243
- this.close();
244
- buf = Buffer.concat(buffers, nread);
245
- return buf;
559
+ const onEnd = () => {
560
+ const buf = Buffer.concat(buffers, nread);
561
+ callback(null, buf);
562
+ engine.close();
563
+ };
564
+ /* v8 ignore next 5 - error callback path */
565
+ const onError = (err) => {
566
+ engine.removeListener('end', onEnd);
567
+ engine.removeListener('readable', flow);
568
+ callback(err);
569
+ };
570
+ engine.on('error', onError);
571
+ engine.on('end', onEnd);
572
+ engine.end(buffer);
573
+ flow();
574
+ }
575
+ function xzBufferSync(engine, buffer) {
576
+ let buf;
577
+ if (typeof buffer === 'string') {
578
+ buf = Buffer.from(buffer);
246
579
  }
247
- this.lzma.code(flushFlag, chunk, inOff, availInBefore, this._buffer, this._offset, callback);
248
- }
249
-
250
- };
251
-
252
- Xz = class Xz extends XzStream {
253
- constructor(lzma_options, options) {
254
- super(liblzma.STREAM_ENCODE, lzma_options, options);
255
- }
256
-
257
- };
258
-
259
- Unxz = class Unxz extends XzStream {
260
- constructor(lzma_options, options) {
261
- super(liblzma.STREAM_DECODE, lzma_options, options);
262
- }
263
-
264
- };
265
-
266
- exports.Xz = Xz;
267
-
268
- exports.Unxz = Unxz;
269
-
270
- exports.hasThreads = function() {
271
- return liblzma.HAS_THREADS_SUPPORT;
272
- };
273
-
274
- exports.messages = ["Operation completed successfully", "End of stream was reached", "Input stream has no integrity check", "Cannot calculate the integrity check", "Integrity check type is not available", "Cannot allocate memory", "Memory usage limit was reached", "File format not recognized", "Invalid or unsupported options", "Data is corrupt", "No progress is possible", "Programming error"];
275
-
276
- exports.check = {
277
- "NONE": liblzma.LZMA_CHECK_NONE,
278
- "CRC32": liblzma.LZMA_CHECK_CRC32,
279
- "CRC64": liblzma.LZMA_CHECK_CRC64,
280
- "SHA256": liblzma.LZMA_CHECK_SHA256
281
- };
282
-
283
- exports.preset = {
284
- "DEFAULT": liblzma.LZMA_PRESET_DEFAULT,
285
- "EXTREME": liblzma.LZMA_PRESET_EXTREME
286
- };
287
-
288
- exports.flag = {
289
- "TELL_NO_CHECK": liblzma.LZMA_TELL_NO_CHECK,
290
- "TELL_UNSUPPORTED_CHECK": liblzma.LZMA_TELL_UNSUPPORTED_CHECK,
291
- "TELL_ANY_CHECK": liblzma.LZMA_TELL_ANY_CHECK,
292
- "CONCATENATED": liblzma.LZMA_CONCATENATED
293
- };
294
-
295
- exports.filter = {
296
- "LZMA2": liblzma.LZMA_FILTER_LZMA2,
297
- "X86": liblzma.LZMA_FILTER_X86,
298
- "POWERPC": liblzma.LZMA_FILTER_POWERPC,
299
- "IA64": liblzma.LZMA_FILTER_IA64,
300
- "ARM": liblzma.LZMA_FILTER_ARM,
301
- "ARMTHUMB": liblzma.LZMA_FILTER_ARMTHUMB,
302
- "SPARC": liblzma.LZMA_FILTER_SPARC
303
- };
304
-
305
- exports.mode = {
306
- "FAST": liblzma.LZMA_MODE_FAST,
307
- "NORMAL": liblzma.LZMA_MODE_NORMAL
308
- };
309
-
310
- exports.createXz = function(lzma_options, options) {
311
- return new Xz(lzma_options, options);
312
- };
313
-
314
- exports.createUnxz = function(lzma_options, options) {
315
- return new Unxz(lzma_options, options);
316
- };
317
-
318
- exports.unxz = function(buffer, opts, callback) {
319
- if (typeof opts === 'function') {
320
- [callback, opts] = [opts, {}];
321
- }
322
- return xzBuffer(new Unxz(opts), buffer, callback);
323
- };
324
-
325
- exports.unxzSync = function(buffer, opts) {
326
- return xzBufferSync(new Unxz(opts), buffer);
327
- };
328
-
329
- exports.xz = function(buffer, opts, callback) {
330
- if (typeof opts === 'function') {
331
- [callback, opts] = [opts, {}];
332
- }
333
- return xzBuffer(new Xz(opts), buffer, callback);
334
- };
335
-
336
- exports.xzSync = function(buffer, opts) {
337
- return xzBufferSync(new Xz(opts), buffer);
338
- };
339
-
340
- xzBuffer = function(engine, buffer, callback) {
341
- var buffers, flow, nread, onEnd, onError;
342
- buffers = [];
343
- nread = 0;
344
- flow = function() {
345
- var chunk;
346
- chunk = void 0;
347
- while (null !== (chunk = engine.read())) {
348
- buffers.push(chunk);
349
- nread += chunk.length;
580
+ else if (buffer instanceof Buffer) {
581
+ buf = buffer;
582
+ /* v8 ignore next 3 - type validation error path */
350
583
  }
351
- engine.once('readable', flow);
352
- };
353
- onEnd = function() {
354
- var buf;
355
- buf = Buffer.concat(buffers, nread);
356
- buffers = [];
357
- callback(null, buf);
358
- engine.close();
359
- };
360
- onError = function(err) {
361
- engine.removeListener('end', onEnd);
362
- engine.removeListener('readable', flow);
363
- callback(err);
364
- };
365
- engine.on('error', onError);
366
- engine.on('end', onEnd);
367
- engine.end(buffer);
368
- flow();
369
- };
370
-
371
- xzBufferSync = function(engine, buffer) {
372
- if (typeof buffer === 'string') {
373
- buffer = Buffer.from(buffer);
374
- }
375
- if (!(buffer instanceof Buffer)) {
376
- throw new TypeError("Not a string or buffer");
377
- }
378
- return engine._processChunk(buffer, liblzma.LZMA_FINISH);
584
+ else {
585
+ throw new TypeError('Not a string or buffer');
586
+ }
587
+ return engine._processChunk(buf, liblzma.LZMA_FINISH);
588
+ }
589
+ // File-based compression/decompression helpers
590
+ import { createReadStream, createWriteStream } from 'node:fs';
591
+ import { pipeline } from 'node:stream/promises';
592
+ /**
593
+ * Compress a file using XZ compression
594
+ * @param inputPath Path to input file
595
+ * @param outputPath Path to output compressed file
596
+ * @param opts LZMA compression options
597
+ * @returns Promise that resolves when compression is complete
598
+ */
599
+ export async function xzFile(inputPath, outputPath, opts) {
600
+ const input = createReadStream(inputPath);
601
+ const output = createWriteStream(outputPath);
602
+ const compressor = createXz(opts);
603
+ await pipeline(input, compressor, output);
604
+ }
605
+ /**
606
+ * Decompress an XZ compressed file
607
+ * @param inputPath Path to compressed input file
608
+ * @param outputPath Path to output decompressed file
609
+ * @param opts LZMA decompression options
610
+ * @returns Promise that resolves when decompression is complete
611
+ */
612
+ export async function unxzFile(inputPath, outputPath, opts) {
613
+ const input = createReadStream(inputPath);
614
+ const output = createWriteStream(outputPath);
615
+ const decompressor = createUnxz(opts);
616
+ await pipeline(input, decompressor, output);
617
+ }
618
+ // Export default object for CommonJS compatibility - use individual exports to avoid duplication
619
+ export default {
620
+ Xz,
621
+ Unxz,
622
+ XzStream,
623
+ hasThreads,
624
+ messages,
625
+ check,
626
+ preset,
627
+ flag,
628
+ filter,
629
+ mode,
630
+ createXz,
631
+ createUnxz,
632
+ unxz,
633
+ unxzSync,
634
+ xz,
635
+ xzSync,
636
+ xzAsync,
637
+ unxzAsync,
638
+ // Reference individual exports to avoid duplication
639
+ LZMA_RUN,
640
+ LZMA_SYNC_FLUSH,
641
+ LZMA_FULL_FLUSH,
642
+ LZMA_FINISH,
643
+ LZMA_OK,
644
+ LZMA_STREAM_END,
645
+ LZMA_NO_CHECK,
646
+ LZMA_UNSUPPORTED_CHECK,
647
+ LZMA_GET_CHECK,
648
+ LZMA_MEM_ERROR,
649
+ LZMA_MEMLIMIT_ERROR,
650
+ LZMA_FORMAT_ERROR,
651
+ LZMA_OPTIONS_ERROR,
652
+ LZMA_DATA_ERROR,
653
+ LZMA_BUF_ERROR,
654
+ LZMA_PROG_ERROR,
655
+ LZMA_FILTER_X86,
656
+ LZMA_FILTER_POWERPC,
657
+ LZMA_FILTER_IA64,
658
+ LZMA_FILTER_ARM,
659
+ LZMA_FILTER_ARMTHUMB,
660
+ LZMA_FILTERS_MAX,
379
661
  };
380
-
381
- module.exports = exports;
662
+ //# sourceMappingURL=lzma.js.map