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 +9 -3
- package/lib/chunker.d.ts +46 -0
- package/lib/chunker.js +68 -0
- package/lib/decoder.d.ts +80 -0
- package/lib/decoder.js +469 -0
- package/lib/encoder.d.ts +266 -0
- package/lib/encoder.js +822 -0
- package/lib/index.d.ts +33 -1
- package/lib/index.js +51 -1
- package/lib/len-coder.d.ts +70 -0
- package/lib/len-coder.js +171 -0
- package/lib/lit-coder.d.ts +63 -0
- package/lib/lit-coder.js +162 -0
- package/lib/lz-in-window.d.ts +43 -0
- package/lib/lz-in-window.js +132 -0
- package/lib/lz-window.d.ts +35 -0
- package/lib/lz-window.js +89 -0
- package/lib/lzma.d.ts +93 -98
- package/lib/lzma.js +445 -1652
- package/lib/match-finder-config.d.ts +34 -0
- package/lib/match-finder-config.js +63 -0
- package/lib/range-bit-tree-coder.d.ts +34 -0
- package/lib/range-bit-tree-coder.js +95 -0
- package/lib/range-decoder.d.ts +34 -0
- package/lib/range-decoder.js +98 -0
- package/lib/range-encoder.d.ts +46 -0
- package/lib/range-encoder.js +129 -0
- package/lib/streams.d.ts +32 -0
- package/lib/streams.js +1 -0
- package/lib/utils.d.ts +127 -0
- package/lib/utils.js +300 -0
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
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)
|
package/lib/chunker.d.ts
ADDED
|
@@ -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
|
+
}
|
package/lib/decoder.d.ts
ADDED
|
@@ -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
|
+
}
|