7z-iterator 1.0.0 → 1.0.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.
package/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  ## 7z-iterator
2
2
 
3
- Extract contents from zip archive type using an iterator API using streams or paths. Use stream interface and pipe transforms to add decompression algorithms.
3
+ Extract contents from 7z archive type using an iterator API using streams or paths. Use stream interface and pipe transforms to add decompression algorithms.
4
4
 
5
5
  // asyncIterator
6
6
 
7
7
  ```js
8
8
  var assert = require('assert');
9
9
  var fs = require('fs');
10
- var ZipIterator = require('7z-iterator');
10
+ var SevenZipIterator = require('7z-iterator');
11
11
 
12
12
  (async function() {
13
- let iterator = new ZipIterator('/path/to/archive');
13
+ let iterator = new SevenZipIterator('/path/to/archive');
14
14
 
15
15
  try {
16
16
  const links = [];
@@ -30,7 +30,7 @@ var ZipIterator = require('7z-iterator');
30
30
  })();
31
31
 
32
32
  (async function() {
33
- let iterator = new ZipIterator(fs.createReadStream('/path/to/archive'));
33
+ let iterator = new SevenZipIterator(fs.createReadStream('/path/to/archive'));
34
34
 
35
35
  try {
36
36
  const links = [];
@@ -54,11 +54,11 @@ var ZipIterator = require('7z-iterator');
54
54
 
55
55
  ```js
56
56
  var assert = require('assert');
57
- var ZipIterator = require('7z-iterator');
57
+ var SevenZipIterator = require('7z-iterator');
58
58
 
59
59
  // one by one
