xz-compat 1.1.4 → 1.2.1

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/sevenz.ts"],"sourcesContent":["/**\n * High-Level 7z-Specific Decoders\n *\n * These functions accept properties separately (matching 7z format structure)\n * and execute either the native lzma-native path or the pure JS fallback.\n *\n * This provides automatic native acceleration for 7z files while maintaining\n * the API that 7z-iterator expects.\n *\n * IMPORTANT: Buffer Management Pattern\n *\n * ❌ SLOW - DO NOT use OutputSink with buffering:\n * const chunks: Buffer[] = [];\n * decodeLzma2(data, props, size, { write: c => chunks.push(c) });\n * return Buffer.concat(chunks); // ← 3 copies: push + concat + return\n *\n * OutWindow → chunks.push(chunk) → Buffer.concat(chunks) → result\n * COPY TO ARRAY COPY ALL FINAL BUFFER\n *\n * ✅ FAST - Direct return (let decoder manage buffer):\n * return decodeLzma2(data, props, size) as Buffer; // ← 1 copy\n *\n * OutWindow → pre-allocated buffer → result\n * DIRECT WRITE\n *\n * The decodeLzma2() function internally pre-allocates the exact output size\n * and writes directly to it. Wrapping with an OutputSink that buffers to an\n * array defeats this optimization by creating unnecessary intermediate copies.\n */\n\nimport { decodeLzma2 } from './lzma/sync/Lzma2Decoder.ts';\nimport { decodeLzma } from './lzma/sync/LzmaDecoder.ts';\nimport { tryLoadNative } from './native.ts';\n\n/** Callback for async decode operations: (error, result) => void */\nexport type DecodeCallback<T = Buffer> = (error: Error | null, result?: T) => void;\n\n/** Callback invoked when an async 7z decode completes */\nexport type SevenZDecodeCallback = DecodeCallback<Buffer>;\n\nconst schedule = typeof setImmediate === 'function' ? setImmediate : (fn: () => void) => process.nextTick(fn);\n\nexport function decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number, callback: SevenZDecodeCallback): void;\nexport function decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number): Promise<Buffer>;\n/**\n * Decode LZMA-compressed data from a 7z file\n */\nexport function decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number, callback?: SevenZDecodeCallback): Promise<Buffer> | void {\n const worker = (cb: SevenZDecodeCallback) => {\n const fallback = () => {\n schedule(() => {\n try {\n cb(null, decodeLzma(data, properties, unpackSize) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n });\n };\n\n const native = tryLoadNative();\n if (native?.lzma) {\n try {\n const promise = native.lzma(data, properties, unpackSize);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as Buffer))));\n}\n\n/**\n * Decode LZMA2-compressed data from a 7z file\n */\nexport function decode7zLzma2(data: Buffer, properties: Buffer, unpackSize: number | undefined, callback: SevenZDecodeCallback): void;\nexport function decode7zLzma2(data: Buffer, properties: Buffer, unpackSize?: number): Promise<Buffer>;\nexport function decode7zLzma2(data: Buffer, properties: Buffer, unpackSize?: number, callback?: SevenZDecodeCallback): Promise<Buffer> | void {\n const worker = (cb: SevenZDecodeCallback) => {\n const fallback = () => {\n schedule(() => {\n try {\n cb(null, decodeLzma2(data, properties, unpackSize) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n });\n };\n\n const native = tryLoadNative();\n if (native?.lzma2) {\n try {\n const promise = native.lzma2(data, properties, unpackSize);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as Buffer))));\n}\n"],"names":["decode7zLzma","decode7zLzma2","schedule","setImmediate","fn","process","nextTick","data","properties","unpackSize","callback","worker","cb","fallback","decodeLzma","err","native","tryLoadNative","lzma","promise","then","value","Promise","resolve","reject","decodeLzma2","lzma2"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BC;;;;;;;;;;;QAmBeA;eAAAA;;QAoCAC;eAAAA;;;8BArDY;6BACD;wBACG;AAQ9B,IAAMC,WAAW,OAAOC,iBAAiB,aAAaA,eAAe,SAACC;WAAmBC,QAAQC,QAAQ,CAACF;;AAOnG,SAASJ,aAAaO,IAAY,EAAEC,UAAkB,EAAEC,UAAkB,EAAEC,QAA+B;IAChH,IAAMC,SAAS,SAACC;QACd,IAAMC,WAAW;YACfX,SAAS;gBACP,IAAI;oBACFU,GAAG,MAAME,IAAAA,yBAAU,EAACP,MAAMC,YAAYC;gBACxC,EAAE,OAAOM,KAAK;oBACZH,GAAGG;gBACL;YACF;QACF;QAEA,IAAMC,SAASC,IAAAA,uBAAa;QAC5B,IAAID,mBAAAA,6BAAAA,OAAQE,IAAI,EAAE;YAChB,IAAI;gBACF,IAAMC,UAAUH,OAAOE,IAAI,CAACX,MAAMC,YAAYC;gBAC9C,IAAIU,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,SAACC;+BAAUT,GAAG,MAAMS;uBAAQR;oBACzC;gBACF;YACF,EAAE,eAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOH,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIY,QAAQ,SAACC,SAASC;eAAWb,OAAO,SAACI,KAAKM;mBAAWN,MAAMS,OAAOT,OAAOQ,QAAQF;;;AAC9F;AAOO,SAASpB,cAAcM,IAAY,EAAEC,UAAkB,EAAEC,UAAmB,EAAEC,QAA+B;IAClH,IAAMC,SAAS,SAACC;QACd,IAAMC,WAAW;YACfX,SAAS;gBACP,IAAI;oBACFU,GAAG,MAAMa,IAAAA,2BAAW,EAAClB,MAAMC,YAAYC;gBACzC,EAAE,OAAOM,KAAK;oBACZH,GAAGG;gBACL;YACF;QACF;QAEA,IAAMC,SAASC,IAAAA,uBAAa;QAC5B,IAAID,mBAAAA,6BAAAA,OAAQU,KAAK,EAAE;YACjB,IAAI;gBACF,IAAMP,UAAUH,OAAOU,KAAK,CAACnB,MAAMC,YAAYC;gBAC/C,IAAIU,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,SAACC;+BAAUT,GAAG,MAAMS;uBAAQR;oBACzC;gBACF;YACF,EAAE,eAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOH,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIY,QAAQ,SAACC,SAASC;eAAWb,OAAO,SAACI,KAAKM;mBAAWN,MAAMS,OAAOT,OAAOQ,QAAQF;;;AAC9F"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/sevenz.ts"],"sourcesContent":["/**\n * High-Level 7z-Specific Decoders\n *\n * These functions accept properties separately (matching 7z format structure)\n * and execute either the native lzma-native path or the pure JS fallback.\n *\n * This provides automatic native acceleration for 7z files while maintaining\n * the API that 7z-iterator expects.\n *\n * IMPORTANT: Buffer Management Pattern\n *\n * ❌ SLOW - DO NOT use OutputSink with buffering:\n * const chunks: Buffer[] = [];\n * decodeLzma2(data, props, size, { write: c => chunks.push(c) });\n * return Buffer.concat(chunks); // ← 3 copies: push + concat + return\n *\n * OutWindow → chunks.push(chunk) → Buffer.concat(chunks) → result\n * COPY TO ARRAY COPY ALL FINAL BUFFER\n *\n * ✅ FAST - Direct return (let decoder manage buffer):\n * return decodeLzma2(data, props, size) as Buffer; // ← 1 copy\n *\n * OutWindow → pre-allocated buffer → result\n * DIRECT WRITE\n *\n * The decodeLzma2() function internally pre-allocates the exact output size\n * and writes directly to it. Wrapping with an OutputSink that buffers to an\n * array defeats this optimization by creating unnecessary intermediate copies.\n */\n\nimport type { BufferLike } from 'extract-base-iterator';\nimport { decodeLzma2 } from './lzma/sync/Lzma2Decoder.ts';\nimport { decodeLzma } from './lzma/sync/LzmaDecoder.ts';\nimport { tryLoadNative } from './native.ts';\n\n/** Callback for async decode operations: (error, result) => void */\nexport type DecodeCallback<T = Buffer> = (error: Error | null, result?: T) => void;\n\n/** Callback invoked when an async 7z decode completes */\nexport type SevenZDecodeCallback = DecodeCallback<Buffer>;\n\nconst schedule = typeof setImmediate === 'function' ? setImmediate : (fn: () => void) => process.nextTick(fn);\n\nexport function decode7zLzma(data: BufferLike, properties: Buffer, unpackSize: number, callback: SevenZDecodeCallback): void;\nexport function decode7zLzma(data: BufferLike, properties: Buffer, unpackSize: number): Promise<Buffer>;\n/**\n * Decode LZMA-compressed data from a 7z file\n */\nexport function decode7zLzma(data: BufferLike, properties: Buffer, unpackSize: number, callback?: SevenZDecodeCallback): Promise<Buffer> | void {\n const worker = (cb: SevenZDecodeCallback) => {\n const fallback = () => {\n schedule(() => {\n try {\n cb(null, decodeLzma(data, properties, unpackSize) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n });\n };\n\n const native = tryLoadNative();\n if (native?.lzma) {\n try {\n // Native lzma-native expects Buffer, convert if needed\n const buf = Buffer.isBuffer(data) ? data : data.toBuffer();\n const promise = native.lzma(buf, properties, unpackSize);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as Buffer))));\n}\n\n/**\n * Decode LZMA2-compressed data from a 7z file\n */\nexport function decode7zLzma2(data: BufferLike, properties: Buffer, unpackSize: number | undefined, callback: SevenZDecodeCallback): void;\nexport function decode7zLzma2(data: BufferLike, properties: Buffer, unpackSize?: number): Promise<Buffer>;\nexport function decode7zLzma2(data: BufferLike, properties: Buffer, unpackSize?: number, callback?: SevenZDecodeCallback): Promise<Buffer> | void {\n const worker = (cb: SevenZDecodeCallback) => {\n const fallback = () => {\n schedule(() => {\n try {\n cb(null, decodeLzma2(data, properties, unpackSize) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n });\n };\n\n const native = tryLoadNative();\n if (native?.lzma2) {\n try {\n // Native lzma-native expects Buffer, convert if needed\n const buf = Buffer.isBuffer(data) ? data : data.toBuffer();\n const promise = native.lzma2(buf, properties, unpackSize);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as Buffer))));\n}\n"],"names":["decode7zLzma","decode7zLzma2","schedule","setImmediate","fn","process","nextTick","data","properties","unpackSize","callback","worker","cb","fallback","decodeLzma","err","native","tryLoadNative","lzma","buf","Buffer","isBuffer","toBuffer","promise","then","value","Promise","resolve","reject","decodeLzma2","lzma2"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BC;;;;;;;;;;;QAoBeA;eAAAA;;QAsCAC;eAAAA;;;8BAvDY;6BACD;wBACG;AAQ9B,IAAMC,WAAW,OAAOC,iBAAiB,aAAaA,eAAe,SAACC;WAAmBC,QAAQC,QAAQ,CAACF;;AAOnG,SAASJ,aAAaO,IAAgB,EAAEC,UAAkB,EAAEC,UAAkB,EAAEC,QAA+B;IACpH,IAAMC,SAAS,SAACC;QACd,IAAMC,WAAW;YACfX,SAAS;gBACP,IAAI;oBACFU,GAAG,MAAME,IAAAA,yBAAU,EAACP,MAAMC,YAAYC;gBACxC,EAAE,OAAOM,KAAK;oBACZH,GAAGG;gBACL;YACF;QACF;QAEA,IAAMC,SAASC,IAAAA,uBAAa;QAC5B,IAAID,mBAAAA,6BAAAA,OAAQE,IAAI,EAAE;YAChB,IAAI;gBACF,uDAAuD;gBACvD,IAAMC,MAAMC,OAAOC,QAAQ,CAACd,QAAQA,OAAOA,KAAKe,QAAQ;gBACxD,IAAMC,UAAUP,OAAOE,IAAI,CAACC,KAAKX,YAAYC;gBAC7C,IAAIc,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,SAACC;+BAAUb,GAAG,MAAMa;uBAAQZ;oBACzC;gBACF;YACF,EAAE,eAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOH,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIgB,QAAQ,SAACC,SAASC;eAAWjB,OAAO,SAACI,KAAKU;mBAAWV,MAAMa,OAAOb,OAAOY,QAAQF;;;AAC9F;AAOO,SAASxB,cAAcM,IAAgB,EAAEC,UAAkB,EAAEC,UAAmB,EAAEC,QAA+B;IACtH,IAAMC,SAAS,SAACC;QACd,IAAMC,WAAW;YACfX,SAAS;gBACP,IAAI;oBACFU,GAAG,MAAMiB,IAAAA,2BAAW,EAACtB,MAAMC,YAAYC;gBACzC,EAAE,OAAOM,KAAK;oBACZH,GAAGG;gBACL;YACF;QACF;QAEA,IAAMC,SAASC,IAAAA,uBAAa;QAC5B,IAAID,mBAAAA,6BAAAA,OAAQc,KAAK,EAAE;YACjB,IAAI;gBACF,uDAAuD;gBACvD,IAAMX,MAAMC,OAAOC,QAAQ,CAACd,QAAQA,OAAOA,KAAKe,QAAQ;gBACxD,IAAMC,UAAUP,OAAOc,KAAK,CAACX,KAAKX,YAAYC;gBAC9C,IAAIc,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,SAACC;+BAAUb,GAAG,MAAMa;uBAAQZ;oBACzC;gBACF;YACF,EAAE,eAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOH,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIgB,QAAQ,SAACC,SAASC;eAAWjB,OAAO,SAACI,KAAKU;mBAAWV,MAAMa,OAAOb,OAAOY,QAAQF;;;AAC9F"}
@@ -13,6 +13,7 @@
13
13
  * 0xC0-0xDF = LZMA chunk, reset state + new properties
14
14
  * 0xE0-0xFF = LZMA chunk, reset dictionary + state + new properties
15
15
  */
16
+ import type { BufferLike } from 'extract-base-iterator';
16
17
  /**
17
18
  * LZMA properties extracted from chunk header
18
19
  */
@@ -53,11 +54,11 @@ export type ParseResult = {
53
54
  /**
54
55
  * Parse an LZMA2 chunk header
55
56
  *
56
- * @param input - Input buffer
57
+ * @param input - Input buffer or BufferList
57
58
  * @param offset - Offset to start parsing
58
59
  * @returns Parsed chunk info or number of bytes needed
59
60
  */
60
- export declare function parseLzma2ChunkHeader(input: Buffer, offset: number): ParseResult;
61
+ export declare function parseLzma2ChunkHeader(input: BufferLike, offset: number): ParseResult;
61
62
  /** Result type for hasCompleteChunk with totalSize included on success */
62
63
  export type CompleteChunkResult = {
63
64
  success: true;
@@ -70,4 +71,4 @@ export type CompleteChunkResult = {
70
71
  /**
71
72
  * Check if we have enough data for the complete chunk (header + data)
72
73
  */
73
- export declare function hasCompleteChunk(input: Buffer, offset: number): CompleteChunkResult;
74
+ export declare function hasCompleteChunk(input: BufferLike, offset: number): CompleteChunkResult;
@@ -13,21 +13,30 @@
13
13
  * 0xC0-0xDF = LZMA chunk, reset state + new properties
14
14
  * 0xE0-0xFF = LZMA chunk, reset dictionary + state + new properties
15
15
  */ /**
16
- * LZMA properties extracted from chunk header
17
- */ /**
16
+ * Read a byte from BufferLike at offset
17
+ */ function readByte(input, offset) {
18
+ return Buffer.isBuffer(input) ? input[offset] : input.readByte(offset);
19
+ }
20
+ /**
21
+ * Get length of BufferLike
22
+ */ function getLength(input) {
23
+ return Buffer.isBuffer(input) ? input.length : input.length;
24
+ }
25
+ /**
18
26
  * Parse an LZMA2 chunk header
19
27
  *
20
- * @param input - Input buffer
28
+ * @param input - Input buffer or BufferList
21
29
  * @param offset - Offset to start parsing
22
30
  * @returns Parsed chunk info or number of bytes needed
23
31
  */ export function parseLzma2ChunkHeader(input, offset) {
24
- if (offset >= input.length) {
32
+ const len = getLength(input);
33
+ if (offset >= len) {
25
34
  return {
26
35
  success: false,
27
36
  needBytes: 1
28
37
  };
29
38
  }
30
- const control = input[offset];
39
+ const control = readByte(input, offset);
31
40
  // End of stream
32
41
  if (control === 0x00) {
33
42
  return {
@@ -46,13 +55,13 @@
46
55
  // Uncompressed chunk
47
56
  if (control === 0x01 || control === 0x02) {
48
57
  // Need 3 bytes: control + 2 size bytes
49
- if (offset + 3 > input.length) {
58
+ if (offset + 3 > len) {
50
59
  return {
51
60
  success: false,
52
- needBytes: 3 - (input.length - offset)
61
+ needBytes: 3 - (len - offset)
53
62
  };
54
63
  }
55
- const uncompSize = (input[offset + 1] << 8 | input[offset + 2]) + 1;
64
+ const uncompSize = (readByte(input, offset + 1) << 8 | readByte(input, offset + 2)) + 1;
56
65
  return {
57
66
  success: true,
58
67
  chunk: {
@@ -70,20 +79,20 @@
70
79
  if (control >= 0x80) {
71
80
  const hasNewProps = control >= 0xc0;
72
81
  const minHeaderSize = hasNewProps ? 6 : 5; // control + 2 uncomp + 2 comp + (1 props)
73
- if (offset + minHeaderSize > input.length) {
82
+ if (offset + minHeaderSize > len) {
74
83
  return {
75
84
  success: false,
76
- needBytes: minHeaderSize - (input.length - offset)
85
+ needBytes: minHeaderSize - (len - offset)
77
86
  };
78
87
  }
79
88
  // Parse sizes
80
89
  const uncompHigh = control & 0x1f;
81
- const uncompSize = (uncompHigh << 16 | input[offset + 1] << 8 | input[offset + 2]) + 1;
82
- const compSize = (input[offset + 3] << 8 | input[offset + 4]) + 1;
90
+ const uncompSize = (uncompHigh << 16 | readByte(input, offset + 1) << 8 | readByte(input, offset + 2)) + 1;
91
+ const compSize = (readByte(input, offset + 3) << 8 | readByte(input, offset + 4)) + 1;
83
92
  // Parse properties if present
84
93
  let newProps = null;
85
94
  if (hasNewProps) {
86
- const propsByte = input[offset + 5];
95
+ const propsByte = readByte(input, offset + 5);
87
96
  const lc = propsByte % 9;
88
97
  const remainder = ~~(propsByte / 9);
89
98
  const lp = remainder % 5;
@@ -123,10 +132,11 @@
123
132
  const { chunk } = result;
124
133
  const dataSize = chunk.type === 'uncompressed' ? chunk.uncompSize : chunk.compSize;
125
134
  const totalSize = chunk.headerSize + dataSize;
126
- if (offset + totalSize > input.length) {
135
+ const len = getLength(input);
136
+ if (offset + totalSize > len) {
127
137
  return {
128
138
  success: false,
129
- needBytes: totalSize - (input.length - offset)
139
+ needBytes: totalSize - (len - offset)
130
140
  };
131
141
  }
132
142
  return {
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/lzma/lib/Lzma2ChunkParser.ts"],"sourcesContent":["/**\n * LZMA2 Chunk Parser\n *\n * Shared parsing logic for LZMA2 chunk headers.\n * Used by both synchronous and streaming decoders.\n *\n * LZMA2 control byte ranges:\n * 0x00 = End of stream\n * 0x01 = Uncompressed chunk, dictionary reset\n * 0x02 = Uncompressed chunk, no dictionary reset\n * 0x80-0x9F = LZMA chunk, no reset (solid mode)\n * 0xA0-0xBF = LZMA chunk, reset state (probabilities)\n * 0xC0-0xDF = LZMA chunk, reset state + new properties\n * 0xE0-0xFF = LZMA chunk, reset dictionary + state + new properties\n */\n\n/**\n * LZMA properties extracted from chunk header\n */\nexport interface LzmaChunkProps {\n lc: number;\n lp: number;\n pb: number;\n}\n\n/**\n * Parsed LZMA2 chunk information\n */\nexport interface Lzma2Chunk {\n /** Chunk type */\n type: 'end' | 'uncompressed' | 'lzma';\n /** Total bytes consumed by header (including control byte) */\n headerSize: number;\n /** Whether to reset dictionary */\n dictReset: boolean;\n /** Whether to reset state/probabilities */\n stateReset: boolean;\n /** New LZMA properties (only for control >= 0xC0) */\n newProps: LzmaChunkProps | null;\n /** Uncompressed data size */\n uncompSize: number;\n /** Compressed data size (0 for uncompressed chunks) */\n compSize: number;\n}\n\n/**\n * Result of parsing attempt\n */\nexport type ParseResult = { success: true; chunk: Lzma2Chunk } | { success: false; needBytes: number };\n\n/**\n * Parse an LZMA2 chunk header\n *\n * @param input - Input buffer\n * @param offset - Offset to start parsing\n * @returns Parsed chunk info or number of bytes needed\n */\nexport function parseLzma2ChunkHeader(input: Buffer, offset: number): ParseResult {\n if (offset >= input.length) {\n return { success: false, needBytes: 1 };\n }\n\n const control = input[offset];\n\n // End of stream\n if (control === 0x00) {\n return {\n success: true,\n chunk: {\n type: 'end',\n headerSize: 1,\n dictReset: false,\n stateReset: false,\n newProps: null,\n uncompSize: 0,\n compSize: 0,\n },\n };\n }\n\n // Uncompressed chunk\n if (control === 0x01 || control === 0x02) {\n // Need 3 bytes: control + 2 size bytes\n if (offset + 3 > input.length) {\n return { success: false, needBytes: 3 - (input.length - offset) };\n }\n\n const uncompSize = ((input[offset + 1] << 8) | input[offset + 2]) + 1;\n\n return {\n success: true,\n chunk: {\n type: 'uncompressed',\n headerSize: 3,\n dictReset: control === 0x01,\n stateReset: false,\n newProps: null,\n uncompSize,\n compSize: 0,\n },\n };\n }\n\n // LZMA compressed chunk\n if (control >= 0x80) {\n const hasNewProps = control >= 0xc0;\n const minHeaderSize = hasNewProps ? 6 : 5; // control + 2 uncomp + 2 comp + (1 props)\n\n if (offset + minHeaderSize > input.length) {\n return { success: false, needBytes: minHeaderSize - (input.length - offset) };\n }\n\n // Parse sizes\n const uncompHigh = control & 0x1f;\n const uncompSize = ((uncompHigh << 16) | (input[offset + 1] << 8) | input[offset + 2]) + 1;\n const compSize = ((input[offset + 3] << 8) | input[offset + 4]) + 1;\n\n // Parse properties if present\n let newProps: LzmaChunkProps | null = null;\n if (hasNewProps) {\n const propsByte = input[offset + 5];\n const lc = propsByte % 9;\n const remainder = ~~(propsByte / 9);\n const lp = remainder % 5;\n const pb = ~~(remainder / 5);\n newProps = { lc, lp, pb };\n }\n\n return {\n success: true,\n chunk: {\n type: 'lzma',\n headerSize: minHeaderSize,\n dictReset: control >= 0xe0,\n stateReset: control >= 0xa0,\n newProps,\n uncompSize,\n compSize,\n },\n };\n }\n\n // Invalid control byte\n throw new Error(`Invalid LZMA2 control byte: 0x${control.toString(16)}`);\n}\n\n/** Result type for hasCompleteChunk with totalSize included on success */\nexport type CompleteChunkResult = { success: true; chunk: Lzma2Chunk; totalSize: number } | { success: false; needBytes: number };\n\n/**\n * Check if we have enough data for the complete chunk (header + data)\n */\nexport function hasCompleteChunk(input: Buffer, offset: number): CompleteChunkResult {\n const result = parseLzma2ChunkHeader(input, offset);\n\n if (result.success === false) {\n return { success: false, needBytes: result.needBytes };\n }\n\n const { chunk } = result;\n const dataSize = chunk.type === 'uncompressed' ? chunk.uncompSize : chunk.compSize;\n const totalSize = chunk.headerSize + dataSize;\n\n if (offset + totalSize > input.length) {\n return { success: false, needBytes: totalSize - (input.length - offset) };\n }\n\n return { success: true, chunk, totalSize };\n}\n"],"names":["parseLzma2ChunkHeader","input","offset","length","success","needBytes","control","chunk","type","headerSize","dictReset","stateReset","newProps","uncompSize","compSize","hasNewProps","minHeaderSize","uncompHigh","propsByte","lc","remainder","lp","pb","Error","toString","hasCompleteChunk","result","dataSize","totalSize"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/lzma/lib/Lzma2ChunkParser.ts"],"sourcesContent":["/**\n * LZMA2 Chunk Parser\n *\n * Shared parsing logic for LZMA2 chunk headers.\n * Used by both synchronous and streaming decoders.\n *\n * LZMA2 control byte ranges:\n * 0x00 = End of stream\n * 0x01 = Uncompressed chunk, dictionary reset\n * 0x02 = Uncompressed chunk, no dictionary reset\n * 0x80-0x9F = LZMA chunk, no reset (solid mode)\n * 0xA0-0xBF = LZMA chunk, reset state (probabilities)\n * 0xC0-0xDF = LZMA chunk, reset state + new properties\n * 0xE0-0xFF = LZMA chunk, reset dictionary + state + new properties\n */\n\nimport type { BufferLike } from 'extract-base-iterator';\n\n/**\n * LZMA properties extracted from chunk header\n */\nexport interface LzmaChunkProps {\n lc: number;\n lp: number;\n pb: number;\n}\n\n/**\n * Parsed LZMA2 chunk information\n */\nexport interface Lzma2Chunk {\n /** Chunk type */\n type: 'end' | 'uncompressed' | 'lzma';\n /** Total bytes consumed by header (including control byte) */\n headerSize: number;\n /** Whether to reset dictionary */\n dictReset: boolean;\n /** Whether to reset state/probabilities */\n stateReset: boolean;\n /** New LZMA properties (only for control >= 0xC0) */\n newProps: LzmaChunkProps | null;\n /** Uncompressed data size */\n uncompSize: number;\n /** Compressed data size (0 for uncompressed chunks) */\n compSize: number;\n}\n\n/**\n * Result of parsing attempt\n */\nexport type ParseResult = { success: true; chunk: Lzma2Chunk } | { success: false; needBytes: number };\n\n/**\n * Read a byte from BufferLike at offset\n */\nfunction readByte(input: BufferLike, offset: number): number {\n return Buffer.isBuffer(input) ? input[offset] : input.readByte(offset);\n}\n\n/**\n * Get length of BufferLike\n */\nfunction getLength(input: BufferLike): number {\n return Buffer.isBuffer(input) ? input.length : input.length;\n}\n\n/**\n * Parse an LZMA2 chunk header\n *\n * @param input - Input buffer or BufferList\n * @param offset - Offset to start parsing\n * @returns Parsed chunk info or number of bytes needed\n */\nexport function parseLzma2ChunkHeader(input: BufferLike, offset: number): ParseResult {\n const len = getLength(input);\n if (offset >= len) {\n return { success: false, needBytes: 1 };\n }\n\n const control = readByte(input, offset);\n\n // End of stream\n if (control === 0x00) {\n return {\n success: true,\n chunk: {\n type: 'end',\n headerSize: 1,\n dictReset: false,\n stateReset: false,\n newProps: null,\n uncompSize: 0,\n compSize: 0,\n },\n };\n }\n\n // Uncompressed chunk\n if (control === 0x01 || control === 0x02) {\n // Need 3 bytes: control + 2 size bytes\n if (offset + 3 > len) {\n return { success: false, needBytes: 3 - (len - offset) };\n }\n\n const uncompSize = ((readByte(input, offset + 1) << 8) | readByte(input, offset + 2)) + 1;\n\n return {\n success: true,\n chunk: {\n type: 'uncompressed',\n headerSize: 3,\n dictReset: control === 0x01,\n stateReset: false,\n newProps: null,\n uncompSize,\n compSize: 0,\n },\n };\n }\n\n // LZMA compressed chunk\n if (control >= 0x80) {\n const hasNewProps = control >= 0xc0;\n const minHeaderSize = hasNewProps ? 6 : 5; // control + 2 uncomp + 2 comp + (1 props)\n\n if (offset + minHeaderSize > len) {\n return { success: false, needBytes: minHeaderSize - (len - offset) };\n }\n\n // Parse sizes\n const uncompHigh = control & 0x1f;\n const uncompSize = ((uncompHigh << 16) | (readByte(input, offset + 1) << 8) | readByte(input, offset + 2)) + 1;\n const compSize = ((readByte(input, offset + 3) << 8) | readByte(input, offset + 4)) + 1;\n\n // Parse properties if present\n let newProps: LzmaChunkProps | null = null;\n if (hasNewProps) {\n const propsByte = readByte(input, offset + 5);\n const lc = propsByte % 9;\n const remainder = ~~(propsByte / 9);\n const lp = remainder % 5;\n const pb = ~~(remainder / 5);\n newProps = { lc, lp, pb };\n }\n\n return {\n success: true,\n chunk: {\n type: 'lzma',\n headerSize: minHeaderSize,\n dictReset: control >= 0xe0,\n stateReset: control >= 0xa0,\n newProps,\n uncompSize,\n compSize,\n },\n };\n }\n\n // Invalid control byte\n throw new Error(`Invalid LZMA2 control byte: 0x${control.toString(16)}`);\n}\n\n/** Result type for hasCompleteChunk with totalSize included on success */\nexport type CompleteChunkResult = { success: true; chunk: Lzma2Chunk; totalSize: number } | { success: false; needBytes: number };\n\n/**\n * Check if we have enough data for the complete chunk (header + data)\n */\nexport function hasCompleteChunk(input: BufferLike, offset: number): CompleteChunkResult {\n const result = parseLzma2ChunkHeader(input, offset);\n\n if (result.success === false) {\n return { success: false, needBytes: result.needBytes };\n }\n\n const { chunk } = result;\n const dataSize = chunk.type === 'uncompressed' ? chunk.uncompSize : chunk.compSize;\n const totalSize = chunk.headerSize + dataSize;\n const len = getLength(input);\n\n if (offset + totalSize > len) {\n return { success: false, needBytes: totalSize - (len - offset) };\n }\n\n return { success: true, chunk, totalSize };\n}\n"],"names":["readByte","input","offset","Buffer","isBuffer","getLength","length","parseLzma2ChunkHeader","len","success","needBytes","control","chunk","type","headerSize","dictReset","stateReset","newProps","uncompSize","compSize","hasNewProps","minHeaderSize","uncompHigh","propsByte","lc","remainder","lp","pb","Error","toString","hasCompleteChunk","result","dataSize","totalSize"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * Synchronous LZMA2 Decoder
3
3
  *
4
4
  * LZMA2 is a container format that wraps LZMA chunks with framing.
5
- * Decodes LZMA2 data from a buffer.
5
+ * Decodes LZMA2 data from a buffer or BufferList.
6
6
  */
7
7
  import { type BufferLike } from 'extract-base-iterator';
8
8
  import { type OutputSink } from '../types.js';
@@ -12,7 +12,6 @@ import { type OutputSink } from '../types.js';
12
12
  export declare class Lzma2Decoder {
13
13
  private lzmaDecoder;
14
14
  private dictionarySize;
15
- private propsSet;
16
15
  constructor(properties: Buffer | Uint8Array, outputSink?: OutputSink);
17
16
  /**
18
17
  * Reset the dictionary (for stream boundaries)
@@ -2,11 +2,24 @@
2
2
  * Synchronous LZMA2 Decoder
3
3
  *
4
4
  * LZMA2 is a container format that wraps LZMA chunks with framing.
5
- * Decodes LZMA2 data from a buffer.
6
- */ import { allocBufferUnsafe } from 'extract-base-iterator';
5
+ * Decodes LZMA2 data from a buffer or BufferList.
6
+ */ import { allocBufferUnsafe, bufferConcat, bufferFrom, canAllocateBufferSize } from 'extract-base-iterator';
7
7
  import { parseLzma2ChunkHeader } from '../lib/Lzma2ChunkParser.js';
8
8
  import { parseLzma2DictionarySize } from '../types.js';
9
9
  import { LzmaDecoder } from './LzmaDecoder.js';
10
+ /**
11
+ * Read multiple bytes from BufferLike into a Buffer
12
+ */ function readBytes(input, offset, length) {
13
+ if (Buffer.isBuffer(input)) {
14
+ return input.slice(offset, offset + length);
15
+ }
16
+ // For BufferList, create a new Buffer with the data
17
+ const buf = bufferFrom(new Array(length));
18
+ for(let i = 0; i < length; i++){
19
+ buf[i] = input.readByte(offset + i);
20
+ }
21
+ return buf;
22
+ }
10
23
  /**
11
24
  * Synchronous LZMA2 decoder
12
25
  */ export class Lzma2Decoder {
@@ -45,12 +58,10 @@ import { LzmaDecoder } from './LzmaDecoder.js';
45
58
  * @param input - LZMA2 compressed data (Buffer or BufferList)
46
59
  * @returns Total number of bytes written to sink
47
60
  */ decodeWithSink(input) {
48
- // Convert BufferList to Buffer for low-level parsing
49
- const buf = Buffer.isBuffer(input) ? input : input.toBuffer();
50
61
  let totalBytes = 0;
51
62
  let offset = 0;
52
- while(offset < buf.length){
53
- const result = parseLzma2ChunkHeader(buf, offset);
63
+ while(true){
64
+ const result = parseLzma2ChunkHeader(input, offset);
54
65
  if (!result.success) {
55
66
  throw new Error('Truncated LZMA2 chunk header');
56
67
  }
@@ -58,45 +69,31 @@ import { LzmaDecoder } from './LzmaDecoder.js';
58
69
  if (chunk.type === 'end') {
59
70
  break;
60
71
  }
61
- // Validate we have enough data for the chunk
62
- const dataSize = chunk.type === 'uncompressed' ? chunk.uncompSize : chunk.compSize;
63
- if (offset + chunk.headerSize + dataSize > buf.length) {
64
- throw new Error(`Truncated LZMA2 ${chunk.type} data`);
65
- }
66
72
  // Handle dictionary reset
67
73
  if (chunk.dictReset) {
68
74
  this.lzmaDecoder.resetDictionary();
69
75
  }
76
+ // Handle state reset
77
+ if (chunk.stateReset) {
78
+ this.lzmaDecoder.resetProbabilities();
79
+ }
80
+ // Apply new properties if present
81
+ if (chunk.newProps) {
82
+ const { lc, lp, pb } = chunk.newProps;
83
+ this.lzmaDecoder.setLcLpPb(lc, lp, pb);
84
+ }
70
85
  const dataOffset = offset + chunk.headerSize;
86
+ const useSolid = !chunk.stateReset || chunk.stateReset && !chunk.dictReset;
71
87
  if (chunk.type === 'uncompressed') {
72
- const uncompData = buf.slice(dataOffset, dataOffset + chunk.uncompSize);
88
+ // Read uncompressed data directly
89
+ const uncompData = readBytes(input, dataOffset, chunk.uncompSize);
73
90
  // Feed uncompressed data to dictionary so subsequent LZMA chunks can reference it
74
91
  this.lzmaDecoder.feedUncompressed(uncompData);
75
92
  totalBytes += uncompData.length;
76
93
  offset = dataOffset + chunk.uncompSize;
77
94
  } else {
78
- // LZMA compressed chunk
79
- // Apply new properties if present
80
- if (chunk.newProps) {
81
- const { lc, lp, pb } = chunk.newProps;
82
- if (!this.lzmaDecoder.setLcLpPb(lc, lp, pb)) {
83
- throw new Error(`Invalid LZMA properties: lc=${lc} lp=${lp} pb=${pb}`);
84
- }
85
- this.propsSet = true;
86
- } else {
87
- // No new properties, check if we already have them
88
- if (!this.propsSet) {
89
- throw new Error('LZMA chunk without properties');
90
- }
91
- }
92
- // Reset probabilities if state reset
93
- if (chunk.stateReset) {
94
- this.lzmaDecoder.resetProbabilities();
95
- }
96
- // Determine solid mode
97
- const useSolid = !chunk.stateReset || chunk.stateReset && !chunk.dictReset;
98
- // Decode LZMA chunk directly to sink
99
- totalBytes += this.lzmaDecoder.decodeWithSink(buf, dataOffset, chunk.uncompSize, useSolid);
95
+ // LZMA compressed chunk - decode directly from BufferLike
96
+ totalBytes += this.lzmaDecoder.decodeWithSink(input, dataOffset, chunk.uncompSize, useSolid);
100
97
  offset = dataOffset + chunk.compSize;
101
98
  }
102
99
  }
@@ -110,18 +107,19 @@ import { LzmaDecoder } from './LzmaDecoder.js';
110
107
  * @param unpackSize - Expected output size (optional, for pre-allocation)
111
108
  * @returns Decompressed data
112
109
  */ decode(input, unpackSize) {
113
- // Convert BufferList to Buffer for low-level parsing
114
- const buf = Buffer.isBuffer(input) ? input : input.toBuffer();
115
- // Pre-allocate output buffer if size is known
110
+ // Pre-allocate output buffer if size is known and safe for this Node version
116
111
  let outputBuffer = null;
117
112
  let outputPos = 0;
118
113
  const outputChunks = [];
119
- if (unpackSize && unpackSize > 0) {
114
+ // Use canAllocateBufferSize to dynamically check if pre-allocation is safe
115
+ const canPreAllocate = unpackSize && unpackSize > 0 && canAllocateBufferSize(unpackSize);
116
+ if (canPreAllocate) {
120
117
  outputBuffer = allocBufferUnsafe(unpackSize);
121
118
  }
122
119
  let offset = 0;
123
- while(offset < buf.length){
124
- const result = parseLzma2ChunkHeader(buf, offset);
120
+ // Parse and decode LZMA2 chunks one at a time
121
+ while(true){
122
+ const result = parseLzma2ChunkHeader(input, offset);
125
123
  if (!result.success) {
126
124
  throw new Error('Truncated LZMA2 chunk header');
127
125
  }
@@ -129,18 +127,25 @@ import { LzmaDecoder } from './LzmaDecoder.js';
129
127
  if (chunk.type === 'end') {
130
128
  break;
131
129
  }
132
- // Validate we have enough data for the chunk
133
- const dataSize = chunk.type === 'uncompressed' ? chunk.uncompSize : chunk.compSize;
134
- if (offset + chunk.headerSize + dataSize > buf.length) {
135
- throw new Error(`Truncated LZMA2 ${chunk.type} data`);
136
- }
130
+ const dataOffset = offset + chunk.headerSize;
137
131
  // Handle dictionary reset
138
132
  if (chunk.dictReset) {
139
133
  this.lzmaDecoder.resetDictionary();
140
134
  }
141
- const dataOffset = offset + chunk.headerSize;
135
+ // Handle state reset
136
+ if (chunk.stateReset) {
137
+ this.lzmaDecoder.resetProbabilities();
138
+ }
139
+ // Apply new properties if present
140
+ if (chunk.newProps) {
141
+ const { lc, lp, pb } = chunk.newProps;
142
+ this.lzmaDecoder.setLcLpPb(lc, lp, pb);
143
+ }
144
+ // Determine solid mode
145
+ const useSolid = !chunk.stateReset || chunk.stateReset && !chunk.dictReset;
142
146
  if (chunk.type === 'uncompressed') {
143
- const uncompData = buf.slice(dataOffset, dataOffset + chunk.uncompSize);
147
+ // Read uncompressed data
148
+ const uncompData = readBytes(input, dataOffset, chunk.uncompSize);
144
149
  // Copy to output
145
150
  if (outputBuffer) {
146
151
  uncompData.copy(outputBuffer, outputPos);
@@ -152,34 +157,14 @@ import { LzmaDecoder } from './LzmaDecoder.js';
152
157
  this.lzmaDecoder.feedUncompressed(uncompData);
153
158
  offset = dataOffset + chunk.uncompSize;
154
159
  } else {
155
- // LZMA compressed chunk
156
- // Apply new properties if present
157
- if (chunk.newProps) {
158
- const { lc, lp, pb } = chunk.newProps;
159
- if (!this.lzmaDecoder.setLcLpPb(lc, lp, pb)) {
160
- throw new Error(`Invalid LZMA properties: lc=${lc} lp=${lp} pb=${pb}`);
161
- }
162
- this.propsSet = true;
163
- } else {
164
- // No new properties, check if we already have them
165
- if (!this.propsSet) {
166
- throw new Error('LZMA chunk without properties');
167
- }
168
- }
169
- // Reset probabilities if state reset
170
- if (chunk.stateReset) {
171
- this.lzmaDecoder.resetProbabilities();
172
- }
173
- // Determine solid mode - preserve dictionary if not resetting state or if only resetting state (not dict)
174
- const useSolid = !chunk.stateReset || chunk.stateReset && !chunk.dictReset;
175
- // Decode LZMA chunk - use zero-copy when we have pre-allocated buffer
160
+ // LZMA compressed chunk - decode directly from BufferLike
176
161
  if (outputBuffer) {
177
162
  // Zero-copy: decode directly into caller's buffer
178
- const bytesWritten = this.lzmaDecoder.decodeToBuffer(buf, dataOffset, chunk.uncompSize, outputBuffer, outputPos, useSolid);
163
+ const bytesWritten = this.lzmaDecoder.decodeToBuffer(input, dataOffset, chunk.uncompSize, outputBuffer, outputPos, useSolid);
179
164
  outputPos += bytesWritten;
180
165
  } else {
181
166
  // No pre-allocation: decode to new buffer and collect chunks
182
- const chunkData = buf.slice(dataOffset, dataOffset + chunk.compSize);
167
+ const chunkData = readBytes(input, dataOffset, chunk.compSize);
183
168
  const decoded = this.lzmaDecoder.decode(chunkData, 0, chunk.uncompSize, useSolid);
184
169
  outputChunks.push(decoded);
185
170
  }
@@ -190,7 +175,8 @@ import { LzmaDecoder } from './LzmaDecoder.js';
190
175
  if (outputBuffer) {
191
176
  return outputPos < outputBuffer.length ? outputBuffer.slice(0, outputPos) : outputBuffer;
192
177
  }
193
- return Buffer.concat(outputChunks);
178
+ // Use bufferConcat which handles large buffers safely via pairwise combination
179
+ return bufferConcat(outputChunks);
194
180
  }
195
181
  constructor(properties, outputSink){
196
182
  if (!properties || properties.length < 1) {
@@ -199,7 +185,6 @@ import { LzmaDecoder } from './LzmaDecoder.js';
199
185
  this.dictionarySize = parseLzma2DictionarySize(properties[0]);
200
186
  this.lzmaDecoder = new LzmaDecoder(outputSink);
201
187
  this.lzmaDecoder.setDictionarySize(this.dictionarySize);
202
- this.propsSet = false;
203
188
  }
204
189
  }
205
190
  /**
@@ -210,6 +195,21 @@ import { LzmaDecoder } from './LzmaDecoder.js';
210
195
  * @param outputSink - Optional output sink with write callback for streaming (returns bytes written)
211
196
  * @returns Decompressed data (or bytes written if outputSink provided)
212
197
  */ export function decodeLzma2(input, properties, unpackSize, outputSink) {
198
+ // For very large outputs on old Node versions, we cannot return a single Buffer
199
+ // Use streaming mode internally to handle large outputs on modern Node
200
+ if (!outputSink && unpackSize && unpackSize > 0 && !canAllocateBufferSize(unpackSize)) {
201
+ // Large output - use streaming mode with internal chunking
202
+ const chunks = [];
203
+ const sink = {
204
+ write (buffer) {
205
+ chunks.push(buffer);
206
+ }
207
+ };
208
+ const decoder = new Lzma2Decoder(properties, sink);
209
+ decoder.decodeWithSink(input);
210
+ // Combine chunks at the end - use bufferConcat for safe combination
211
+ return bufferConcat(chunks);
212
+ }
213
213
  const decoder = new Lzma2Decoder(properties, outputSink);
214
214
  if (outputSink) {
215
215
  // Zero-copy mode: write to sink during decode
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/lzma/sync/Lzma2Decoder.ts"],"sourcesContent":["/**\n * Synchronous LZMA2 Decoder\n *\n * LZMA2 is a container format that wraps LZMA chunks with framing.\n * Decodes LZMA2 data from a buffer.\n */\n\nimport { allocBufferUnsafe, type BufferLike } from 'extract-base-iterator';\nimport { parseLzma2ChunkHeader } from '../lib/Lzma2ChunkParser.ts';\nimport { type OutputSink, parseLzma2DictionarySize } from '../types.ts';\nimport { LzmaDecoder } from './LzmaDecoder.ts';\n\n/**\n * Synchronous LZMA2 decoder\n */\nexport class Lzma2Decoder {\n private lzmaDecoder: LzmaDecoder;\n private dictionarySize: number;\n private propsSet: boolean;\n\n constructor(properties: Buffer | Uint8Array, outputSink?: OutputSink) {\n if (!properties || properties.length < 1) {\n throw new Error('LZMA2 requires properties byte');\n }\n\n this.dictionarySize = parseLzma2DictionarySize(properties[0]);\n this.lzmaDecoder = new LzmaDecoder(outputSink);\n this.lzmaDecoder.setDictionarySize(this.dictionarySize);\n this.propsSet = false;\n }\n\n /**\n * Reset the dictionary (for stream boundaries)\n */\n resetDictionary(): void {\n this.lzmaDecoder.resetDictionary();\n }\n\n /**\n * Reset all probability models (for stream boundaries)\n */\n resetProbabilities(): void {\n this.lzmaDecoder.resetProbabilities();\n }\n\n /**\n * Set LZMA properties\n */\n setLcLpPb(lc: number, lp: number, pb: number): boolean {\n return this.lzmaDecoder.setLcLpPb(lc, lp, pb);\n }\n\n /**\n * Feed uncompressed data to the dictionary (for subsequent LZMA chunks)\n */\n feedUncompressed(data: Buffer): void {\n this.lzmaDecoder.feedUncompressed(data);\n }\n\n /**\n * Decode raw LZMA data (used internally for LZMA2 chunks)\n * @param input - LZMA compressed data\n * @param offset - Input offset\n * @param outSize - Expected output size\n * @param solid - Use solid mode\n * @returns Decompressed data\n */\n decodeLzmaData(input: Buffer, offset: number, outSize: number, solid = false): Buffer {\n return this.lzmaDecoder.decode(input, offset, outSize, solid);\n }\n\n /**\n * Decode LZMA2 data with streaming output\n * @param input - LZMA2 compressed data (Buffer or BufferList)\n * @returns Total number of bytes written to sink\n */\n decodeWithSink(input: BufferLike): number {\n // Convert BufferList to Buffer for low-level parsing\n const buf = Buffer.isBuffer(input) ? input : input.toBuffer();\n let totalBytes = 0;\n let offset = 0;\n\n while (offset < buf.length) {\n const result = parseLzma2ChunkHeader(buf, offset);\n\n if (!result.success) {\n throw new Error('Truncated LZMA2 chunk header');\n }\n\n const chunk = result.chunk;\n\n if (chunk.type === 'end') {\n break;\n }\n\n // Validate we have enough data for the chunk\n const dataSize = chunk.type === 'uncompressed' ? chunk.uncompSize : chunk.compSize;\n if (offset + chunk.headerSize + dataSize > buf.length) {\n throw new Error(`Truncated LZMA2 ${chunk.type} data`);\n }\n\n // Handle dictionary reset\n if (chunk.dictReset) {\n this.lzmaDecoder.resetDictionary();\n }\n\n const dataOffset = offset + chunk.headerSize;\n\n if (chunk.type === 'uncompressed') {\n const uncompData = buf.slice(dataOffset, dataOffset + chunk.uncompSize);\n\n // Feed uncompressed data to dictionary so subsequent LZMA chunks can reference it\n this.lzmaDecoder.feedUncompressed(uncompData);\n\n totalBytes += uncompData.length;\n offset = dataOffset + chunk.uncompSize;\n } else {\n // LZMA compressed chunk\n\n // Apply new properties if present\n if (chunk.newProps) {\n const { lc, lp, pb } = chunk.newProps;\n if (!this.lzmaDecoder.setLcLpPb(lc, lp, pb)) {\n throw new Error(`Invalid LZMA properties: lc=${lc} lp=${lp} pb=${pb}`);\n }\n this.propsSet = true;\n } else {\n // No new properties, check if we already have them\n if (!this.propsSet) {\n throw new Error('LZMA chunk without properties');\n }\n }\n\n // Reset probabilities if state reset\n if (chunk.stateReset) {\n this.lzmaDecoder.resetProbabilities();\n }\n\n // Determine solid mode\n const useSolid = !chunk.stateReset || (chunk.stateReset && !chunk.dictReset);\n\n // Decode LZMA chunk directly to sink\n totalBytes += this.lzmaDecoder.decodeWithSink(buf, dataOffset, chunk.uncompSize, useSolid);\n\n offset = dataOffset + chunk.compSize;\n }\n }\n\n // Flush any remaining data in the OutWindow\n this.lzmaDecoder.flushOutWindow();\n\n return totalBytes;\n }\n\n /**\n * Decode LZMA2 data\n * @param input - LZMA2 compressed data (Buffer or BufferList)\n * @param unpackSize - Expected output size (optional, for pre-allocation)\n * @returns Decompressed data\n */\n decode(input: BufferLike, unpackSize?: number): Buffer {\n // Convert BufferList to Buffer for low-level parsing\n const buf = Buffer.isBuffer(input) ? input : input.toBuffer();\n\n // Pre-allocate output buffer if size is known\n let outputBuffer: Buffer | null = null;\n let outputPos = 0;\n const outputChunks: Buffer[] = [];\n\n if (unpackSize && unpackSize > 0) {\n outputBuffer = allocBufferUnsafe(unpackSize);\n }\n\n let offset = 0;\n\n while (offset < buf.length) {\n const result = parseLzma2ChunkHeader(buf, offset);\n\n if (!result.success) {\n throw new Error('Truncated LZMA2 chunk header');\n }\n\n const chunk = result.chunk;\n\n if (chunk.type === 'end') {\n break;\n }\n\n // Validate we have enough data for the chunk\n const dataSize = chunk.type === 'uncompressed' ? chunk.uncompSize : chunk.compSize;\n if (offset + chunk.headerSize + dataSize > buf.length) {\n throw new Error(`Truncated LZMA2 ${chunk.type} data`);\n }\n\n // Handle dictionary reset\n if (chunk.dictReset) {\n this.lzmaDecoder.resetDictionary();\n }\n\n const dataOffset = offset + chunk.headerSize;\n\n if (chunk.type === 'uncompressed') {\n const uncompData = buf.slice(dataOffset, dataOffset + chunk.uncompSize);\n\n // Copy to output\n if (outputBuffer) {\n uncompData.copy(outputBuffer, outputPos);\n outputPos += uncompData.length;\n } else {\n outputChunks.push(uncompData);\n }\n\n // Feed uncompressed data to dictionary so subsequent LZMA chunks can reference it\n this.lzmaDecoder.feedUncompressed(uncompData);\n\n offset = dataOffset + chunk.uncompSize;\n } else {\n // LZMA compressed chunk\n\n // Apply new properties if present\n if (chunk.newProps) {\n const { lc, lp, pb } = chunk.newProps;\n if (!this.lzmaDecoder.setLcLpPb(lc, lp, pb)) {\n throw new Error(`Invalid LZMA properties: lc=${lc} lp=${lp} pb=${pb}`);\n }\n this.propsSet = true;\n } else {\n // No new properties, check if we already have them\n if (!this.propsSet) {\n throw new Error('LZMA chunk without properties');\n }\n }\n\n // Reset probabilities if state reset\n if (chunk.stateReset) {\n this.lzmaDecoder.resetProbabilities();\n }\n\n // Determine solid mode - preserve dictionary if not resetting state or if only resetting state (not dict)\n const useSolid = !chunk.stateReset || (chunk.stateReset && !chunk.dictReset);\n\n // Decode LZMA chunk - use zero-copy when we have pre-allocated buffer\n if (outputBuffer) {\n // Zero-copy: decode directly into caller's buffer\n const bytesWritten = this.lzmaDecoder.decodeToBuffer(buf, dataOffset, chunk.uncompSize, outputBuffer, outputPos, useSolid);\n outputPos += bytesWritten;\n } else {\n // No pre-allocation: decode to new buffer and collect chunks\n const chunkData = buf.slice(dataOffset, dataOffset + chunk.compSize);\n const decoded = this.lzmaDecoder.decode(chunkData, 0, chunk.uncompSize, useSolid);\n outputChunks.push(decoded);\n }\n\n offset = dataOffset + chunk.compSize;\n }\n }\n\n // Return pre-allocated buffer or concatenated chunks\n if (outputBuffer) {\n return outputPos < outputBuffer.length ? outputBuffer.slice(0, outputPos) : outputBuffer;\n }\n return Buffer.concat(outputChunks);\n }\n}\n\n/**\n * Decode LZMA2 data synchronously\n * @param input - LZMA2 compressed data (Buffer or BufferList)\n * @param properties - 1-byte properties (dictionary size)\n * @param unpackSize - Expected output size (optional, autodetects if not provided)\n * @param outputSink - Optional output sink with write callback for streaming (returns bytes written)\n * @returns Decompressed data (or bytes written if outputSink provided)\n */\nexport function decodeLzma2(input: BufferLike, properties: Buffer | Uint8Array, unpackSize?: number, outputSink?: { write(buffer: Buffer): void }): Buffer | number {\n const decoder = new Lzma2Decoder(properties, outputSink as OutputSink);\n if (outputSink) {\n // Zero-copy mode: write to sink during decode\n return decoder.decodeWithSink(input);\n }\n // Buffering mode: returns Buffer (zero-copy)\n return decoder.decode(input, unpackSize);\n}\n"],"names":["allocBufferUnsafe","parseLzma2ChunkHeader","parseLzma2DictionarySize","LzmaDecoder","Lzma2Decoder","resetDictionary","lzmaDecoder","resetProbabilities","setLcLpPb","lc","lp","pb","feedUncompressed","data","decodeLzmaData","input","offset","outSize","solid","decode","decodeWithSink","buf","Buffer","isBuffer","toBuffer","totalBytes","length","result","success","Error","chunk","type","dataSize","uncompSize","compSize","headerSize","dictReset","dataOffset","uncompData","slice","newProps","propsSet","stateReset","useSolid","flushOutWindow","unpackSize","outputBuffer","outputPos","outputChunks","copy","push","bytesWritten","decodeToBuffer","chunkData","decoded","concat","properties","outputSink","dictionarySize","setDictionarySize","decodeLzma2","decoder"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/lzma/sync/Lzma2Decoder.ts"],"sourcesContent":["/**\n * Synchronous LZMA2 Decoder\n *\n * LZMA2 is a container format that wraps LZMA chunks with framing.\n * Decodes LZMA2 data from a buffer or BufferList.\n */\n\nimport { allocBufferUnsafe, type BufferLike, bufferConcat, bufferFrom, canAllocateBufferSize } from 'extract-base-iterator';\nimport { parseLzma2ChunkHeader } from '../lib/Lzma2ChunkParser.ts';\nimport { type OutputSink, parseLzma2DictionarySize } from '../types.ts';\nimport { LzmaDecoder } from './LzmaDecoder.ts';\n\n/**\n * Read multiple bytes from BufferLike into a Buffer\n */\nfunction readBytes(input: BufferLike, offset: number, length: number): Buffer {\n if (Buffer.isBuffer(input)) {\n return input.slice(offset, offset + length);\n }\n // For BufferList, create a new Buffer with the data\n const buf = bufferFrom(new Array(length));\n for (let i = 0; i < length; i++) {\n buf[i] = input.readByte(offset + i);\n }\n return buf;\n}\n\n/**\n * Synchronous LZMA2 decoder\n */\nexport class Lzma2Decoder {\n private lzmaDecoder: LzmaDecoder;\n private dictionarySize: number;\n\n constructor(properties: Buffer | Uint8Array, outputSink?: OutputSink) {\n if (!properties || properties.length < 1) {\n throw new Error('LZMA2 requires properties byte');\n }\n\n this.dictionarySize = parseLzma2DictionarySize(properties[0]);\n this.lzmaDecoder = new LzmaDecoder(outputSink);\n this.lzmaDecoder.setDictionarySize(this.dictionarySize);\n }\n\n /**\n * Reset the dictionary (for stream boundaries)\n */\n resetDictionary(): void {\n this.lzmaDecoder.resetDictionary();\n }\n\n /**\n * Reset all probability models (for stream boundaries)\n */\n resetProbabilities(): void {\n this.lzmaDecoder.resetProbabilities();\n }\n\n /**\n * Set LZMA properties\n */\n setLcLpPb(lc: number, lp: number, pb: number): boolean {\n return this.lzmaDecoder.setLcLpPb(lc, lp, pb);\n }\n\n /**\n * Feed uncompressed data to the dictionary (for subsequent LZMA chunks)\n */\n feedUncompressed(data: Buffer): void {\n this.lzmaDecoder.feedUncompressed(data);\n }\n\n /**\n * Decode raw LZMA data (used internally for LZMA2 chunks)\n * @param input - LZMA compressed data\n * @param offset - Input offset\n * @param outSize - Expected output size\n * @param solid - Use solid mode\n * @returns Decompressed data\n */\n decodeLzmaData(input: Buffer, offset: number, outSize: number, solid = false): Buffer {\n return this.lzmaDecoder.decode(input, offset, outSize, solid);\n }\n\n /**\n * Decode LZMA2 data with streaming output\n * @param input - LZMA2 compressed data (Buffer or BufferList)\n * @returns Total number of bytes written to sink\n */\n decodeWithSink(input: BufferLike): number {\n let totalBytes = 0;\n let offset = 0;\n\n while (true) {\n const result = parseLzma2ChunkHeader(input, offset);\n\n if (!result.success) {\n throw new Error('Truncated LZMA2 chunk header');\n }\n\n const chunk = result.chunk;\n\n if (chunk.type === 'end') {\n break;\n }\n\n // Handle dictionary reset\n if (chunk.dictReset) {\n this.lzmaDecoder.resetDictionary();\n }\n\n // Handle state reset\n if (chunk.stateReset) {\n this.lzmaDecoder.resetProbabilities();\n }\n\n // Apply new properties if present\n if (chunk.newProps) {\n const { lc, lp, pb } = chunk.newProps;\n this.lzmaDecoder.setLcLpPb(lc, lp, pb);\n }\n\n const dataOffset = offset + chunk.headerSize;\n const useSolid = !chunk.stateReset || (chunk.stateReset && !chunk.dictReset);\n\n if (chunk.type === 'uncompressed') {\n // Read uncompressed data directly\n const uncompData = readBytes(input, dataOffset, chunk.uncompSize);\n\n // Feed uncompressed data to dictionary so subsequent LZMA chunks can reference it\n this.lzmaDecoder.feedUncompressed(uncompData);\n\n totalBytes += uncompData.length;\n offset = dataOffset + chunk.uncompSize;\n } else {\n // LZMA compressed chunk - decode directly from BufferLike\n totalBytes += this.lzmaDecoder.decodeWithSink(input, dataOffset, chunk.uncompSize, useSolid);\n\n offset = dataOffset + chunk.compSize;\n }\n }\n\n // Flush any remaining data in the OutWindow\n this.lzmaDecoder.flushOutWindow();\n\n return totalBytes;\n }\n\n /**\n * Decode LZMA2 data\n * @param input - LZMA2 compressed data (Buffer or BufferList)\n * @param unpackSize - Expected output size (optional, for pre-allocation)\n * @returns Decompressed data\n */\n decode(input: BufferLike, unpackSize?: number): Buffer {\n // Pre-allocate output buffer if size is known and safe for this Node version\n let outputBuffer: Buffer | null = null;\n let outputPos = 0;\n const outputChunks: Buffer[] = [];\n\n // Use canAllocateBufferSize to dynamically check if pre-allocation is safe\n const canPreAllocate = unpackSize && unpackSize > 0 && canAllocateBufferSize(unpackSize);\n if (canPreAllocate) {\n outputBuffer = allocBufferUnsafe(unpackSize);\n }\n\n let offset = 0;\n\n // Parse and decode LZMA2 chunks one at a time\n while (true) {\n const result = parseLzma2ChunkHeader(input, offset);\n\n if (!result.success) {\n throw new Error('Truncated LZMA2 chunk header');\n }\n\n const chunk = result.chunk;\n\n if (chunk.type === 'end') {\n break;\n }\n\n const dataOffset = offset + chunk.headerSize;\n\n // Handle dictionary reset\n if (chunk.dictReset) {\n this.lzmaDecoder.resetDictionary();\n }\n\n // Handle state reset\n if (chunk.stateReset) {\n this.lzmaDecoder.resetProbabilities();\n }\n\n // Apply new properties if present\n if (chunk.newProps) {\n const { lc, lp, pb } = chunk.newProps;\n this.lzmaDecoder.setLcLpPb(lc, lp, pb);\n }\n\n // Determine solid mode\n const useSolid = !chunk.stateReset || (chunk.stateReset && !chunk.dictReset);\n\n if (chunk.type === 'uncompressed') {\n // Read uncompressed data\n const uncompData = readBytes(input, dataOffset, chunk.uncompSize);\n\n // Copy to output\n if (outputBuffer) {\n uncompData.copy(outputBuffer, outputPos);\n outputPos += uncompData.length;\n } else {\n outputChunks.push(uncompData);\n }\n\n // Feed uncompressed data to dictionary so subsequent LZMA chunks can reference it\n this.lzmaDecoder.feedUncompressed(uncompData);\n\n offset = dataOffset + chunk.uncompSize;\n } else {\n // LZMA compressed chunk - decode directly from BufferLike\n if (outputBuffer) {\n // Zero-copy: decode directly into caller's buffer\n const bytesWritten = this.lzmaDecoder.decodeToBuffer(input, dataOffset, chunk.uncompSize, outputBuffer, outputPos, useSolid);\n outputPos += bytesWritten;\n } else {\n // No pre-allocation: decode to new buffer and collect chunks\n const chunkData = readBytes(input, dataOffset, chunk.compSize);\n const decoded = this.lzmaDecoder.decode(chunkData, 0, chunk.uncompSize, useSolid);\n outputChunks.push(decoded);\n }\n\n offset = dataOffset + chunk.compSize;\n }\n }\n\n // Return pre-allocated buffer or concatenated chunks\n if (outputBuffer) {\n return outputPos < outputBuffer.length ? outputBuffer.slice(0, outputPos) : outputBuffer;\n }\n // Use bufferConcat which handles large buffers safely via pairwise combination\n return bufferConcat(outputChunks);\n }\n}\n\n/**\n * Decode LZMA2 data synchronously\n * @param input - LZMA2 compressed data (Buffer or BufferList)\n * @param properties - 1-byte properties (dictionary size)\n * @param unpackSize - Expected output size (optional, autodetects if not provided)\n * @param outputSink - Optional output sink with write callback for streaming (returns bytes written)\n * @returns Decompressed data (or bytes written if outputSink provided)\n */\nexport function decodeLzma2(input: BufferLike, properties: Buffer | Uint8Array, unpackSize?: number, outputSink?: { write(buffer: Buffer): void }): Buffer | number {\n // For very large outputs on old Node versions, we cannot return a single Buffer\n // Use streaming mode internally to handle large outputs on modern Node\n if (!outputSink && unpackSize && unpackSize > 0 && !canAllocateBufferSize(unpackSize)) {\n // Large output - use streaming mode with internal chunking\n const chunks: Buffer[] = [];\n const sink: OutputSink = {\n write(buffer: Buffer): void {\n chunks.push(buffer);\n },\n };\n\n const decoder = new Lzma2Decoder(properties, sink);\n decoder.decodeWithSink(input);\n\n // Combine chunks at the end - use bufferConcat for safe combination\n return bufferConcat(chunks);\n }\n\n const decoder = new Lzma2Decoder(properties, outputSink as OutputSink);\n if (outputSink) {\n // Zero-copy mode: write to sink during decode\n return decoder.decodeWithSink(input);\n }\n // Buffering mode: returns Buffer (zero-copy)\n return decoder.decode(input, unpackSize);\n}\n"],"names":["allocBufferUnsafe","bufferConcat","bufferFrom","canAllocateBufferSize","parseLzma2ChunkHeader","parseLzma2DictionarySize","LzmaDecoder","readBytes","input","offset","length","Buffer","isBuffer","slice","buf","Array","i","readByte","Lzma2Decoder","resetDictionary","lzmaDecoder","resetProbabilities","setLcLpPb","lc","lp","pb","feedUncompressed","data","decodeLzmaData","outSize","solid","decode","decodeWithSink","totalBytes","result","success","Error","chunk","type","dictReset","stateReset","newProps","dataOffset","headerSize","useSolid","uncompData","uncompSize","compSize","flushOutWindow","unpackSize","outputBuffer","outputPos","outputChunks","canPreAllocate","copy","push","bytesWritten","decodeToBuffer","chunkData","decoded","properties","outputSink","dictionarySize","setDictionarySize","decodeLzma2","chunks","sink","write","buffer","decoder"],"mappings":"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"}
@@ -27,14 +27,15 @@
27
27
  * and writes directly to it. Wrapping with an OutputSink that buffers to an
28
28
  * array defeats this optimization by creating unnecessary intermediate copies.
29
29
  */
30
+ import type { BufferLike } from 'extract-base-iterator';
30
31
  /** Callback for async decode operations: (error, result) => void */
31
32
  export type DecodeCallback<T = Buffer> = (error: Error | null, result?: T) => void;
32
33
  /** Callback invoked when an async 7z decode completes */
33
34
  export type SevenZDecodeCallback = DecodeCallback<Buffer>;
34
- export declare function decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number, callback: SevenZDecodeCallback): void;
35
- export declare function decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number): Promise<Buffer>;
35
+ export declare function decode7zLzma(data: BufferLike, properties: Buffer, unpackSize: number, callback: SevenZDecodeCallback): void;
36
+ export declare function decode7zLzma(data: BufferLike, properties: Buffer, unpackSize: number): Promise<Buffer>;
36
37
  /**
37
38
  * Decode LZMA2-compressed data from a 7z file
38
39
  */
39
- export declare function decode7zLzma2(data: Buffer, properties: Buffer, unpackSize: number | undefined, callback: SevenZDecodeCallback): void;
40
- export declare function decode7zLzma2(data: Buffer, properties: Buffer, unpackSize?: number): Promise<Buffer>;
40
+ export declare function decode7zLzma2(data: BufferLike, properties: Buffer, unpackSize: number | undefined, callback: SevenZDecodeCallback): void;
41
+ export declare function decode7zLzma2(data: BufferLike, properties: Buffer, unpackSize?: number): Promise<Buffer>;
@@ -46,7 +46,9 @@ const schedule = typeof setImmediate === 'function' ? setImmediate : (fn)=>proce
46
46
  const native = tryLoadNative();
47
47
  if (native === null || native === void 0 ? void 0 : native.lzma) {
48
48
  try {
49
- const promise = native.lzma(data, properties, unpackSize);
49
+ // Native lzma-native expects Buffer, convert if needed
50
+ const buf = Buffer.isBuffer(data) ? data : data.toBuffer();
51
+ const promise = native.lzma(buf, properties, unpackSize);
50
52
  if (promise && typeof promise.then === 'function') {
51
53
  promise.then((value)=>cb(null, value), fallback);
52
54
  return;
@@ -74,7 +76,9 @@ export function decode7zLzma2(data, properties, unpackSize, callback) {
74
76
  const native = tryLoadNative();
75
77
  if (native === null || native === void 0 ? void 0 : native.lzma2) {
76
78
  try {
77
- const promise = native.lzma2(data, properties, unpackSize);
79
+ // Native lzma-native expects Buffer, convert if needed
80
+ const buf = Buffer.isBuffer(data) ? data : data.toBuffer();
81
+ const promise = native.lzma2(buf, properties, unpackSize);
78
82
  if (promise && typeof promise.then === 'function') {
79
83
  promise.then((value)=>cb(null, value), fallback);
80
84
  return;
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/sevenz.ts"],"sourcesContent":["/**\n * High-Level 7z-Specific Decoders\n *\n * These functions accept properties separately (matching 7z format structure)\n * and execute either the native lzma-native path or the pure JS fallback.\n *\n * This provides automatic native acceleration for 7z files while maintaining\n * the API that 7z-iterator expects.\n *\n * IMPORTANT: Buffer Management Pattern\n *\n * ❌ SLOW - DO NOT use OutputSink with buffering:\n * const chunks: Buffer[] = [];\n * decodeLzma2(data, props, size, { write: c => chunks.push(c) });\n * return Buffer.concat(chunks); // ← 3 copies: push + concat + return\n *\n * OutWindow → chunks.push(chunk) → Buffer.concat(chunks) → result\n * COPY TO ARRAY COPY ALL FINAL BUFFER\n *\n * ✅ FAST - Direct return (let decoder manage buffer):\n * return decodeLzma2(data, props, size) as Buffer; // ← 1 copy\n *\n * OutWindow → pre-allocated buffer → result\n * DIRECT WRITE\n *\n * The decodeLzma2() function internally pre-allocates the exact output size\n * and writes directly to it. Wrapping with an OutputSink that buffers to an\n * array defeats this optimization by creating unnecessary intermediate copies.\n */\n\nimport { decodeLzma2 } from './lzma/sync/Lzma2Decoder.ts';\nimport { decodeLzma } from './lzma/sync/LzmaDecoder.ts';\nimport { tryLoadNative } from './native.ts';\n\n/** Callback for async decode operations: (error, result) => void */\nexport type DecodeCallback<T = Buffer> = (error: Error | null, result?: T) => void;\n\n/** Callback invoked when an async 7z decode completes */\nexport type SevenZDecodeCallback = DecodeCallback<Buffer>;\n\nconst schedule = typeof setImmediate === 'function' ? setImmediate : (fn: () => void) => process.nextTick(fn);\n\nexport function decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number, callback: SevenZDecodeCallback): void;\nexport function decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number): Promise<Buffer>;\n/**\n * Decode LZMA-compressed data from a 7z file\n */\nexport function decode7zLzma(data: Buffer, properties: Buffer, unpackSize: number, callback?: SevenZDecodeCallback): Promise<Buffer> | void {\n const worker = (cb: SevenZDecodeCallback) => {\n const fallback = () => {\n schedule(() => {\n try {\n cb(null, decodeLzma(data, properties, unpackSize) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n });\n };\n\n const native = tryLoadNative();\n if (native?.lzma) {\n try {\n const promise = native.lzma(data, properties, unpackSize);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as Buffer))));\n}\n\n/**\n * Decode LZMA2-compressed data from a 7z file\n */\nexport function decode7zLzma2(data: Buffer, properties: Buffer, unpackSize: number | undefined, callback: SevenZDecodeCallback): void;\nexport function decode7zLzma2(data: Buffer, properties: Buffer, unpackSize?: number): Promise<Buffer>;\nexport function decode7zLzma2(data: Buffer, properties: Buffer, unpackSize?: number, callback?: SevenZDecodeCallback): Promise<Buffer> | void {\n const worker = (cb: SevenZDecodeCallback) => {\n const fallback = () => {\n schedule(() => {\n try {\n cb(null, decodeLzma2(data, properties, unpackSize) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n });\n };\n\n const native = tryLoadNative();\n if (native?.lzma2) {\n try {\n const promise = native.lzma2(data, properties, unpackSize);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as Buffer))));\n}\n"],"names":["decodeLzma2","decodeLzma","tryLoadNative","schedule","setImmediate","fn","process","nextTick","decode7zLzma","data","properties","unpackSize","callback","worker","cb","fallback","err","native","lzma","promise","then","value","Promise","resolve","reject","decode7zLzma2","lzma2"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BC,GAED,SAASA,WAAW,QAAQ,8BAA8B;AAC1D,SAASC,UAAU,QAAQ,6BAA6B;AACxD,SAASC,aAAa,QAAQ,cAAc;AAQ5C,MAAMC,WAAW,OAAOC,iBAAiB,aAAaA,eAAe,CAACC,KAAmBC,QAAQC,QAAQ,CAACF;AAI1G;;CAEC,GACD,OAAO,SAASG,aAAaC,IAAY,EAAEC,UAAkB,EAAEC,UAAkB,EAAEC,QAA+B;IAChH,MAAMC,SAAS,CAACC;QACd,MAAMC,WAAW;YACfZ,SAAS;gBACP,IAAI;oBACFW,GAAG,MAAMb,WAAWQ,MAAMC,YAAYC;gBACxC,EAAE,OAAOK,KAAK;oBACZF,GAAGE;gBACL;YACF;QACF;QAEA,MAAMC,SAASf;QACf,IAAIe,mBAAAA,6BAAAA,OAAQC,IAAI,EAAE;YAChB,IAAI;gBACF,MAAMC,UAAUF,OAAOC,IAAI,CAACT,MAAMC,YAAYC;gBAC9C,IAAIQ,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,CAACC,QAAUP,GAAG,MAAMO,QAAQN;oBACzC;gBACF;YACF,EAAE,OAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOH,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIU,QAAQ,CAACC,SAASC,SAAWX,OAAO,CAACG,KAAKK,QAAWL,MAAMQ,OAAOR,OAAOO,QAAQF;AAC9F;AAOA,OAAO,SAASI,cAAchB,IAAY,EAAEC,UAAkB,EAAEC,UAAmB,EAAEC,QAA+B;IAClH,MAAMC,SAAS,CAACC;QACd,MAAMC,WAAW;YACfZ,SAAS;gBACP,IAAI;oBACFW,GAAG,MAAMd,YAAYS,MAAMC,YAAYC;gBACzC,EAAE,OAAOK,KAAK;oBACZF,GAAGE;gBACL;YACF;QACF;QAEA,MAAMC,SAASf;QACf,IAAIe,mBAAAA,6BAAAA,OAAQS,KAAK,EAAE;YACjB,IAAI;gBACF,MAAMP,UAAUF,OAAOS,KAAK,CAACjB,MAAMC,YAAYC;gBAC/C,IAAIQ,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,CAACC,QAAUP,GAAG,MAAMO,QAAQN;oBACzC;gBACF;YACF,EAAE,OAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOH,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIU,QAAQ,CAACC,SAASC,SAAWX,OAAO,CAACG,KAAKK,QAAWL,MAAMQ,OAAOR,OAAOO,QAAQF;AAC9F"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/xz-compat/src/sevenz.ts"],"sourcesContent":["/**\n * High-Level 7z-Specific Decoders\n *\n * These functions accept properties separately (matching 7z format structure)\n * and execute either the native lzma-native path or the pure JS fallback.\n *\n * This provides automatic native acceleration for 7z files while maintaining\n * the API that 7z-iterator expects.\n *\n * IMPORTANT: Buffer Management Pattern\n *\n * ❌ SLOW - DO NOT use OutputSink with buffering:\n * const chunks: Buffer[] = [];\n * decodeLzma2(data, props, size, { write: c => chunks.push(c) });\n * return Buffer.concat(chunks); // ← 3 copies: push + concat + return\n *\n * OutWindow → chunks.push(chunk) → Buffer.concat(chunks) → result\n * COPY TO ARRAY COPY ALL FINAL BUFFER\n *\n * ✅ FAST - Direct return (let decoder manage buffer):\n * return decodeLzma2(data, props, size) as Buffer; // ← 1 copy\n *\n * OutWindow → pre-allocated buffer → result\n * DIRECT WRITE\n *\n * The decodeLzma2() function internally pre-allocates the exact output size\n * and writes directly to it. Wrapping with an OutputSink that buffers to an\n * array defeats this optimization by creating unnecessary intermediate copies.\n */\n\nimport type { BufferLike } from 'extract-base-iterator';\nimport { decodeLzma2 } from './lzma/sync/Lzma2Decoder.ts';\nimport { decodeLzma } from './lzma/sync/LzmaDecoder.ts';\nimport { tryLoadNative } from './native.ts';\n\n/** Callback for async decode operations: (error, result) => void */\nexport type DecodeCallback<T = Buffer> = (error: Error | null, result?: T) => void;\n\n/** Callback invoked when an async 7z decode completes */\nexport type SevenZDecodeCallback = DecodeCallback<Buffer>;\n\nconst schedule = typeof setImmediate === 'function' ? setImmediate : (fn: () => void) => process.nextTick(fn);\n\nexport function decode7zLzma(data: BufferLike, properties: Buffer, unpackSize: number, callback: SevenZDecodeCallback): void;\nexport function decode7zLzma(data: BufferLike, properties: Buffer, unpackSize: number): Promise<Buffer>;\n/**\n * Decode LZMA-compressed data from a 7z file\n */\nexport function decode7zLzma(data: BufferLike, properties: Buffer, unpackSize: number, callback?: SevenZDecodeCallback): Promise<Buffer> | void {\n const worker = (cb: SevenZDecodeCallback) => {\n const fallback = () => {\n schedule(() => {\n try {\n cb(null, decodeLzma(data, properties, unpackSize) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n });\n };\n\n const native = tryLoadNative();\n if (native?.lzma) {\n try {\n // Native lzma-native expects Buffer, convert if needed\n const buf = Buffer.isBuffer(data) ? data : data.toBuffer();\n const promise = native.lzma(buf, properties, unpackSize);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as Buffer))));\n}\n\n/**\n * Decode LZMA2-compressed data from a 7z file\n */\nexport function decode7zLzma2(data: BufferLike, properties: Buffer, unpackSize: number | undefined, callback: SevenZDecodeCallback): void;\nexport function decode7zLzma2(data: BufferLike, properties: Buffer, unpackSize?: number): Promise<Buffer>;\nexport function decode7zLzma2(data: BufferLike, properties: Buffer, unpackSize?: number, callback?: SevenZDecodeCallback): Promise<Buffer> | void {\n const worker = (cb: SevenZDecodeCallback) => {\n const fallback = () => {\n schedule(() => {\n try {\n cb(null, decodeLzma2(data, properties, unpackSize) as Buffer);\n } catch (err) {\n cb(err as Error);\n }\n });\n };\n\n const native = tryLoadNative();\n if (native?.lzma2) {\n try {\n // Native lzma-native expects Buffer, convert if needed\n const buf = Buffer.isBuffer(data) ? data : data.toBuffer();\n const promise = native.lzma2(buf, properties, unpackSize);\n if (promise && typeof promise.then === 'function') {\n promise.then((value) => cb(null, value), fallback);\n return;\n }\n } catch {\n // fall through to fallback\n }\n }\n fallback();\n };\n\n if (typeof callback === 'function') return worker(callback);\n return new Promise((resolve, reject) => worker((err, value) => (err ? reject(err) : resolve(value as Buffer))));\n}\n"],"names":["decodeLzma2","decodeLzma","tryLoadNative","schedule","setImmediate","fn","process","nextTick","decode7zLzma","data","properties","unpackSize","callback","worker","cb","fallback","err","native","lzma","buf","Buffer","isBuffer","toBuffer","promise","then","value","Promise","resolve","reject","decode7zLzma2","lzma2"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BC,GAGD,SAASA,WAAW,QAAQ,8BAA8B;AAC1D,SAASC,UAAU,QAAQ,6BAA6B;AACxD,SAASC,aAAa,QAAQ,cAAc;AAQ5C,MAAMC,WAAW,OAAOC,iBAAiB,aAAaA,eAAe,CAACC,KAAmBC,QAAQC,QAAQ,CAACF;AAI1G;;CAEC,GACD,OAAO,SAASG,aAAaC,IAAgB,EAAEC,UAAkB,EAAEC,UAAkB,EAAEC,QAA+B;IACpH,MAAMC,SAAS,CAACC;QACd,MAAMC,WAAW;YACfZ,SAAS;gBACP,IAAI;oBACFW,GAAG,MAAMb,WAAWQ,MAAMC,YAAYC;gBACxC,EAAE,OAAOK,KAAK;oBACZF,GAAGE;gBACL;YACF;QACF;QAEA,MAAMC,SAASf;QACf,IAAIe,mBAAAA,6BAAAA,OAAQC,IAAI,EAAE;YAChB,IAAI;gBACF,uDAAuD;gBACvD,MAAMC,MAAMC,OAAOC,QAAQ,CAACZ,QAAQA,OAAOA,KAAKa,QAAQ;gBACxD,MAAMC,UAAUN,OAAOC,IAAI,CAACC,KAAKT,YAAYC;gBAC7C,IAAIY,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,CAACC,QAAUX,GAAG,MAAMW,QAAQV;oBACzC;gBACF;YACF,EAAE,OAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOH,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIc,QAAQ,CAACC,SAASC,SAAWf,OAAO,CAACG,KAAKS,QAAWT,MAAMY,OAAOZ,OAAOW,QAAQF;AAC9F;AAOA,OAAO,SAASI,cAAcpB,IAAgB,EAAEC,UAAkB,EAAEC,UAAmB,EAAEC,QAA+B;IACtH,MAAMC,SAAS,CAACC;QACd,MAAMC,WAAW;YACfZ,SAAS;gBACP,IAAI;oBACFW,GAAG,MAAMd,YAAYS,MAAMC,YAAYC;gBACzC,EAAE,OAAOK,KAAK;oBACZF,GAAGE;gBACL;YACF;QACF;QAEA,MAAMC,SAASf;QACf,IAAIe,mBAAAA,6BAAAA,OAAQa,KAAK,EAAE;YACjB,IAAI;gBACF,uDAAuD;gBACvD,MAAMX,MAAMC,OAAOC,QAAQ,CAACZ,QAAQA,OAAOA,KAAKa,QAAQ;gBACxD,MAAMC,UAAUN,OAAOa,KAAK,CAACX,KAAKT,YAAYC;gBAC9C,IAAIY,WAAW,OAAOA,QAAQC,IAAI,KAAK,YAAY;oBACjDD,QAAQC,IAAI,CAAC,CAACC,QAAUX,GAAG,MAAMW,QAAQV;oBACzC;gBACF;YACF,EAAE,OAAM;YACN,2BAA2B;YAC7B;QACF;QACAA;IACF;IAEA,IAAI,OAAOH,aAAa,YAAY,OAAOC,OAAOD;IAClD,OAAO,IAAIc,QAAQ,CAACC,SAASC,SAAWf,OAAO,CAACG,KAAKS,QAAWT,MAAMY,OAAOZ,OAAOW,QAAQF;AAC9F"}