lzma1 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,16 @@
1
- # lzma1
1
+ <div align="center">
2
2
 
3
- This is a [fork][fork-link] of [Nathan Rugg's][fork-author] LZMA-JS package.
3
+ <h1>lzma1</h1>
4
+
5
+ This is a [fork][fork-link] of [Nathan Rugg's][fork-author] LZMA-JS package and
6
+ inspiration of [Java][7zip-sdk] and Googles [Go][go-sdk] implementations.
7
+
8
+ </div>
4
9
 
5
10
  [fork-link]: https://github.com/LZMA-JS/LZMA-JS
6
11
  [fork-author]: https://github.com/nmrugg
12
+ [7zip-sdk]: https://www.7-zip.org/sdk.html
13
+ [go-sdk]: https://code.google.com/p/lzma
7
14
 
8
15
  ## Why
9
16
 
@@ -156,7 +163,6 @@ More [information][header_link] about the LZMA header structure.
156
163
 
157
164
  ## Related
158
165
 
159
- - [7-Zip SDK](https://www.7-zip.org/sdk.html)
160
166
  - [lzma-purejs](https://github.com/cscott/lzma-purejs)
161
167
  - [lzmajs](https://github.com/glinscott/lzmajs)
162
168
  - [lzma-purejs fork](https://github.com/mauron85/lzma-purejs/tree/master)
@@ -0,0 +1,46 @@
1
+ import { Decoder } from "./decoder.js";
2
+ import { Encoder } from "./encoder.js";
3
+ /**
4
+ * Base chunker interface for both encoding and decoding operations
5
+ */
6
+ interface BaseChunker {
7
+ alive: number;
8
+ inBytesProcessed: [number, number];
9
+ }
10
+ /**
11
+ * Interface for LZMA instance needed by EncoderChunker
12
+ */
13
+ interface LZMAInstance {
14
+ codeOneBlock(): void;
15
+ releaseStreams(): void;
16
+ }
17
+ /**
18
+ * Encoder chunker for handling compression chunk processing
19
+ */
20
+ export declare class EncoderChunker implements BaseChunker {
21
+ encoder: Encoder | null;
22
+ decoder: null;
23
+ alive: number;
24
+ inBytesProcessed: [number, number];
25
+ private lzma;
26
+ constructor(lzma: LZMAInstance);
27
+ /**
28
+ * Process one chunk of encoding
29
+ */
30
+ processChunk(): number;
31
+ }
32
+ /**
33
+ * Decoder chunker for handling decompression chunk processing
34
+ */
35
+ export declare class DecoderChunker implements BaseChunker {
36
+ encoder: null;
37
+ decoder: Decoder;
38
+ alive: number;
39
+ inBytesProcessed: [number, number];
40
+ constructor(decoder: Decoder);
41
+ /**
42
+ * Process one chunk of decoding
43
+ */
44
+ processChunk(): number;
45
+ }
46
+ export {};
package/lib/chunker.js ADDED
@@ -0,0 +1,68 @@
1
+ import { compare64, P0_LONG_LIT, } from "./utils.js";
2
+ /**
3
+ * Encoder chunker for handling compression chunk processing
4
+ */
5
+ export class EncoderChunker {
6
+ encoder = null;
7
+ decoder = null;
8
+ alive = 0;
9
+ inBytesProcessed = [0, 0];
10
+ lzma;
11
+ constructor(lzma) {
12
+ this.lzma = lzma;
13
+ }
14
+ /**
15
+ * Process one chunk of encoding
16
+ */
17
+ processChunk() {
18
+ if (!this.alive) {
19
+ throw new Error("bad state");
20
+ }
21
+ if (!this.encoder) {
22
+ throw new Error("No decoding");
23
+ }
24
+ this.lzma.codeOneBlock();
25
+ this.inBytesProcessed = this.encoder.processedInSize[0];
26
+ if (this.encoder.finished[0]) {
27
+ this.lzma.releaseStreams();
28
+ this.alive = 0;
29
+ }
30
+ return this.alive;
31
+ }
32
+ }
33
+ /**
34
+ * Decoder chunker for handling decompression chunk processing
35
+ */
36
+ export class DecoderChunker {
37
+ encoder = null;
38
+ decoder;
39
+ alive = 0;
40
+ inBytesProcessed = [0, 0];
41
+ constructor(decoder) {
42
+ this.decoder = decoder;
43
+ }
44
+ /**
45
+ * Process one chunk of decoding
46
+ */
47
+ processChunk() {
48
+ if (!this.alive) {
49
+ throw new Error("Bad state");
50
+ }
51
+ if (this.encoder) {
52
+ throw new Error("No encoding");
53
+ }
54
+ const result = this.decoder.codeOneChunk();
55
+ if (result === -1) {
56
+ throw new Error("Corrupted input");
57
+ }
58
+ this.inBytesProcessed = this.decoder.nowPos64;
59
+ const isOutputComplete = (compare64(this.decoder.outSize, P0_LONG_LIT) >= 0)
60
+ && (compare64(this.decoder.nowPos64, this.decoder.outSize) >= 0);
61
+ if (result || isOutputComplete) {
62
+ this.decoder.flush();
63
+ this.decoder.cleanup();
64
+ this.alive = 0;
65
+ }
66
+ return this.alive;
67
+ }
68
+ }
@@ -0,0 +1,80 @@
1
+ import { LzOutWindow } from "./lz-window.js";
2
+ import { RangeDecoder } from "./range-decoder.js";
3
+ import type { BaseStream, BufferWithCount } from "./streams.js";
4
+ import { type BitTree } from "./utils.js";
5
+ interface LenDecoder {
6
+ choice: number[];
7
+ lowCoder: BitTree[];
8
+ midCoder: BitTree[];
9
+ highCoder: BitTree;
10
+ numPosStates: number;
11
+ }
12
+ interface LiteralCoder {
13
+ coders: any[];
14
+ numPrevBits: number;
15
+ numPosBits: number;
16
+ posMask: number;
17
+ init?(): void;
18
+ }
19
+ export declare class Decoder {
20
+ rangeDecoder: RangeDecoder;
21
+ outWindow: LzOutWindow;
22
+ state: number;
23
+ rep0: number;
24
+ rep1: number;
25
+ rep2: number;
26
+ rep3: number;
27
+ prevByte: number;
28
+ nowPos64: [number, number];
29
+ outSize: [number, number];
30
+ posStateMask: number;
31
+ dictSizeCheck: number;
32
+ matchDecoders: number[];
33
+ rep0LongDecoders: number[];
34
+ repDecoders: number[];
35
+ repG0Decoders: number[];
36
+ repG1Decoders: number[];
37
+ repG2Decoders: number[];
38
+ posDecoders: number[];
39
+ literalDecoder: LiteralCoder;
40
+ posSlotDecoders: BitTree[];
41
+ lenDecoder: LenDecoder;
42
+ repLenDecoder: LenDecoder;
43
+ posAlignDecoder: BitTree;
44
+ get literalCoder(): LiteralCoder;
45
+ decoder: Decoder;
46
+ encoder: null;
47
+ alive: number;
48
+ inBytesProcessed: [number, number];
49
+ constructor();
50
+ createLenDecoder(): LenDecoder;
51
+ setDecoderProperties(properties: number[]): boolean;
52
+ copyBlock(len: number): void;
53
+ putByte(b: number): void;
54
+ getByte(distance: number): number;
55
+ getDecoder(pos: number, prevByte: number): any;
56
+ initLiteralDecoder(): void;
57
+ init(): void;
58
+ initLenDecoder(decoder: LenDecoder): void;
59
+ outWindowReleaseStream(): void;
60
+ decodeBit(probs: number[], index: number): 0 | 1;
61
+ decodeDirectBits(numTotalBits: number): number;
62
+ initRangeDecoder(): void;
63
+ rangeBitTreeDecoder(bitTree: BitTree): number;
64
+ reverseDecode(models: number[], startIndex: number, numBitLevels: number): number;
65
+ reverseDecodeAlignDecoder(): number;
66
+ decodeNormalWithRangeDecoder(decoder: any): number;
67
+ decodeWithMatchByteWithRangeDecoder(encoder: any, matchByte: number): number;
68
+ decodeLenWithRangeDecoder(decoder: LenDecoder, posState: number): number;
69
+ codeOneChunk(): 0 | 1 | -1;
70
+ setupForDecoding(inStream: BaseStream, outSize: [number, number], outputBuffer: BufferWithCount): void;
71
+ processChunk(): number;
72
+ writeToOutput(buffer: BufferWithCount, data: number[], offset: number, length: number): void;
73
+ private isBufferWithCount;
74
+ flush(): void;
75
+ /**
76
+ * Cleanup decoder resources
77
+ */
78
+ cleanup(): void;
79
+ }
80
+ export {};
package/lib/decoder.js ADDED
@@ -0,0 +1,469 @@
1
+ import { LzOutWindow } from "./lz-window.js";
2
+ import { RangeDecoder } from "./range-decoder.js";
3
+ import { add64, CHOICE_ARRAY_SIZE, compare64, createBitTree, DEFAULT_WINDOW_SIZE, getLenToPosState, initArray, initBitModels, LITERAL_DECODER_SIZE, lowBits64, MATCH_DECODERS_SIZE, POS_DECODERS_SIZE, REP_DECODERS_SIZE, stateUpdateChar, } from "./utils.js";
4
+ export class Decoder {
5
+ rangeDecoder;
6
+ outWindow;
7
+ // Decoder state
8
+ state = 0;
9
+ rep0 = 0;
10
+ rep1 = 0;
11
+ rep2 = 0;
12
+ rep3 = 0;
13
+ prevByte = 0;
14
+ nowPos64 = [0, 0];
15
+ outSize = [0, 0];
16
+ // Decoder configuration
17
+ posStateMask = 0;
18
+ dictSizeCheck = 0;
19
+ // Probability models for different symbols
20
+ matchDecoders = [];
21
+ rep0LongDecoders = [];
22
+ repDecoders = [];
23
+ repG0Decoders = [];
24
+ repG1Decoders = [];
25
+ repG2Decoders = [];
26
+ posDecoders = [];
27
+ // Complex decoders
28
+ literalDecoder;
29
+ posSlotDecoders = [];
30
+ lenDecoder;
31
+ repLenDecoder;
32
+ posAlignDecoder;
33
+ // Alias for compatibility with LZMA class
34
+ get literalCoder() {
35
+ return this.literalDecoder;
36
+ }
37
+ // Chunker properties for compatibility
38
+ decoder;
39
+ encoder = null;
40
+ alive = 0;
41
+ inBytesProcessed = [0, 0];
42
+ constructor() {
43
+ // Initialize range decoder
44
+ this.rangeDecoder = new RangeDecoder();
45
+ // Initialize output window using proper LzOutWindow
46
+ this.outWindow = new LzOutWindow(null, DEFAULT_WINDOW_SIZE);
47
+ // Initialize probability models
48
+ this.matchDecoders = initArray(MATCH_DECODERS_SIZE);
49
+ this.rep0LongDecoders = initArray(MATCH_DECODERS_SIZE);
50
+ this.repDecoders = initArray(REP_DECODERS_SIZE);
51
+ this.repG0Decoders = initArray(REP_DECODERS_SIZE);
52
+ this.repG1Decoders = initArray(REP_DECODERS_SIZE);
53
+ this.repG2Decoders = initArray(REP_DECODERS_SIZE);
54
+ this.posDecoders = initArray(POS_DECODERS_SIZE);
55
+ // Initialize literal decoder
56
+ this.literalDecoder = {
57
+ coders: [],
58
+ numPrevBits: 0,
59
+ numPosBits: 0,
60
+ posMask: 0,
61
+ init: () => this.initLiteralDecoder(),
62
+ };
63
+ // Initialize position slot decoders (4 different length-to-position states)
64
+ for (let i = 0; i < 4; i++) {
65
+ this.posSlotDecoders[i] = createBitTree(6);
66
+ }
67
+ // Initialize length decoders
68
+ this.lenDecoder = this.createLenDecoder();
69
+ this.repLenDecoder = this.createLenDecoder();
70
+ // Initialize position alignment decoder
71
+ this.posAlignDecoder = createBitTree(4);
72
+ // Initialize self-reference for chunker compatibility
73
+ this.decoder = this;
74
+ }
75
+ createLenDecoder() {
76
+ const decoder = {
77
+ choice: initArray(CHOICE_ARRAY_SIZE),
78
+ lowCoder: [],
79
+ midCoder: [],
80
+ highCoder: createBitTree(0x08),
81
+ numPosStates: 0,
82
+ };
83
+ return decoder;
84
+ }
85
+ setDecoderProperties(properties) {
86
+ if (properties.length < 5) {
87
+ return false;
88
+ }
89
+ const lc = properties[0] % 9;
90
+ const remainder = Math.floor(properties[0] / 9);
91
+ const lp = remainder % 5;
92
+ const pb = Math.floor(remainder / 5);
93
+ if (pb > 4) {
94
+ return false;
95
+ }
96
+ // Set literal decoder properties
97
+ this.literalDecoder.numPrevBits = lc;
98
+ this.literalDecoder.numPosBits = lp;
99
+ this.literalDecoder.posMask = (1 << lp) - 1;
100
+ // Set position state mask
101
+ this.posStateMask = (1 << pb) - 1;
102
+ // Calculate dictionary size from properties[1-4]
103
+ let dictSize = 0;
104
+ for (let i = 0; i < 4; i++) {
105
+ // Treat bytes as unsigned (0-255) instead of signed (-128 to 127)
106
+ const unsignedByte = properties[1 + i] & 0xFF;
107
+ dictSize += unsignedByte << (i * 8);
108
+ }
109
+ // Set dictionary size and check value
110
+ this.dictSizeCheck = Math.max(dictSize, 1);
111
+ // Initialize output window
112
+ if (dictSize > 0) {
113
+ this.outWindow.windowSize = Math.max(dictSize, 4096);
114
+ this.outWindow.buffer = initArray(this.outWindow.windowSize);
115
+ }
116
+ // Initialize literal decoder coders
117
+ const numStates = 1 << (this.literalDecoder.numPrevBits + this.literalDecoder.numPosBits);
118
+ this.literalDecoder.coders = [];
119
+ for (let i = 0; i < numStates; i++) {
120
+ this.literalDecoder.coders[i] = {
121
+ decoders: initArray(LITERAL_DECODER_SIZE), // 0x300
122
+ };
123
+ }
124
+ // Initialize length decoders
125
+ this.lenDecoder.numPosStates = 1 << pb;
126
+ this.repLenDecoder.numPosStates = 1 << pb;
127
+ // Initialize low and mid coders for length decoders
128
+ this.lenDecoder.lowCoder = [];
129
+ this.lenDecoder.midCoder = [];
130
+ this.repLenDecoder.lowCoder = [];
131
+ this.repLenDecoder.midCoder = [];
132
+ for (let posState = 0; posState < (1 << pb); posState++) {
133
+ this.lenDecoder.lowCoder[posState] = createBitTree(3);
134
+ this.lenDecoder.midCoder[posState] = createBitTree(3);
135
+ this.repLenDecoder.lowCoder[posState] = createBitTree(3);
136
+ this.repLenDecoder.midCoder[posState] = createBitTree(3);
137
+ }
138
+ return true;
139
+ }
140
+ // Methods that modify decoder state
141
+ copyBlock(len) {
142
+ const outputWindow = this.outWindow;
143
+ const distance = this.rep0;
144
+ let pos = outputWindow.pos - distance - 1;
145
+ if (pos < 0) {
146
+ pos += outputWindow.windowSize;
147
+ }
148
+ for (; len != 0; len -= 1) {
149
+ if (pos >= outputWindow.windowSize) {
150
+ pos = 0;
151
+ }
152
+ outputWindow.buffer[outputWindow.pos] = outputWindow.buffer[pos];
153
+ outputWindow.pos += 1;
154
+ pos += 1;
155
+ if (outputWindow.pos >= outputWindow.windowSize) {
156
+ this.flush();
157
+ }
158
+ }
159
+ }
160
+ putByte(b) {
161
+ this.outWindow.buffer[this.outWindow.pos] = b;
162
+ this.outWindow.pos += 1;
163
+ if (this.outWindow.pos >= this.outWindow.windowSize) {
164
+ this.flush();
165
+ }
166
+ }
167
+ getByte(distance) {
168
+ const outputWindow = this.outWindow;
169
+ let pos = outputWindow.pos - distance - 1;
170
+ if (pos < 0) {
171
+ pos += outputWindow.windowSize;
172
+ }
173
+ return outputWindow.buffer[pos];
174
+ }
175
+ getDecoder(pos, prevByte) {
176
+ // Calculate index based on position and previous byte
177
+ const positionMask = pos & this.literalDecoder.posMask;
178
+ const prevBitsMask = (prevByte & 0xFF) >>> (8 - this.literalDecoder.numPrevBits);
179
+ const index = (positionMask << this.literalDecoder.numPrevBits) + prevBitsMask;
180
+ // Return decoder at calculated index
181
+ return this.literalDecoder.coders[index];
182
+ }
183
+ initLiteralDecoder() {
184
+ let numStates = 1 << (this.literalDecoder.numPrevBits + this.literalDecoder.numPosBits);
185
+ for (let i = 0; i < numStates; ++i) {
186
+ // Initialize bit models for each coder
187
+ for (let j = 0; j < this.literalDecoder.coders[i].decoders.length; j++) {
188
+ this.literalDecoder.coders[i].decoders[j] = 1024;
189
+ }
190
+ }
191
+ }
192
+ init() {
193
+ this.outWindow.streamPos = 0;
194
+ this.outWindow.pos = 0;
195
+ initBitModels(this.matchDecoders);
196
+ initBitModels(this.rep0LongDecoders);
197
+ initBitModels(this.repDecoders);
198
+ initBitModels(this.repG0Decoders);
199
+ initBitModels(this.repG1Decoders);
200
+ initBitModels(this.repG2Decoders);
201
+ initBitModels(this.posDecoders);
202
+ this.initLiteralDecoder();
203
+ for (let i = 0; i < 4; ++i) {
204
+ initBitModels(this.posSlotDecoders[i].models);
205
+ }
206
+ this.initLenDecoder(this.lenDecoder);
207
+ this.initLenDecoder(this.repLenDecoder);
208
+ initBitModels(this.posAlignDecoder.models);
209
+ this.initRangeDecoder();
210
+ }
211
+ initLenDecoder(decoder) {
212
+ initBitModels(decoder.choice);
213
+ for (let posState = 0; posState < decoder.numPosStates; ++posState) {
214
+ initBitModels(decoder.lowCoder[posState].models);
215
+ initBitModels(decoder.midCoder[posState].models);
216
+ }
217
+ initBitModels(decoder.highCoder.models);
218
+ }
219
+ outWindowReleaseStream() {
220
+ this.flush();
221
+ this.outWindow.stream = null;
222
+ }
223
+ decodeBit(probs, index) {
224
+ return this.rangeDecoder.decodeBit(probs, index);
225
+ }
226
+ decodeDirectBits(numTotalBits) {
227
+ return this.rangeDecoder.decodeDirectBits(numTotalBits);
228
+ }
229
+ initRangeDecoder() {
230
+ this.rangeDecoder.init();
231
+ }
232
+ rangeBitTreeDecoder(bitTree) {
233
+ let bitIndex, m = 1;
234
+ for (bitIndex = bitTree.numBitLevels; bitIndex != 0; bitIndex -= 1) {
235
+ m = (m << 1) + this.decodeBit(bitTree.models, m);
236
+ }
237
+ return m - (1 << bitTree.numBitLevels);
238
+ }
239
+ reverseDecode(models, startIndex, numBitLevels) {
240
+ let symbol = 0;
241
+ for (let bitIndex = 0, m = 1, bit; bitIndex < numBitLevels; ++bitIndex) {
242
+ bit = this.decodeBit(models, startIndex + m);
243
+ m <<= 1;
244
+ m += bit;
245
+ symbol |= bit << bitIndex;
246
+ }
247
+ return symbol;
248
+ }
249
+ reverseDecodeAlignDecoder() {
250
+ let symbol = 0;
251
+ for (let m = 1, bitIndex = 0, bit; bitIndex < this.posAlignDecoder.numBitLevels; ++bitIndex) {
252
+ bit = this.decodeBit(this.posAlignDecoder.models, m);
253
+ m <<= 1;
254
+ m += bit;
255
+ symbol |= bit << bitIndex;
256
+ }
257
+ return symbol;
258
+ }
259
+ // Update the placeholder implementations with actual logic
260
+ decodeNormalWithRangeDecoder(decoder) {
261
+ let symbol = 1;
262
+ do {
263
+ symbol = symbol << 1 | this.decodeBit(decoder.decoders, symbol);
264
+ } while (symbol < 0x100);
265
+ return symbol << 24 >> 24;
266
+ }
267
+ decodeWithMatchByteWithRangeDecoder(encoder, matchByte) {
268
+ let bit, matchBit, symbol = 1;
269
+ do {
270
+ matchBit = (matchByte >> 7) & 1;
271
+ matchByte <<= 1;
272
+ bit = this.decodeBit(encoder.decoders, ((1 + matchBit) << 8) + symbol);
273
+ symbol = symbol << 1 | bit;
274
+ if (matchBit != bit) {
275
+ while (symbol < 0x100) {
276
+ symbol = symbol << 1 | this.decodeBit(encoder.decoders, symbol);
277
+ }
278
+ break;
279
+ }
280
+ } while (symbol < 0x100);
281
+ return symbol << 24 >> 24;
282
+ }
283
+ decodeLenWithRangeDecoder(decoder, posState) {
284
+ if (!this.decodeBit(decoder.choice, 0)) {
285
+ return this.rangeBitTreeDecoder(decoder.lowCoder[posState]);
286
+ }
287
+ let symbol = 0x08;
288
+ if (!this.decodeBit(decoder.choice, 1)) {
289
+ symbol += this.rangeBitTreeDecoder(decoder.midCoder[posState]);
290
+ }
291
+ else {
292
+ symbol += 0x08 + this.rangeBitTreeDecoder(decoder.highCoder);
293
+ }
294
+ return symbol;
295
+ }
296
+ codeOneChunk() {
297
+ let decoder2, distance, len, numDirectBits, positionSlot;
298
+ let posState = lowBits64(this.nowPos64) & this.posStateMask;
299
+ if (!this.decodeBit(this.matchDecoders, (this.state << 4) + posState)) {
300
+ decoder2 = this.getDecoder(lowBits64(this.nowPos64), this.prevByte);
301
+ if (this.state < 7) {
302
+ this.prevByte = this.decodeNormalWithRangeDecoder(decoder2);
303
+ }
304
+ else {
305
+ this.prevByte = this.decodeWithMatchByteWithRangeDecoder(decoder2, this.getByte(this.rep0));
306
+ }
307
+ this.putByte(this.prevByte);
308
+ this.state = stateUpdateChar(this.state);
309
+ this.nowPos64 = add64(this.nowPos64, [1, 0]);
310
+ }
311
+ else {
312
+ if (this.decodeBit(this.repDecoders, this.state)) {
313
+ len = 0;
314
+ if (!this.decodeBit(this.repG0Decoders, this.state)) {
315
+ if (!this.decodeBit(this.rep0LongDecoders, (this.state << 4) + posState)) {
316
+ this.state = this.state < 7 ? 9 : 11;
317
+ len = 1;
318
+ }
319
+ }
320
+ else {
321
+ if (!this.decodeBit(this.repG1Decoders, this.state)) {
322
+ distance = this.rep1;
323
+ }
324
+ else {
325
+ if (!this.decodeBit(this.repG2Decoders, this.state)) {
326
+ distance = this.rep2;
327
+ }
328
+ else {
329
+ distance = this.rep3;
330
+ this.rep3 = this.rep2;
331
+ }
332
+ this.rep2 = this.rep1;
333
+ }
334
+ this.rep1 = this.rep0;
335
+ this.rep0 = distance;
336
+ }
337
+ if (!len) {
338
+ len = this.decodeLenWithRangeDecoder(this.repLenDecoder, posState) + 2;
339
+ this.state = this.state < 7 ? 0x08 : 11;
340
+ }
341
+ }
342
+ else {
343
+ this.rep3 = this.rep2;
344
+ this.rep2 = this.rep1;
345
+ this.rep1 = this.rep0;
346
+ len = 2 + this.decodeLenWithRangeDecoder(this.lenDecoder, posState);
347
+ this.state = this.state < 7 ? 7 : 10;
348
+ positionSlot = this.rangeBitTreeDecoder(this.posSlotDecoders[getLenToPosState(len)]);
349
+ if (positionSlot >= 4) {
350
+ numDirectBits = (positionSlot >> 1) - 1;
351
+ this.rep0 = (2 | (positionSlot & 1)) << numDirectBits;
352
+ if (positionSlot < 14) {
353
+ this.rep0 += this.reverseDecode(this.posDecoders, this.rep0 - positionSlot - 1, numDirectBits);
354
+ }
355
+ else {
356
+ this.rep0 += this.decodeDirectBits(numDirectBits - 4) << 4;
357
+ this.rep0 += this.reverseDecodeAlignDecoder();
358
+ if (this.rep0 < 0) {
359
+ if (this.rep0 == -1) {
360
+ return 1;
361
+ }
362
+ return -1;
363
+ }
364
+ }
365
+ }
366
+ else {
367
+ this.rep0 = positionSlot;
368
+ }
369
+ }
370
+ if (compare64([this.rep0, 0], this.nowPos64) >= 0 || this.rep0 >= this.dictSizeCheck) {
371
+ return -1;
372
+ }
373
+ this.copyBlock(len);
374
+ this.nowPos64 = add64(this.nowPos64, [len, 0]);
375
+ this.prevByte = this.getByte(0);
376
+ }
377
+ return 0;
378
+ }
379
+ // Setup decoder for chunk processing
380
+ setupForDecoding(inStream, outSize, outputBuffer) {
381
+ this.rangeDecoder.setStream(inStream);
382
+ this.outSize = outSize;
383
+ this.outWindowReleaseStream();
384
+ this.outWindow.stream = outputBuffer;
385
+ this.init();
386
+ this.state = 0;
387
+ this.rep0 = 0;
388
+ this.rep1 = 0;
389
+ this.rep2 = 0;
390
+ this.rep3 = 0;
391
+ this.outSize = outSize;
392
+ this.nowPos64 = [0, 0];
393
+ this.prevByte = 0;
394
+ this.decoder = this;
395
+ this.encoder = null;
396
+ this.alive = 1;
397
+ }
398
+ // Process chunk and return alive status
399
+ processChunk() {
400
+ if (!this.alive) {
401
+ throw new Error("Bad state");
402
+ }
403
+ if (this.encoder) {
404
+ throw new Error("No encoding");
405
+ }
406
+ const result = this.codeOneChunk();
407
+ if (result === -1) {
408
+ throw new Error("Corrupted input");
409
+ }
410
+ const isOutputComplete = (compare64(this.outSize, [0, 0]) >= 0)
411
+ && (compare64(this.nowPos64, this.outSize) >= 0);
412
+ if (result || isOutputComplete) {
413
+ this.flush();
414
+ this.outWindowReleaseStream();
415
+ this.rangeDecoder.setStream(null);
416
+ this.alive = 0;
417
+ }
418
+ return this.alive;
419
+ }
420
+ writeToOutput(buffer, data, offset, length) {
421
+ // Ensure buffer has enough capacity
422
+ const requiredSize = buffer.count + length;
423
+ if (requiredSize > buffer.buf.length) {
424
+ const newSize = Math.max(buffer.buf.length * 2, requiredSize);
425
+ const newBuf = new Array(newSize);
426
+ for (let i = 0; i < buffer.count; i++) {
427
+ newBuf[i] = buffer.buf[i];
428
+ }
429
+ buffer.buf = newBuf;
430
+ }
431
+ // Copy data
432
+ for (let i = 0; i < length; i++) {
433
+ buffer.buf[buffer.count + i] = data[offset + i];
434
+ }
435
+ buffer.count += length;
436
+ }
437
+ isBufferWithCount(x) {
438
+ const s = x;
439
+ return !!s && Array.isArray(s.buf) && typeof s.count === "number" && typeof s.write === "function";
440
+ }
441
+ flush() {
442
+ const size = this.outWindow.pos - this.outWindow.streamPos;
443
+ if (!size) {
444
+ return;
445
+ }
446
+ if (this.outWindow.stream && this.outWindow.buffer) {
447
+ const outputBuffer = this.outWindow.stream;
448
+ if (this.isBufferWithCount(outputBuffer)) {
449
+ this.writeToOutput(outputBuffer, this.outWindow.buffer, this.outWindow.streamPos, size);
450
+ }
451
+ else if (typeof outputBuffer.write === "function") {
452
+ // Fallback: write directly if it's a plain Writer
453
+ const slice = this.outWindow.buffer.slice(this.outWindow.streamPos, this.outWindow.streamPos + size);
454
+ outputBuffer.write(slice);
455
+ }
456
+ }
457
+ if (this.outWindow.pos >= this.outWindow.windowSize) {
458
+ this.outWindow.pos = 0;
459
+ }
460
+ this.outWindow.streamPos = this.outWindow.pos;
461
+ }
462
+ /**
463
+ * Cleanup decoder resources
464
+ */
465
+ cleanup() {
466
+ this.outWindow.stream = null;
467
+ this.rangeDecoder.stream = null;
468
+ }
469
+ }