60
60
  (async function() {
61
- let iterator = new ZipIterator('/path/to/archive');
61
+ let iterator = new SevenZipIterator('/path/to/archive');
62
62
 
63
63
  const links = [];
64
64
  let entry = await iterator.next();
@@ -79,7 +79,7 @@ var ZipIterator = require('7z-iterator');
79
79
 
80
80
  // infinite concurrency
81
81
  (async function() {
82
- let iterator = new ZipIterator('/path/to/archive');
82
+ let iterator = new SevenZipIterator('/path/to/archive');
83
83
 
84
84
  try {
85
85
  const links = [];
@@ -108,9 +108,9 @@ var ZipIterator = require('7z-iterator');
108
108
  ```js
109
109
  var assert = require('assert');
110
110
  var Queue = require('queue-cb');
111
- var ZipIterator = require('7z-iterator');
111
+ var SevenZipIterator = require('7z-iterator');
112
112
 
113
- var iterator = new ZipIterator('/path/to/archive');
113
+ var iterator = new SevenZipIterator('/path/to/archive');
114
114
 
115
115
  // one by one
116
116
  var links = [];
@@ -126,7 +126,7 @@ iterator.forEach(
126
126
  },
127
127
  { callbacks: true, concurrency: 1 },
128
128
  function (err) {
129
-
129
+
130
130
  // create links after directories and files
131
131
  var queue = new Queue();
132
132
  for (var index = 0; index < links.length; index++) {
@@ -142,6 +142,32 @@ Decoder.prototype.setSolid = function(solid) {
142
142
  this._solid = solid;
143
143
  };
144
144
 
145
+ Decoder.prototype.resetProbabilities = function() {
146
+ // Reset probability tables (same as init() but without dictionary/stream reset)
147
+ // Used for LZMA2 control bytes 0xa0-0xdf (state reset without dictionary reset)
148
+ initBitModels(this._isMatchDecoders);
149
+ initBitModels(this._isRepDecoders);
150
+ initBitModels(this._isRepG0Decoders);
151
+ initBitModels(this._isRepG1Decoders);
152
+ initBitModels(this._isRepG2Decoders);
153
+ initBitModels(this._isRep0LongDecoders);
154
+ initBitModels(this._posDecoders);
155
+ this._literalDecoder.init();
156
+ for (var i = this._posSlotDecoder.length - 1; i >= 0; i--) {
157
+ this._posSlotDecoder[i].init();
158
+ }
159
+ this._lenDecoder.init();
160
+ this._repLenDecoder.init();
161
+ this._posAlignDecoder.init();
162
+ // Reset state variables
163
+ this._state = 0;
164
+ this._rep0 = 0;
165
+ this._rep1 = 0;
166
+ this._rep2 = 0;
167
+ this._rep3 = 0;
168
+ // DO NOT reset _nowPos64, _prevByte, or dictionary
169
+ };
170
+
145
171
  Decoder.prototype.setDictionarySize = function(dictionarySize){
146
172
  if (dictionarySize < 0) return false;
147
173
  if (this._dictionarySize !== dictionarySize){
@@ -186,7 +186,14 @@ function decodeLzma2(input, properties, unpackSize) {
186
186
  var inStream = (0, _streamsts.createInputStream)(input, offset, compSize);
187
187
  var outStream = (0, _streamsts.createOutputStream)(uncompSize2); // Pre-allocate for memory efficiency
188
188
  // Set solid mode based on control byte - this preserves state across code() calls
189
- decoder.setSolid(useSolidMode);
189
+ // For state reset WITHOUT dict reset (0xa0-0xdf), use resetProbabilities() to
190
+ // reset probability tables while preserving _nowPos64 for dictionary references
191
+ if (resetState && !dictReset) {
192
+ decoder.resetProbabilities();
193
+ decoder.setSolid(true); // Preserve _nowPos64 in code()
194
+ } else {
195
+ decoder.setSolid(useSolidMode);
196
+ }
190
197
  // Decode the chunk
191
198
  var success = decoder.code(inStream, outStream, uncompSize2);
192
199
  if (!success) {
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/sevenz/codecs/Lzma2.ts"],"sourcesContent":["import Module from 'module';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// LZMA2 codec - uses native lzma-native when available, falls back to lzma-purejs\n// LZMA2 is a container format that wraps LZMA chunks with framing\n//\n// LZMA2 format specification:\n// https://github.com/ulikunitz/xz/blob/master/doc/LZMA2.md\n//\n// Control byte values:\n// 0x00 = End of stream\n// 0x01 = Uncompressed chunk, dictionary reset\n// 0x02 = Uncompressed chunk, no dictionary reset\n// 0x80-0xFF = LZMA compressed chunk (bits encode reset flags and size)\n//\n// Native optimization: On Node.js 8+, lzma-native provides liblzma bindings\n// that decode LZMA2 streams natively for better performance.\n// Falls back to lzma-purejs for Node.js 0.8-7.x compatibility.\n\nimport { allocBufferUnsafe } from 'extract-base-iterator';\nimport type { Transform } from 'readable-stream';\nimport createBufferingDecoder from './createBufferingDecoder.ts';\nimport { createNativeLzma2Decoder, hasNativeLzma } from './lzmaCompat.ts';\nimport { createInputStream, createOutputStream } from './streams.ts';\n\n// Import vendored lzma-purejs - provides raw LZMA decoder (patched for LZMA2 support)\n// Path accounts for build output in dist/esm/sevenz/codecs/\nconst { LZMA } = _require('../../../../assets/lzma-purejs');\nconst LzmaDecoder = LZMA.Decoder;\n\n/**\n * Decode LZMA2 dictionary size from properties byte\n * Properties byte encodes dictionary size as: 2^(dictByte/2 + 12) or similar\n *\n * Per XZ spec, dictionary sizes are:\n * 0x00 = 4 KiB (2^12)\n * 0x01 = 6 KiB\n * 0x02 = 8 KiB (2^13)\n * ...\n * 0x28 = 1.5 GiB\n */\nfunction decodeDictionarySize(propByte: number): number {\n if (propByte > 40) {\n throw new Error(`Invalid LZMA2 dictionary size property: ${propByte}`);\n }\n if (propByte === 40) {\n // Max dictionary size: 4 GiB - 1\n return 0xffffffff;\n }\n // Dictionary size = 2 | (propByte & 1) << (propByte / 2 + 11)\n const base = 2 | (propByte & 1);\n const shift = Math.floor(propByte / 2) + 11;\n return base << shift;\n}\n\n/**\n * Decode LZMA2 compressed data to buffer\n *\n * @param input - LZMA2 compressed data\n * @param properties - Properties buffer (1 byte: dictionary size)\n * @param unpackSize - Expected output size (used for pre-allocation to reduce memory)\n * @returns Decompressed data\n */\nexport function decodeLzma2(input: Buffer, properties?: Buffer, unpackSize?: number): Buffer {\n if (!properties || properties.length < 1) {\n throw new Error('LZMA2 requires properties byte');\n }\n\n const dictSize = decodeDictionarySize(properties[0]);\n\n // Memory optimization: pre-allocate output buffer if size is known\n // This avoids double-memory during Buffer.concat\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 // LZMA decoder instance - reused across chunks\n // The vendored decoder supports setSolid() for LZMA2 state preservation\n // The decoder also has _nowPos64 which tracks cumulative position for rep0 validation\n // and _prevByte which is used for literal decoder context selection\n const decoder = new LzmaDecoder() as InstanceType<typeof LzmaDecoder> & {\n setSolid: (solid: boolean) => void;\n _nowPos64: number;\n _prevByte: number;\n };\n decoder.setDictionarySize(dictSize);\n\n // Access internal _outWindow for dictionary management\n // We need to preserve dictionary state across LZMA2 chunks\n type OutWindowType = {\n _buffer: Buffer;\n _pos: number;\n _streamPos: number;\n _windowSize: number;\n init: (solid: boolean) => void;\n };\n const outWindow = (decoder as unknown as { _outWindow: OutWindowType })._outWindow;\n\n // Track current LZMA properties (lc, lp, pb)\n let propsSet = false;\n\n while (offset < input.length) {\n const control = input[offset++];\n\n if (control === 0x00) {\n // End of LZMA2 stream\n break;\n }\n\n if (control === 0x01 || control === 0x02) {\n // Uncompressed chunk\n // 0x01 = dictionary reset + uncompressed\n // 0x02 = uncompressed (no reset)\n\n // Handle dictionary reset for 0x01\n if (control === 0x01) {\n outWindow._pos = 0;\n outWindow._streamPos = 0;\n decoder._nowPos64 = 0;\n }\n\n if (offset + 2 > input.length) {\n throw new Error('Truncated LZMA2 uncompressed chunk header');\n }\n\n // Size is big-endian, 16-bit, value + 1\n const uncompSize = ((input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n if (offset + uncompSize > input.length) {\n throw new Error('Truncated LZMA2 uncompressed data');\n }\n\n // Get the uncompressed data\n const uncompData = input.slice(offset, offset + uncompSize);\n\n // Copy uncompressed data to output\n if (outputBuffer) {\n uncompData.copy(outputBuffer, outputPos);\n outputPos += uncompData.length;\n } else {\n outputChunks?.push(uncompData);\n }\n\n // Also update the decoder's internal dictionary so subsequent LZMA chunks can reference it\n // The decoder needs to track this data for LZ77 back-references\n // We write directly to _buffer to avoid flush() which requires _stream to be set\n // We must also update _streamPos to match _pos so that flush() doesn't try to write\n for (let i = 0; i < uncompData.length; i++) {\n outWindow._buffer[outWindow._pos++] = uncompData[i];\n // Handle circular buffer wrap-around\n if (outWindow._pos >= outWindow._windowSize) {\n outWindow._pos = 0;\n }\n }\n // Keep _streamPos in sync so flush() doesn't try to write these bytes\n // (they're already in our output buffer)\n outWindow._streamPos = outWindow._pos;\n\n // Update decoder's cumulative position so subsequent LZMA chunks have correct rep0 validation\n decoder._nowPos64 += uncompSize;\n\n // Update prevByte for literal decoder context in subsequent LZMA chunks\n decoder._prevByte = uncompData[uncompData.length - 1];\n\n offset += uncompSize;\n } else if (control >= 0x80) {\n // LZMA compressed chunk\n // Control byte format (bits 7-0):\n // Bit 7: always 1 for LZMA chunk\n // Bits 6-5: reset mode (00=nothing, 01=state, 10=state+props, 11=all)\n // Bits 4-0: high 5 bits of uncompressed size - 1\n\n // Control byte ranges (based on bits 6-5):\n // 0x80-0x9F (00): no reset - continue existing state (solid mode)\n // 0xA0-0xBF (01): reset state only\n // 0xC0-0xDF (10): reset state + new properties\n // 0xE0-0xFF (11): reset dictionary + state + new properties\n const resetState = control >= 0xa0;\n const newProps = control >= 0xc0;\n const dictReset = control >= 0xe0;\n const useSolidMode = !resetState;\n\n // Handle dictionary reset for control bytes 0xE0-0xFF\n if (dictReset) {\n outWindow._pos = 0;\n outWindow._streamPos = 0;\n }\n\n if (offset + 4 > input.length) {\n throw new Error('Truncated LZMA2 LZMA chunk header');\n }\n\n // Uncompressed size: 5 bits from control + 16 bits from next 2 bytes + 1\n const uncompHigh = control & 0x1f;\n const uncompSize2 = ((uncompHigh << 16) | (input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n // Compressed size: 16 bits + 1\n const compSize = ((input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n // If new properties, read 1-byte LZMA properties\n if (newProps) {\n if (offset >= input.length) {\n throw new Error('Truncated LZMA2 properties byte');\n }\n const propsByte = input[offset++];\n\n // Properties byte: pb * 45 + lp * 9 + lc\n // where pb, lp, lc are LZMA parameters\n const lc = propsByte % 9;\n const remainder = Math.floor(propsByte / 9);\n const lp = remainder % 5;\n const pb = Math.floor(remainder / 5);\n\n if (!decoder.setLcLpPb(lc, lp, pb)) {\n throw new Error(`Invalid LZMA properties: lc=${lc} lp=${lp} pb=${pb}`);\n }\n propsSet = true;\n }\n\n if (!propsSet) {\n throw new Error('LZMA chunk without properties');\n }\n\n if (offset + compSize > input.length) {\n throw new Error('Truncated LZMA2 compressed data');\n }\n\n // Decode LZMA chunk\n const inStream = createInputStream(input, offset, compSize);\n const outStream = createOutputStream(uncompSize2); // Pre-allocate for memory efficiency\n\n // Set solid mode based on control byte - this preserves state across code() calls\n decoder.setSolid(useSolidMode);\n\n // Decode the chunk\n const success = decoder.code(inStream, outStream, uncompSize2);\n if (!success) {\n throw new Error('LZMA decompression failed');\n }\n\n const chunkOutput = outStream.toBuffer();\n if (outputBuffer) {\n chunkOutput.copy(outputBuffer, outputPos);\n outputPos += chunkOutput.length;\n } else {\n outputChunks?.push(chunkOutput);\n }\n\n offset += compSize;\n } else {\n throw new Error(`Invalid LZMA2 control byte: 0x${control.toString(16)}`);\n }\n }\n\n // Return pre-allocated buffer or concatenated chunks\n if (outputBuffer) {\n // Return only the used portion if we didn't fill the buffer\n return outputPos < outputBuffer.length ? outputBuffer.slice(0, outputPos) : outputBuffer;\n }\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Create an LZMA2 decoder Transform stream\n *\n * Uses native lzma-native when available for better performance,\n * falls back to lzma-purejs buffering decoder for Node.js 0.8+ compatibility.\n */\nexport function createLzma2Decoder(properties?: Buffer, unpackSize?: number): Transform {\n // Try native decoder first (available on Node.js 8+ with lzma-native installed)\n if (hasNativeLzma && properties && properties.length >= 1) {\n const dictSize = decodeDictionarySize(properties[0]);\n const nativeDecoder = createNativeLzma2Decoder(dictSize);\n if (nativeDecoder) {\n return nativeDecoder;\n }\n }\n\n // Fall back to buffering decoder with pure JS implementation\n return createBufferingDecoder(decodeLzma2, properties, unpackSize);\n}\n"],"names":["createLzma2Decoder","decodeLzma2","_require","require","Module","createRequire","LZMA","LzmaDecoder","Decoder","decodeDictionarySize","propByte","Error","base","shift","Math","floor","input","properties","unpackSize","length","dictSize","outputBuffer","outputPos","outputChunks","allocBufferUnsafe","offset","decoder","setDictionarySize","outWindow","_outWindow","propsSet","control","_pos","_streamPos","_nowPos64","uncompSize","uncompData","slice","copy","push","i","_buffer","_windowSize","_prevByte","resetState","newProps","dictReset","useSolidMode","uncompHigh","uncompSize2","compSize","propsByte","lc","remainder","lp","pb","setLcLpPb","inStream","createInputStream","outStream","createOutputStream","setSolid","success","code","chunkOutput","toBuffer","toString","Buffer","concat","hasNativeLzma","nativeDecoder","createNativeLzma2Decoder","createBufferingDecoder"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/sevenz/codecs/Lzma2.ts"],"sourcesContent":["import Module from 'module';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// LZMA2 codec - uses native lzma-native when available, falls back to lzma-purejs\n// LZMA2 is a container format that wraps LZMA chunks with framing\n//\n// LZMA2 format specification:\n// https://github.com/ulikunitz/xz/blob/master/doc/LZMA2.md\n//\n// Control byte values:\n// 0x00 = End of stream\n// 0x01 = Uncompressed chunk, dictionary reset\n// 0x02 = Uncompressed chunk, no dictionary reset\n// 0x80-0xFF = LZMA compressed chunk (bits encode reset flags and size)\n//\n// Native optimization: On Node.js 8+, lzma-native provides liblzma bindings\n// that decode LZMA2 streams natively for better performance.\n// Falls back to lzma-purejs for Node.js 0.8-7.x compatibility.\n\nimport { allocBufferUnsafe } from 'extract-base-iterator';\nimport type { Transform } from 'readable-stream';\nimport createBufferingDecoder from './createBufferingDecoder.ts';\nimport { createNativeLzma2Decoder, hasNativeLzma } from './lzmaCompat.ts';\nimport { createInputStream, createOutputStream } from './streams.ts';\n\n// Import vendored lzma-purejs - provides raw LZMA decoder (patched for LZMA2 support)\n// Path accounts for build output in dist/esm/sevenz/codecs/\nconst { LZMA } = _require('../../../../assets/lzma-purejs');\nconst LzmaDecoder = LZMA.Decoder;\n\n/**\n * Decode LZMA2 dictionary size from properties byte\n * Properties byte encodes dictionary size as: 2^(dictByte/2 + 12) or similar\n *\n * Per XZ spec, dictionary sizes are:\n * 0x00 = 4 KiB (2^12)\n * 0x01 = 6 KiB\n * 0x02 = 8 KiB (2^13)\n * ...\n * 0x28 = 1.5 GiB\n */\nfunction decodeDictionarySize(propByte: number): number {\n if (propByte > 40) {\n throw new Error(`Invalid LZMA2 dictionary size property: ${propByte}`);\n }\n if (propByte === 40) {\n // Max dictionary size: 4 GiB - 1\n return 0xffffffff;\n }\n // Dictionary size = 2 | (propByte & 1) << (propByte / 2 + 11)\n const base = 2 | (propByte & 1);\n const shift = Math.floor(propByte / 2) + 11;\n return base << shift;\n}\n\n/**\n * Decode LZMA2 compressed data to buffer\n *\n * @param input - LZMA2 compressed data\n * @param properties - Properties buffer (1 byte: dictionary size)\n * @param unpackSize - Expected output size (used for pre-allocation to reduce memory)\n * @returns Decompressed data\n */\nexport function decodeLzma2(input: Buffer, properties?: Buffer, unpackSize?: number): Buffer {\n if (!properties || properties.length < 1) {\n throw new Error('LZMA2 requires properties byte');\n }\n\n const dictSize = decodeDictionarySize(properties[0]);\n\n // Memory optimization: pre-allocate output buffer if size is known\n // This avoids double-memory during Buffer.concat\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 // LZMA decoder instance - reused across chunks\n // The vendored decoder supports setSolid() for LZMA2 state preservation\n // The decoder also has _nowPos64 which tracks cumulative position for rep0 validation\n // and _prevByte which is used for literal decoder context selection\n const decoder = new LzmaDecoder() as InstanceType<typeof LzmaDecoder> & {\n setSolid: (solid: boolean) => void;\n resetProbabilities: () => void;\n _nowPos64: number;\n _prevByte: number;\n };\n decoder.setDictionarySize(dictSize);\n\n // Access internal _outWindow for dictionary management\n // We need to preserve dictionary state across LZMA2 chunks\n type OutWindowType = {\n _buffer: Buffer;\n _pos: number;\n _streamPos: number;\n _windowSize: number;\n init: (solid: boolean) => void;\n };\n const outWindow = (decoder as unknown as { _outWindow: OutWindowType })._outWindow;\n\n // Track current LZMA properties (lc, lp, pb)\n let propsSet = false;\n\n while (offset < input.length) {\n const control = input[offset++];\n\n if (control === 0x00) {\n // End of LZMA2 stream\n break;\n }\n\n if (control === 0x01 || control === 0x02) {\n // Uncompressed chunk\n // 0x01 = dictionary reset + uncompressed\n // 0x02 = uncompressed (no reset)\n\n // Handle dictionary reset for 0x01\n if (control === 0x01) {\n outWindow._pos = 0;\n outWindow._streamPos = 0;\n decoder._nowPos64 = 0;\n }\n\n if (offset + 2 > input.length) {\n throw new Error('Truncated LZMA2 uncompressed chunk header');\n }\n\n // Size is big-endian, 16-bit, value + 1\n const uncompSize = ((input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n if (offset + uncompSize > input.length) {\n throw new Error('Truncated LZMA2 uncompressed data');\n }\n\n // Get the uncompressed data\n const uncompData = input.slice(offset, offset + uncompSize);\n\n // Copy uncompressed data to output\n if (outputBuffer) {\n uncompData.copy(outputBuffer, outputPos);\n outputPos += uncompData.length;\n } else {\n outputChunks?.push(uncompData);\n }\n\n // Also update the decoder's internal dictionary so subsequent LZMA chunks can reference it\n // The decoder needs to track this data for LZ77 back-references\n // We write directly to _buffer to avoid flush() which requires _stream to be set\n // We must also update _streamPos to match _pos so that flush() doesn't try to write\n for (let i = 0; i < uncompData.length; i++) {\n outWindow._buffer[outWindow._pos++] = uncompData[i];\n // Handle circular buffer wrap-around\n if (outWindow._pos >= outWindow._windowSize) {\n outWindow._pos = 0;\n }\n }\n // Keep _streamPos in sync so flush() doesn't try to write these bytes\n // (they're already in our output buffer)\n outWindow._streamPos = outWindow._pos;\n\n // Update decoder's cumulative position so subsequent LZMA chunks have correct rep0 validation\n decoder._nowPos64 += uncompSize;\n\n // Update prevByte for literal decoder context in subsequent LZMA chunks\n decoder._prevByte = uncompData[uncompData.length - 1];\n\n offset += uncompSize;\n } else if (control >= 0x80) {\n // LZMA compressed chunk\n // Control byte format (bits 7-0):\n // Bit 7: always 1 for LZMA chunk\n // Bits 6-5: reset mode (00=nothing, 01=state, 10=state+props, 11=all)\n // Bits 4-0: high 5 bits of uncompressed size - 1\n\n // Control byte ranges (based on bits 6-5):\n // 0x80-0x9F (00): no reset - continue existing state (solid mode)\n // 0xA0-0xBF (01): reset state only\n // 0xC0-0xDF (10): reset state + new properties\n // 0xE0-0xFF (11): reset dictionary + state + new properties\n const resetState = control >= 0xa0;\n const newProps = control >= 0xc0;\n const dictReset = control >= 0xe0;\n const useSolidMode = !resetState;\n\n // Handle dictionary reset for control bytes 0xE0-0xFF\n if (dictReset) {\n outWindow._pos = 0;\n outWindow._streamPos = 0;\n }\n\n if (offset + 4 > input.length) {\n throw new Error('Truncated LZMA2 LZMA chunk header');\n }\n\n // Uncompressed size: 5 bits from control + 16 bits from next 2 bytes + 1\n const uncompHigh = control & 0x1f;\n const uncompSize2 = ((uncompHigh << 16) | (input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n // Compressed size: 16 bits + 1\n const compSize = ((input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n // If new properties, read 1-byte LZMA properties\n if (newProps) {\n if (offset >= input.length) {\n throw new Error('Truncated LZMA2 properties byte');\n }\n const propsByte = input[offset++];\n\n // Properties byte: pb * 45 + lp * 9 + lc\n // where pb, lp, lc are LZMA parameters\n const lc = propsByte % 9;\n const remainder = Math.floor(propsByte / 9);\n const lp = remainder % 5;\n const pb = Math.floor(remainder / 5);\n\n if (!decoder.setLcLpPb(lc, lp, pb)) {\n throw new Error(`Invalid LZMA properties: lc=${lc} lp=${lp} pb=${pb}`);\n }\n propsSet = true;\n }\n\n if (!propsSet) {\n throw new Error('LZMA chunk without properties');\n }\n\n if (offset + compSize > input.length) {\n throw new Error('Truncated LZMA2 compressed data');\n }\n\n // Decode LZMA chunk\n const inStream = createInputStream(input, offset, compSize);\n const outStream = createOutputStream(uncompSize2); // Pre-allocate for memory efficiency\n\n // Set solid mode based on control byte - this preserves state across code() calls\n // For state reset WITHOUT dict reset (0xa0-0xdf), use resetProbabilities() to\n // reset probability tables while preserving _nowPos64 for dictionary references\n if (resetState && !dictReset) {\n decoder.resetProbabilities();\n decoder.setSolid(true); // Preserve _nowPos64 in code()\n } else {\n decoder.setSolid(useSolidMode);\n }\n\n // Decode the chunk\n const success = decoder.code(inStream, outStream, uncompSize2);\n if (!success) {\n throw new Error('LZMA decompression failed');\n }\n\n const chunkOutput = outStream.toBuffer();\n if (outputBuffer) {\n chunkOutput.copy(outputBuffer, outputPos);\n outputPos += chunkOutput.length;\n } else {\n outputChunks?.push(chunkOutput);\n }\n\n offset += compSize;\n } else {\n throw new Error(`Invalid LZMA2 control byte: 0x${control.toString(16)}`);\n }\n }\n\n // Return pre-allocated buffer or concatenated chunks\n if (outputBuffer) {\n // Return only the used portion if we didn't fill the buffer\n return outputPos < outputBuffer.length ? outputBuffer.slice(0, outputPos) : outputBuffer;\n }\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Create an LZMA2 decoder Transform stream\n *\n * Uses native lzma-native when available for better performance,\n * falls back to lzma-purejs buffering decoder for Node.js 0.8+ compatibility.\n */\nexport function createLzma2Decoder(properties?: Buffer, unpackSize?: number): Transform {\n // Try native decoder first (available on Node.js 8+ with lzma-native installed)\n if (hasNativeLzma && properties && properties.length >= 1) {\n const dictSize = decodeDictionarySize(properties[0]);\n const nativeDecoder = createNativeLzma2Decoder(dictSize);\n if (nativeDecoder) {\n return nativeDecoder;\n }\n }\n\n // Fall back to buffering decoder with pure JS implementation\n return createBufferingDecoder(decodeLzma2, properties, unpackSize);\n}\n"],"names":["createLzma2Decoder","decodeLzma2","_require","require","Module","createRequire","LZMA","LzmaDecoder","Decoder","decodeDictionarySize","propByte","Error","base","shift","Math","floor","input","properties","unpackSize","length","dictSize","outputBuffer","outputPos","outputChunks","allocBufferUnsafe","offset","decoder","setDictionarySize","outWindow","_outWindow","propsSet","control","_pos","_streamPos","_nowPos64","uncompSize","uncompData","slice","copy","push","i","_buffer","_windowSize","_prevByte","resetState","newProps","dictReset","useSolidMode","uncompHigh","uncompSize2","compSize","propsByte","lc","remainder","lp","pb","setLcLpPb","inStream","createInputStream","outStream","createOutputStream","resetProbabilities","setSolid","success","code","chunkOutput","toBuffer","toString","Buffer","concat","hasNativeLzma","nativeDecoder","createNativeLzma2Decoder","createBufferingDecoder"],"mappings":"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"}
@@ -185,7 +185,14 @@ const LzmaDecoder = LZMA.Decoder;
185
185
  const inStream = createInputStream(input, offset, compSize);
186
186
  const outStream = createOutputStream(uncompSize2); // Pre-allocate for memory efficiency
187
187
  // Set solid mode based on control byte - this preserves state across code() calls
188
- decoder.setSolid(useSolidMode);
188
+ // For state reset WITHOUT dict reset (0xa0-0xdf), use resetProbabilities() to
189
+ // reset probability tables while preserving _nowPos64 for dictionary references
190
+ if (resetState && !dictReset) {
191
+ decoder.resetProbabilities();
192
+ decoder.setSolid(true); // Preserve _nowPos64 in code()
193
+ } else {
194
+ decoder.setSolid(useSolidMode);
195
+ }
189
196
  // Decode the chunk
190
197
  const success = decoder.code(inStream, outStream, uncompSize2);
191
198
  if (!success) {
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/sevenz/codecs/Lzma2.ts"],"sourcesContent":["import Module from 'module';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// LZMA2 codec - uses native lzma-native when available, falls back to lzma-purejs\n// LZMA2 is a container format that wraps LZMA chunks with framing\n//\n// LZMA2 format specification:\n// https://github.com/ulikunitz/xz/blob/master/doc/LZMA2.md\n//\n// Control byte values:\n// 0x00 = End of stream\n// 0x01 = Uncompressed chunk, dictionary reset\n// 0x02 = Uncompressed chunk, no dictionary reset\n// 0x80-0xFF = LZMA compressed chunk (bits encode reset flags and size)\n//\n// Native optimization: On Node.js 8+, lzma-native provides liblzma bindings\n// that decode LZMA2 streams natively for better performance.\n// Falls back to lzma-purejs for Node.js 0.8-7.x compatibility.\n\nimport { allocBufferUnsafe } from 'extract-base-iterator';\nimport type { Transform } from 'readable-stream';\nimport createBufferingDecoder from './createBufferingDecoder.ts';\nimport { createNativeLzma2Decoder, hasNativeLzma } from './lzmaCompat.ts';\nimport { createInputStream, createOutputStream } from './streams.ts';\n\n// Import vendored lzma-purejs - provides raw LZMA decoder (patched for LZMA2 support)\n// Path accounts for build output in dist/esm/sevenz/codecs/\nconst { LZMA } = _require('../../../../assets/lzma-purejs');\nconst LzmaDecoder = LZMA.Decoder;\n\n/**\n * Decode LZMA2 dictionary size from properties byte\n * Properties byte encodes dictionary size as: 2^(dictByte/2 + 12) or similar\n *\n * Per XZ spec, dictionary sizes are:\n * 0x00 = 4 KiB (2^12)\n * 0x01 = 6 KiB\n * 0x02 = 8 KiB (2^13)\n * ...\n * 0x28 = 1.5 GiB\n */\nfunction decodeDictionarySize(propByte: number): number {\n if (propByte > 40) {\n throw new Error(`Invalid LZMA2 dictionary size property: ${propByte}`);\n }\n if (propByte === 40) {\n // Max dictionary size: 4 GiB - 1\n return 0xffffffff;\n }\n // Dictionary size = 2 | (propByte & 1) << (propByte / 2 + 11)\n const base = 2 | (propByte & 1);\n const shift = Math.floor(propByte / 2) + 11;\n return base << shift;\n}\n\n/**\n * Decode LZMA2 compressed data to buffer\n *\n * @param input - LZMA2 compressed data\n * @param properties - Properties buffer (1 byte: dictionary size)\n * @param unpackSize - Expected output size (used for pre-allocation to reduce memory)\n * @returns Decompressed data\n */\nexport function decodeLzma2(input: Buffer, properties?: Buffer, unpackSize?: number): Buffer {\n if (!properties || properties.length < 1) {\n throw new Error('LZMA2 requires properties byte');\n }\n\n const dictSize = decodeDictionarySize(properties[0]);\n\n // Memory optimization: pre-allocate output buffer if size is known\n // This avoids double-memory during Buffer.concat\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 // LZMA decoder instance - reused across chunks\n // The vendored decoder supports setSolid() for LZMA2 state preservation\n // The decoder also has _nowPos64 which tracks cumulative position for rep0 validation\n // and _prevByte which is used for literal decoder context selection\n const decoder = new LzmaDecoder() as InstanceType<typeof LzmaDecoder> & {\n setSolid: (solid: boolean) => void;\n _nowPos64: number;\n _prevByte: number;\n };\n decoder.setDictionarySize(dictSize);\n\n // Access internal _outWindow for dictionary management\n // We need to preserve dictionary state across LZMA2 chunks\n type OutWindowType = {\n _buffer: Buffer;\n _pos: number;\n _streamPos: number;\n _windowSize: number;\n init: (solid: boolean) => void;\n };\n const outWindow = (decoder as unknown as { _outWindow: OutWindowType })._outWindow;\n\n // Track current LZMA properties (lc, lp, pb)\n let propsSet = false;\n\n while (offset < input.length) {\n const control = input[offset++];\n\n if (control === 0x00) {\n // End of LZMA2 stream\n break;\n }\n\n if (control === 0x01 || control === 0x02) {\n // Uncompressed chunk\n // 0x01 = dictionary reset + uncompressed\n // 0x02 = uncompressed (no reset)\n\n // Handle dictionary reset for 0x01\n if (control === 0x01) {\n outWindow._pos = 0;\n outWindow._streamPos = 0;\n decoder._nowPos64 = 0;\n }\n\n if (offset + 2 > input.length) {\n throw new Error('Truncated LZMA2 uncompressed chunk header');\n }\n\n // Size is big-endian, 16-bit, value + 1\n const uncompSize = ((input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n if (offset + uncompSize > input.length) {\n throw new Error('Truncated LZMA2 uncompressed data');\n }\n\n // Get the uncompressed data\n const uncompData = input.slice(offset, offset + uncompSize);\n\n // Copy uncompressed data to output\n if (outputBuffer) {\n uncompData.copy(outputBuffer, outputPos);\n outputPos += uncompData.length;\n } else {\n outputChunks?.push(uncompData);\n }\n\n // Also update the decoder's internal dictionary so subsequent LZMA chunks can reference it\n // The decoder needs to track this data for LZ77 back-references\n // We write directly to _buffer to avoid flush() which requires _stream to be set\n // We must also update _streamPos to match _pos so that flush() doesn't try to write\n for (let i = 0; i < uncompData.length; i++) {\n outWindow._buffer[outWindow._pos++] = uncompData[i];\n // Handle circular buffer wrap-around\n if (outWindow._pos >= outWindow._windowSize) {\n outWindow._pos = 0;\n }\n }\n // Keep _streamPos in sync so flush() doesn't try to write these bytes\n // (they're already in our output buffer)\n outWindow._streamPos = outWindow._pos;\n\n // Update decoder's cumulative position so subsequent LZMA chunks have correct rep0 validation\n decoder._nowPos64 += uncompSize;\n\n // Update prevByte for literal decoder context in subsequent LZMA chunks\n decoder._prevByte = uncompData[uncompData.length - 1];\n\n offset += uncompSize;\n } else if (control >= 0x80) {\n // LZMA compressed chunk\n // Control byte format (bits 7-0):\n // Bit 7: always 1 for LZMA chunk\n // Bits 6-5: reset mode (00=nothing, 01=state, 10=state+props, 11=all)\n // Bits 4-0: high 5 bits of uncompressed size - 1\n\n // Control byte ranges (based on bits 6-5):\n // 0x80-0x9F (00): no reset - continue existing state (solid mode)\n // 0xA0-0xBF (01): reset state only\n // 0xC0-0xDF (10): reset state + new properties\n // 0xE0-0xFF (11): reset dictionary + state + new properties\n const resetState = control >= 0xa0;\n const newProps = control >= 0xc0;\n const dictReset = control >= 0xe0;\n const useSolidMode = !resetState;\n\n // Handle dictionary reset for control bytes 0xE0-0xFF\n if (dictReset) {\n outWindow._pos = 0;\n outWindow._streamPos = 0;\n }\n\n if (offset + 4 > input.length) {\n throw new Error('Truncated LZMA2 LZMA chunk header');\n }\n\n // Uncompressed size: 5 bits from control + 16 bits from next 2 bytes + 1\n const uncompHigh = control & 0x1f;\n const uncompSize2 = ((uncompHigh << 16) | (input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n // Compressed size: 16 bits + 1\n const compSize = ((input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n // If new properties, read 1-byte LZMA properties\n if (newProps) {\n if (offset >= input.length) {\n throw new Error('Truncated LZMA2 properties byte');\n }\n const propsByte = input[offset++];\n\n // Properties byte: pb * 45 + lp * 9 + lc\n // where pb, lp, lc are LZMA parameters\n const lc = propsByte % 9;\n const remainder = Math.floor(propsByte / 9);\n const lp = remainder % 5;\n const pb = Math.floor(remainder / 5);\n\n if (!decoder.setLcLpPb(lc, lp, pb)) {\n throw new Error(`Invalid LZMA properties: lc=${lc} lp=${lp} pb=${pb}`);\n }\n propsSet = true;\n }\n\n if (!propsSet) {\n throw new Error('LZMA chunk without properties');\n }\n\n if (offset + compSize > input.length) {\n throw new Error('Truncated LZMA2 compressed data');\n }\n\n // Decode LZMA chunk\n const inStream = createInputStream(input, offset, compSize);\n const outStream = createOutputStream(uncompSize2); // Pre-allocate for memory efficiency\n\n // Set solid mode based on control byte - this preserves state across code() calls\n decoder.setSolid(useSolidMode);\n\n // Decode the chunk\n const success = decoder.code(inStream, outStream, uncompSize2);\n if (!success) {\n throw new Error('LZMA decompression failed');\n }\n\n const chunkOutput = outStream.toBuffer();\n if (outputBuffer) {\n chunkOutput.copy(outputBuffer, outputPos);\n outputPos += chunkOutput.length;\n } else {\n outputChunks?.push(chunkOutput);\n }\n\n offset += compSize;\n } else {\n throw new Error(`Invalid LZMA2 control byte: 0x${control.toString(16)}`);\n }\n }\n\n // Return pre-allocated buffer or concatenated chunks\n if (outputBuffer) {\n // Return only the used portion if we didn't fill the buffer\n return outputPos < outputBuffer.length ? outputBuffer.slice(0, outputPos) : outputBuffer;\n }\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Create an LZMA2 decoder Transform stream\n *\n * Uses native lzma-native when available for better performance,\n * falls back to lzma-purejs buffering decoder for Node.js 0.8+ compatibility.\n */\nexport function createLzma2Decoder(properties?: Buffer, unpackSize?: number): Transform {\n // Try native decoder first (available on Node.js 8+ with lzma-native installed)\n if (hasNativeLzma && properties && properties.length >= 1) {\n const dictSize = decodeDictionarySize(properties[0]);\n const nativeDecoder = createNativeLzma2Decoder(dictSize);\n if (nativeDecoder) {\n return nativeDecoder;\n }\n }\n\n // Fall back to buffering decoder with pure JS implementation\n return createBufferingDecoder(decodeLzma2, properties, unpackSize);\n}\n"],"names":["Module","_require","require","createRequire","url","allocBufferUnsafe","createBufferingDecoder","createNativeLzma2Decoder","hasNativeLzma","createInputStream","createOutputStream","LZMA","LzmaDecoder","Decoder","decodeDictionarySize","propByte","Error","base","shift","Math","floor","decodeLzma2","input","properties","unpackSize","length","dictSize","outputBuffer","outputPos","outputChunks","offset","decoder","setDictionarySize","outWindow","_outWindow","propsSet","control","_pos","_streamPos","_nowPos64","uncompSize","uncompData","slice","copy","push","i","_buffer","_windowSize","_prevByte","resetState","newProps","dictReset","useSolidMode","uncompHigh","uncompSize2","compSize","propsByte","lc","remainder","lp","pb","setLcLpPb","inStream","outStream","setSolid","success","code","chunkOutput","toBuffer","toString","Buffer","concat","createLzma2Decoder","nativeDecoder"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/iterators/7z-iterator/src/sevenz/codecs/Lzma2.ts"],"sourcesContent":["import Module from 'module';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// LZMA2 codec - uses native lzma-native when available, falls back to lzma-purejs\n// LZMA2 is a container format that wraps LZMA chunks with framing\n//\n// LZMA2 format specification:\n// https://github.com/ulikunitz/xz/blob/master/doc/LZMA2.md\n//\n// Control byte values:\n// 0x00 = End of stream\n// 0x01 = Uncompressed chunk, dictionary reset\n// 0x02 = Uncompressed chunk, no dictionary reset\n// 0x80-0xFF = LZMA compressed chunk (bits encode reset flags and size)\n//\n// Native optimization: On Node.js 8+, lzma-native provides liblzma bindings\n// that decode LZMA2 streams natively for better performance.\n// Falls back to lzma-purejs for Node.js 0.8-7.x compatibility.\n\nimport { allocBufferUnsafe } from 'extract-base-iterator';\nimport type { Transform } from 'readable-stream';\nimport createBufferingDecoder from './createBufferingDecoder.ts';\nimport { createNativeLzma2Decoder, hasNativeLzma } from './lzmaCompat.ts';\nimport { createInputStream, createOutputStream } from './streams.ts';\n\n// Import vendored lzma-purejs - provides raw LZMA decoder (patched for LZMA2 support)\n// Path accounts for build output in dist/esm/sevenz/codecs/\nconst { LZMA } = _require('../../../../assets/lzma-purejs');\nconst LzmaDecoder = LZMA.Decoder;\n\n/**\n * Decode LZMA2 dictionary size from properties byte\n * Properties byte encodes dictionary size as: 2^(dictByte/2 + 12) or similar\n *\n * Per XZ spec, dictionary sizes are:\n * 0x00 = 4 KiB (2^12)\n * 0x01 = 6 KiB\n * 0x02 = 8 KiB (2^13)\n * ...\n * 0x28 = 1.5 GiB\n */\nfunction decodeDictionarySize(propByte: number): number {\n if (propByte > 40) {\n throw new Error(`Invalid LZMA2 dictionary size property: ${propByte}`);\n }\n if (propByte === 40) {\n // Max dictionary size: 4 GiB - 1\n return 0xffffffff;\n }\n // Dictionary size = 2 | (propByte & 1) << (propByte / 2 + 11)\n const base = 2 | (propByte & 1);\n const shift = Math.floor(propByte / 2) + 11;\n return base << shift;\n}\n\n/**\n * Decode LZMA2 compressed data to buffer\n *\n * @param input - LZMA2 compressed data\n * @param properties - Properties buffer (1 byte: dictionary size)\n * @param unpackSize - Expected output size (used for pre-allocation to reduce memory)\n * @returns Decompressed data\n */\nexport function decodeLzma2(input: Buffer, properties?: Buffer, unpackSize?: number): Buffer {\n if (!properties || properties.length < 1) {\n throw new Error('LZMA2 requires properties byte');\n }\n\n const dictSize = decodeDictionarySize(properties[0]);\n\n // Memory optimization: pre-allocate output buffer if size is known\n // This avoids double-memory during Buffer.concat\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 // LZMA decoder instance - reused across chunks\n // The vendored decoder supports setSolid() for LZMA2 state preservation\n // The decoder also has _nowPos64 which tracks cumulative position for rep0 validation\n // and _prevByte which is used for literal decoder context selection\n const decoder = new LzmaDecoder() as InstanceType<typeof LzmaDecoder> & {\n setSolid: (solid: boolean) => void;\n resetProbabilities: () => void;\n _nowPos64: number;\n _prevByte: number;\n };\n decoder.setDictionarySize(dictSize);\n\n // Access internal _outWindow for dictionary management\n // We need to preserve dictionary state across LZMA2 chunks\n type OutWindowType = {\n _buffer: Buffer;\n _pos: number;\n _streamPos: number;\n _windowSize: number;\n init: (solid: boolean) => void;\n };\n const outWindow = (decoder as unknown as { _outWindow: OutWindowType })._outWindow;\n\n // Track current LZMA properties (lc, lp, pb)\n let propsSet = false;\n\n while (offset < input.length) {\n const control = input[offset++];\n\n if (control === 0x00) {\n // End of LZMA2 stream\n break;\n }\n\n if (control === 0x01 || control === 0x02) {\n // Uncompressed chunk\n // 0x01 = dictionary reset + uncompressed\n // 0x02 = uncompressed (no reset)\n\n // Handle dictionary reset for 0x01\n if (control === 0x01) {\n outWindow._pos = 0;\n outWindow._streamPos = 0;\n decoder._nowPos64 = 0;\n }\n\n if (offset + 2 > input.length) {\n throw new Error('Truncated LZMA2 uncompressed chunk header');\n }\n\n // Size is big-endian, 16-bit, value + 1\n const uncompSize = ((input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n if (offset + uncompSize > input.length) {\n throw new Error('Truncated LZMA2 uncompressed data');\n }\n\n // Get the uncompressed data\n const uncompData = input.slice(offset, offset + uncompSize);\n\n // Copy uncompressed data to output\n if (outputBuffer) {\n uncompData.copy(outputBuffer, outputPos);\n outputPos += uncompData.length;\n } else {\n outputChunks?.push(uncompData);\n }\n\n // Also update the decoder's internal dictionary so subsequent LZMA chunks can reference it\n // The decoder needs to track this data for LZ77 back-references\n // We write directly to _buffer to avoid flush() which requires _stream to be set\n // We must also update _streamPos to match _pos so that flush() doesn't try to write\n for (let i = 0; i < uncompData.length; i++) {\n outWindow._buffer[outWindow._pos++] = uncompData[i];\n // Handle circular buffer wrap-around\n if (outWindow._pos >= outWindow._windowSize) {\n outWindow._pos = 0;\n }\n }\n // Keep _streamPos in sync so flush() doesn't try to write these bytes\n // (they're already in our output buffer)\n outWindow._streamPos = outWindow._pos;\n\n // Update decoder's cumulative position so subsequent LZMA chunks have correct rep0 validation\n decoder._nowPos64 += uncompSize;\n\n // Update prevByte for literal decoder context in subsequent LZMA chunks\n decoder._prevByte = uncompData[uncompData.length - 1];\n\n offset += uncompSize;\n } else if (control >= 0x80) {\n // LZMA compressed chunk\n // Control byte format (bits 7-0):\n // Bit 7: always 1 for LZMA chunk\n // Bits 6-5: reset mode (00=nothing, 01=state, 10=state+props, 11=all)\n // Bits 4-0: high 5 bits of uncompressed size - 1\n\n // Control byte ranges (based on bits 6-5):\n // 0x80-0x9F (00): no reset - continue existing state (solid mode)\n // 0xA0-0xBF (01): reset state only\n // 0xC0-0xDF (10): reset state + new properties\n // 0xE0-0xFF (11): reset dictionary + state + new properties\n const resetState = control >= 0xa0;\n const newProps = control >= 0xc0;\n const dictReset = control >= 0xe0;\n const useSolidMode = !resetState;\n\n // Handle dictionary reset for control bytes 0xE0-0xFF\n if (dictReset) {\n outWindow._pos = 0;\n outWindow._streamPos = 0;\n }\n\n if (offset + 4 > input.length) {\n throw new Error('Truncated LZMA2 LZMA chunk header');\n }\n\n // Uncompressed size: 5 bits from control + 16 bits from next 2 bytes + 1\n const uncompHigh = control & 0x1f;\n const uncompSize2 = ((uncompHigh << 16) | (input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n // Compressed size: 16 bits + 1\n const compSize = ((input[offset] << 8) | input[offset + 1]) + 1;\n offset += 2;\n\n // If new properties, read 1-byte LZMA properties\n if (newProps) {\n if (offset >= input.length) {\n throw new Error('Truncated LZMA2 properties byte');\n }\n const propsByte = input[offset++];\n\n // Properties byte: pb * 45 + lp * 9 + lc\n // where pb, lp, lc are LZMA parameters\n const lc = propsByte % 9;\n const remainder = Math.floor(propsByte / 9);\n const lp = remainder % 5;\n const pb = Math.floor(remainder / 5);\n\n if (!decoder.setLcLpPb(lc, lp, pb)) {\n throw new Error(`Invalid LZMA properties: lc=${lc} lp=${lp} pb=${pb}`);\n }\n propsSet = true;\n }\n\n if (!propsSet) {\n throw new Error('LZMA chunk without properties');\n }\n\n if (offset + compSize > input.length) {\n throw new Error('Truncated LZMA2 compressed data');\n }\n\n // Decode LZMA chunk\n const inStream = createInputStream(input, offset, compSize);\n const outStream = createOutputStream(uncompSize2); // Pre-allocate for memory efficiency\n\n // Set solid mode based on control byte - this preserves state across code() calls\n // For state reset WITHOUT dict reset (0xa0-0xdf), use resetProbabilities() to\n // reset probability tables while preserving _nowPos64 for dictionary references\n if (resetState && !dictReset) {\n decoder.resetProbabilities();\n decoder.setSolid(true); // Preserve _nowPos64 in code()\n } else {\n decoder.setSolid(useSolidMode);\n }\n\n // Decode the chunk\n const success = decoder.code(inStream, outStream, uncompSize2);\n if (!success) {\n throw new Error('LZMA decompression failed');\n }\n\n const chunkOutput = outStream.toBuffer();\n if (outputBuffer) {\n chunkOutput.copy(outputBuffer, outputPos);\n outputPos += chunkOutput.length;\n } else {\n outputChunks?.push(chunkOutput);\n }\n\n offset += compSize;\n } else {\n throw new Error(`Invalid LZMA2 control byte: 0x${control.toString(16)}`);\n }\n }\n\n // Return pre-allocated buffer or concatenated chunks\n if (outputBuffer) {\n // Return only the used portion if we didn't fill the buffer\n return outputPos < outputBuffer.length ? outputBuffer.slice(0, outputPos) : outputBuffer;\n }\n return Buffer.concat(outputChunks);\n}\n\n/**\n * Create an LZMA2 decoder Transform stream\n *\n * Uses native lzma-native when available for better performance,\n * falls back to lzma-purejs buffering decoder for Node.js 0.8+ compatibility.\n */\nexport function createLzma2Decoder(properties?: Buffer, unpackSize?: number): Transform {\n // Try native decoder first (available on Node.js 8+ with lzma-native installed)\n if (hasNativeLzma && properties && properties.length >= 1) {\n const dictSize = decodeDictionarySize(properties[0]);\n const nativeDecoder = createNativeLzma2Decoder(dictSize);\n if (nativeDecoder) {\n return nativeDecoder;\n }\n }\n\n // Fall back to buffering decoder with pure JS implementation\n return createBufferingDecoder(decodeLzma2, properties, unpackSize);\n}\n"],"names":["Module","_require","require","createRequire","url","allocBufferUnsafe","createBufferingDecoder","createNativeLzma2Decoder","hasNativeLzma","createInputStream","createOutputStream","LZMA","LzmaDecoder","Decoder","decodeDictionarySize","propByte","Error","base","shift","Math","floor","decodeLzma2","input","properties","unpackSize","length","dictSize","outputBuffer","outputPos","outputChunks","offset","decoder","setDictionarySize","outWindow","_outWindow","propsSet","control","_pos","_streamPos","_nowPos64","uncompSize","uncompData","slice","copy","push","i","_buffer","_windowSize","_prevByte","resetState","newProps","dictReset","useSolidMode","uncompHigh","uncompSize2","compSize","propsByte","lc","remainder","lp","pb","setLcLpPb","inStream","outStream","resetProbabilities","setSolid","success","code","chunkOutput","toBuffer","toString","Buffer","concat","createLzma2Decoder","nativeDecoder"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "7z-iterator",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Extract contents from 7z archives using an iterator API. Pure JavaScript, works on Node.js 0.8+",
5
5
  "keywords": [
6
6
  "extract",