zstdify 1.1.2 → 1.3.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 +51 -2
- package/dist/bitstream/bitReaderReverse.d.ts +6 -0
- package/dist/bitstream/bitReaderReverse.js +51 -1
- package/dist/bitstream/bitReaderReverse.js.map +1 -1
- package/dist/bitstream/index.d.ts +1 -0
- package/dist/bitstream/index.js +1 -0
- package/dist/bitstream/index.js.map +1 -1
- package/dist/bitstream/reverseBitWriter.d.ts +1 -0
- package/dist/bitstream/reverseBitWriter.js +66 -0
- package/dist/bitstream/reverseBitWriter.js.map +1 -0
- package/dist/compress.js +47 -7
- package/dist/compress.js.map +1 -1
- package/dist/decode/debugTrace.d.ts +31 -0
- package/dist/decode/debugTrace.js +2 -0
- package/dist/decode/debugTrace.js.map +1 -0
- package/dist/decode/decompressFrame.d.ts +3 -1
- package/dist/decode/decompressFrame.js +153 -59
- package/dist/decode/decompressFrame.js.map +1 -1
- package/dist/decode/fusedSequences.d.ts +9 -0
- package/dist/decode/fusedSequences.js +26 -0
- package/dist/decode/fusedSequences.js.map +1 -0
- package/dist/decode/literals.js +164 -111
- package/dist/decode/literals.js.map +1 -1
- package/dist/decode/reconstruct.d.ts +33 -1
- package/dist/decode/reconstruct.js +591 -24
- package/dist/decode/reconstruct.js.map +1 -1
- package/dist/decode/sequences.d.ts +19 -7
- package/dist/decode/sequences.js +225 -133
- package/dist/decode/sequences.js.map +1 -1
- package/dist/decompress.d.ts +10 -0
- package/dist/decompress.js +5 -3
- package/dist/decompress.js.map +1 -1
- package/dist/encode/blockWriter.js +8 -2
- package/dist/encode/blockWriter.js.map +1 -1
- package/dist/encode/compressedBlock.d.ts +27 -1
- package/dist/encode/compressedBlock.js +594 -339
- package/dist/encode/compressedBlock.js.map +1 -1
- package/dist/encode/fastMatcher.d.ts +7 -0
- package/dist/encode/fastMatcher.js +13 -0
- package/dist/encode/fastMatcher.js.map +1 -0
- package/dist/encode/greedySequences.d.ts +9 -6
- package/dist/encode/greedySequences.js +21 -77
- package/dist/encode/greedySequences.js.map +1 -1
- package/dist/encode/lazyMatcher.d.ts +7 -0
- package/dist/encode/lazyMatcher.js +13 -0
- package/dist/encode/lazyMatcher.js.map +1 -0
- package/dist/encode/literalsEncoder.d.ts +14 -0
- package/dist/encode/literalsEncoder.js +343 -0
- package/dist/encode/literalsEncoder.js.map +1 -0
- package/dist/encode/optimalParser.d.ts +7 -0
- package/dist/encode/optimalParser.js +13 -0
- package/dist/encode/optimalParser.js.map +1 -0
- package/dist/encode/sequencePlanner.d.ts +23 -0
- package/dist/encode/sequencePlanner.js +280 -0
- package/dist/encode/sequencePlanner.js.map +1 -0
- package/dist/entropy/fse.d.ts +13 -6
- package/dist/entropy/fse.js +176 -13
- package/dist/entropy/fse.js.map +1 -1
- package/dist/entropy/huffman.d.ts +7 -5
- package/dist/entropy/huffman.js +18 -7
- package/dist/entropy/huffman.js.map +1 -1
- package/dist/entropy/index.d.ts +2 -2
- package/dist/entropy/weights.js +20 -14
- package/dist/entropy/weights.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,26 +2,208 @@
|
|
|
2
2
|
* Sequence execution: copy literals + match copies with window.
|
|
3
3
|
*/
|
|
4
4
|
import { ZstdError } from '../errors.js';
|
|
5
|
+
const FAST_LITERAL_COPY_LOOP_THRESHOLD = 8;
|
|
6
|
+
const FAST_SMALL_OFFSET_LOOP_THRESHOLD = 16;
|
|
7
|
+
const FAST_HISTORY_COPY_LOOP_THRESHOLD = 16;
|
|
8
|
+
function isHistoryWindow(value) {
|
|
9
|
+
return (typeof value.length === 'number' &&
|
|
10
|
+
typeof value.writePos === 'number' &&
|
|
11
|
+
value.buffer instanceof Uint8Array);
|
|
12
|
+
}
|
|
13
|
+
export function createHistoryWindow(windowSize, initial) {
|
|
14
|
+
const initialLength = initial?.length ?? 0;
|
|
15
|
+
const capacity = Math.max(windowSize, initialLength);
|
|
16
|
+
if (capacity <= 0) {
|
|
17
|
+
return { buffer: new Uint8Array(0), length: 0, writePos: 0 };
|
|
18
|
+
}
|
|
19
|
+
const buffer = new Uint8Array(capacity);
|
|
20
|
+
const history = { buffer, length: 0, writePos: 0 };
|
|
21
|
+
if (initialLength > 0 && initial) {
|
|
22
|
+
appendToHistoryWindow(history, initial);
|
|
23
|
+
}
|
|
24
|
+
return history;
|
|
25
|
+
}
|
|
26
|
+
function createPackedSequences(capacity) {
|
|
27
|
+
return {
|
|
28
|
+
literalsLength: new Uint32Array(capacity),
|
|
29
|
+
offset: new Uint32Array(capacity),
|
|
30
|
+
matchLength: new Uint32Array(capacity),
|
|
31
|
+
length: 0,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function ensurePackedSequencesCapacity(existing, minLength) {
|
|
35
|
+
if (existing && existing.literalsLength.length >= minLength) {
|
|
36
|
+
existing.length = minLength;
|
|
37
|
+
return existing;
|
|
38
|
+
}
|
|
39
|
+
let capacity = existing?.literalsLength.length ?? 0;
|
|
40
|
+
if (capacity === 0) {
|
|
41
|
+
capacity = 16;
|
|
42
|
+
}
|
|
43
|
+
while (capacity < minLength) {
|
|
44
|
+
capacity *= 2;
|
|
45
|
+
}
|
|
46
|
+
return createPackedSequences(capacity);
|
|
47
|
+
}
|
|
48
|
+
export function packSequences(sequences, reuse) {
|
|
49
|
+
const packed = ensurePackedSequencesCapacity(reuse, sequences.length);
|
|
50
|
+
for (let i = 0; i < sequences.length; i++) {
|
|
51
|
+
const seq = sequences[i];
|
|
52
|
+
if (!seq) {
|
|
53
|
+
throw new ZstdError('Invalid sequence object', 'corruption_detected');
|
|
54
|
+
}
|
|
55
|
+
packed.literalsLength[i] = seq.literalsLength;
|
|
56
|
+
packed.offset[i] = seq.offset;
|
|
57
|
+
packed.matchLength[i] = seq.matchLength;
|
|
58
|
+
}
|
|
59
|
+
packed.length = sequences.length;
|
|
60
|
+
return packed;
|
|
61
|
+
}
|
|
62
|
+
export function packedSequencesToArray(sequences) {
|
|
63
|
+
const out = new Array(sequences.length);
|
|
64
|
+
for (let i = 0; i < sequences.length; i++) {
|
|
65
|
+
out[i] = {
|
|
66
|
+
literalsLength: sequences.literalsLength[i] ?? 0,
|
|
67
|
+
offset: sequences.offset[i] ?? 0,
|
|
68
|
+
matchLength: sequences.matchLength[i] ?? 0,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
5
73
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
74
|
+
* Get or create a history window, reusing from bag when buffer is large enough.
|
|
75
|
+
* Caller may pass a mutable bag; it will be updated with the history used.
|
|
8
76
|
*/
|
|
9
|
-
export function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
77
|
+
export function getOrCreateHistoryWindow(windowSize, initial, reuse) {
|
|
78
|
+
const existing = reuse?._history;
|
|
79
|
+
if (existing && existing.buffer.length >= windowSize) {
|
|
80
|
+
existing.length = 0;
|
|
81
|
+
existing.writePos = 0;
|
|
82
|
+
if (initial && initial.length > 0) {
|
|
83
|
+
appendToHistoryWindow(existing, initial);
|
|
84
|
+
}
|
|
85
|
+
return existing;
|
|
86
|
+
}
|
|
87
|
+
const history = createHistoryWindow(windowSize, initial);
|
|
88
|
+
if (reuse) {
|
|
89
|
+
reuse._history = history;
|
|
90
|
+
}
|
|
91
|
+
return history;
|
|
92
|
+
}
|
|
93
|
+
export function appendToHistoryWindow(history, chunk) {
|
|
94
|
+
const cap = history.buffer.length;
|
|
95
|
+
if (cap === 0 || chunk.length === 0) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (chunk.length >= cap) {
|
|
99
|
+
const tail = chunk.subarray(chunk.length - cap);
|
|
100
|
+
history.buffer.set(tail, 0);
|
|
101
|
+
history.length = cap;
|
|
102
|
+
history.writePos = 0;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const firstLen = Math.min(chunk.length, cap - history.writePos);
|
|
106
|
+
history.buffer.set(chunk.subarray(0, firstLen), history.writePos);
|
|
107
|
+
const remaining = chunk.length - firstLen;
|
|
108
|
+
if (remaining > 0) {
|
|
109
|
+
history.buffer.set(chunk.subarray(firstLen), 0);
|
|
110
|
+
}
|
|
111
|
+
history.writePos = (history.writePos + chunk.length) % cap;
|
|
112
|
+
history.length = Math.min(cap, history.length + chunk.length);
|
|
113
|
+
}
|
|
114
|
+
const APPEND_RANGE_LOOP_THRESHOLD = 16;
|
|
115
|
+
export function appendRangeToHistoryWindow(history, source, start, length) {
|
|
116
|
+
const cap = history.buffer.length;
|
|
117
|
+
if (cap === 0 || length <= 0) {
|
|
118
|
+
return;
|
|
16
119
|
}
|
|
17
|
-
|
|
120
|
+
if (start < 0 || length < 0 || start + length > source.length) {
|
|
121
|
+
throw new RangeError('Invalid source range for history append');
|
|
122
|
+
}
|
|
123
|
+
if (length >= cap) {
|
|
124
|
+
const tailStart = start + length - cap;
|
|
125
|
+
history.buffer.set(source.subarray(tailStart, start + length), 0);
|
|
126
|
+
history.length = cap;
|
|
127
|
+
history.writePos = 0;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const firstLen = Math.min(length, cap - history.writePos);
|
|
131
|
+
const remaining = length - firstLen;
|
|
132
|
+
if (length <= APPEND_RANGE_LOOP_THRESHOLD) {
|
|
133
|
+
let wp = history.writePos;
|
|
134
|
+
for (let i = 0; i < length; i++) {
|
|
135
|
+
history.buffer[wp] = source[start + i];
|
|
136
|
+
wp = wp + 1 === cap ? 0 : wp + 1;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
history.buffer.set(source.subarray(start, start + firstLen), history.writePos);
|
|
141
|
+
if (remaining > 0) {
|
|
142
|
+
history.buffer.set(source.subarray(start + firstLen, start + firstLen + remaining), 0);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
history.writePos = (history.writePos + length) % cap;
|
|
146
|
+
history.length = Math.min(cap, history.length + length);
|
|
147
|
+
}
|
|
148
|
+
export function appendRLEToHistoryWindow(history, byte, length) {
|
|
149
|
+
const cap = history.buffer.length;
|
|
150
|
+
if (cap === 0 || length <= 0) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const fillByte = byte & 0xff;
|
|
154
|
+
if (length >= cap) {
|
|
155
|
+
history.buffer.fill(fillByte, 0, cap);
|
|
156
|
+
history.length = cap;
|
|
157
|
+
history.writePos = 0;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const firstLen = Math.min(length, cap - history.writePos);
|
|
161
|
+
history.buffer.fill(fillByte, history.writePos, history.writePos + firstLen);
|
|
162
|
+
const remaining = length - firstLen;
|
|
163
|
+
if (remaining > 0) {
|
|
164
|
+
history.buffer.fill(fillByte, 0, remaining);
|
|
165
|
+
}
|
|
166
|
+
history.writePos = (history.writePos + length) % cap;
|
|
167
|
+
history.length = Math.min(cap, history.length + length);
|
|
168
|
+
}
|
|
169
|
+
export function executeSequencesInto(literals, sequences, windowSize, target, targetOffset, repOffsets = [1, 4, 8], historyInput = { buffer: new Uint8Array(0), length: 0, writePos: 0 }, updateHistory = false) {
|
|
170
|
+
const history = isHistoryWindow(historyInput) ? historyInput : createHistoryWindow(windowSize, historyInput);
|
|
171
|
+
const historyLength = history.length;
|
|
172
|
+
const historyCap = history.buffer.length;
|
|
173
|
+
const historyOldestPos = historyCap > 0 ? (history.writePos - historyLength + historyCap) % historyCap : 0;
|
|
174
|
+
const historyBuffer = history.buffer;
|
|
175
|
+
let outPos = targetOffset;
|
|
18
176
|
let litPos = 0;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
177
|
+
const LIT_COPY_LOOP_THRESHOLD = 16;
|
|
178
|
+
const HISTORY_COPY_LOOP_THRESHOLD = 16;
|
|
179
|
+
const seqCount = sequences.length;
|
|
180
|
+
const literalsLengthBySeq = sequences.literalsLength;
|
|
181
|
+
const offsetBySeq = sequences.offset;
|
|
182
|
+
const matchLengthBySeq = sequences.matchLength;
|
|
183
|
+
for (let seqIndex = 0; seqIndex < seqCount; seqIndex++) {
|
|
184
|
+
const seqLiteralsLength = literalsLengthBySeq[seqIndex];
|
|
185
|
+
if (seqLiteralsLength > 0) {
|
|
186
|
+
const litOutStart = outPos;
|
|
187
|
+
const litEnd = litPos + seqLiteralsLength;
|
|
188
|
+
if (litEnd > literals.length) {
|
|
189
|
+
throw new ZstdError('Literals overrun while executing sequence', 'corruption_detected');
|
|
190
|
+
}
|
|
191
|
+
if (seqLiteralsLength <= LIT_COPY_LOOP_THRESHOLD) {
|
|
192
|
+
for (let i = 0; i < seqLiteralsLength; i++) {
|
|
193
|
+
target[outPos + i] = literals[litPos + i];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
target.set(literals.subarray(litPos, litEnd), outPos);
|
|
198
|
+
}
|
|
199
|
+
outPos += seqLiteralsLength;
|
|
200
|
+
litPos = litEnd;
|
|
201
|
+
if (updateHistory) {
|
|
202
|
+
appendRangeToHistoryWindow(history, target, litOutStart, seqLiteralsLength);
|
|
203
|
+
}
|
|
22
204
|
}
|
|
23
|
-
const ov =
|
|
24
|
-
const ll0 =
|
|
205
|
+
const ov = offsetBySeq[seqIndex]; // Offset_Value from sequence decode.
|
|
206
|
+
const ll0 = seqLiteralsLength === 0;
|
|
25
207
|
let offset;
|
|
26
208
|
let repeatIndex = null;
|
|
27
209
|
const isNonRepeat = ov > 3 || (ov === 3 && ll0);
|
|
@@ -43,16 +225,74 @@ export function executeSequences(literals, sequences, windowSize, repOffsets = [
|
|
|
43
225
|
else {
|
|
44
226
|
repeatIndex = (ov - 1);
|
|
45
227
|
}
|
|
46
|
-
offset = repOffsets[repeatIndex]
|
|
228
|
+
offset = repOffsets[repeatIndex];
|
|
47
229
|
}
|
|
48
|
-
const produced = outPos -
|
|
49
|
-
const maxReachBack =
|
|
230
|
+
const produced = outPos - targetOffset;
|
|
231
|
+
const maxReachBack = Math.min(windowSize, produced + historyLength);
|
|
50
232
|
if (offset <= 0 || offset > maxReachBack) {
|
|
51
233
|
throw new ZstdError(`Invalid match offset: offset=${offset} maxReachBack=${maxReachBack} produced=${produced} history=${historyLength} window=${windowSize}`, 'corruption_detected');
|
|
52
234
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
235
|
+
let remainingMatch = matchLengthBySeq[seqIndex];
|
|
236
|
+
const historyBytesNeeded = Math.max(0, offset - produced);
|
|
237
|
+
if (historyBytesNeeded > 0) {
|
|
238
|
+
if (historyCap === 0) {
|
|
239
|
+
throw new ZstdError('Invalid history read', 'corruption_detected');
|
|
240
|
+
}
|
|
241
|
+
const historyCopyLen = Math.min(historyBytesNeeded, remainingMatch);
|
|
242
|
+
const historyStart = historyLength - historyBytesNeeded;
|
|
243
|
+
if (historyStart < 0 || historyStart + historyCopyLen > historyLength) {
|
|
244
|
+
throw new ZstdError('Invalid history read', 'corruption_detected');
|
|
245
|
+
}
|
|
246
|
+
let physicalStart = historyOldestPos + historyStart;
|
|
247
|
+
if (physicalStart >= historyCap) {
|
|
248
|
+
physicalStart -= historyCap;
|
|
249
|
+
}
|
|
250
|
+
const firstHistoryChunk = Math.min(historyCopyLen, historyCap - physicalStart);
|
|
251
|
+
const remainingHistoryChunk = historyCopyLen - firstHistoryChunk;
|
|
252
|
+
const historyOutStart = outPos;
|
|
253
|
+
if (historyCopyLen <= HISTORY_COPY_LOOP_THRESHOLD) {
|
|
254
|
+
let phys = physicalStart;
|
|
255
|
+
for (let i = 0; i < historyCopyLen; i++) {
|
|
256
|
+
target[outPos + i] = historyBuffer[phys];
|
|
257
|
+
phys = phys + 1 === historyCap ? 0 : phys + 1;
|
|
258
|
+
}
|
|
259
|
+
outPos += historyCopyLen;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
target.set(historyBuffer.subarray(physicalStart, physicalStart + firstHistoryChunk), outPos);
|
|
263
|
+
outPos += firstHistoryChunk;
|
|
264
|
+
if (remainingHistoryChunk > 0) {
|
|
265
|
+
target.set(historyBuffer.subarray(0, remainingHistoryChunk), outPos);
|
|
266
|
+
outPos += remainingHistoryChunk;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (updateHistory) {
|
|
270
|
+
appendRangeToHistoryWindow(history, target, historyOutStart, historyCopyLen);
|
|
271
|
+
}
|
|
272
|
+
remainingMatch -= historyCopyLen;
|
|
273
|
+
}
|
|
274
|
+
if (remainingMatch > 0) {
|
|
275
|
+
const matchOutStart = outPos;
|
|
276
|
+
const copyStart = outPos - offset;
|
|
277
|
+
if (offset >= remainingMatch) {
|
|
278
|
+
target.copyWithin(outPos, copyStart, copyStart + remainingMatch);
|
|
279
|
+
outPos += remainingMatch;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// Handle overlapping copies with exponentially growing chunks.
|
|
283
|
+
let copied = offset;
|
|
284
|
+
target.copyWithin(outPos, copyStart, copyStart + copied);
|
|
285
|
+
outPos += copied;
|
|
286
|
+
while (copied < remainingMatch) {
|
|
287
|
+
const toCopy = Math.min(copied, remainingMatch - copied);
|
|
288
|
+
target.copyWithin(outPos, outPos - copied, outPos - copied + toCopy);
|
|
289
|
+
outPos += toCopy;
|
|
290
|
+
copied += toCopy;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (updateHistory) {
|
|
294
|
+
appendRangeToHistoryWindow(history, target, matchOutStart, remainingMatch);
|
|
295
|
+
}
|
|
56
296
|
}
|
|
57
297
|
if (isNonRepeat) {
|
|
58
298
|
repOffsets[2] = repOffsets[1];
|
|
@@ -72,9 +312,336 @@ export function executeSequences(literals, sequences, windowSize, repOffsets = [
|
|
|
72
312
|
}
|
|
73
313
|
}
|
|
74
314
|
}
|
|
75
|
-
|
|
76
|
-
|
|
315
|
+
if (litPos < literals.length) {
|
|
316
|
+
const tailOutStart = outPos;
|
|
317
|
+
const remaining = literals.length - litPos;
|
|
318
|
+
if (remaining <= LIT_COPY_LOOP_THRESHOLD) {
|
|
319
|
+
for (let i = 0; i < remaining; i++) {
|
|
320
|
+
target[outPos + i] = literals[litPos + i];
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
target.set(literals.subarray(litPos), outPos);
|
|
325
|
+
}
|
|
326
|
+
outPos += remaining;
|
|
327
|
+
if (updateHistory) {
|
|
328
|
+
appendRangeToHistoryWindow(history, target, tailOutStart, remaining);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return outPos - targetOffset;
|
|
332
|
+
}
|
|
333
|
+
export function executeSequencesIntoFast(literals, sequences, windowSize, target, targetOffset, repOffsets = [1, 4, 8], historyInput = { buffer: new Uint8Array(0), length: 0, writePos: 0 }, updateHistory = false) {
|
|
334
|
+
const history = isHistoryWindow(historyInput) ? historyInput : createHistoryWindow(windowSize, historyInput);
|
|
335
|
+
if (history.length === 0) {
|
|
336
|
+
return executeSequencesIntoFastNoHistory(literals, sequences, windowSize, target, targetOffset, repOffsets, history, updateHistory);
|
|
337
|
+
}
|
|
338
|
+
const historyLength = history.length;
|
|
339
|
+
const historyCap = history.buffer.length;
|
|
340
|
+
const historyOldestPos = historyCap > 0 ? (history.writePos - historyLength + historyCap) % historyCap : 0;
|
|
341
|
+
const historyBuffer = history.buffer;
|
|
342
|
+
let outPos = targetOffset;
|
|
343
|
+
let litPos = 0;
|
|
344
|
+
const seqCount = sequences.length;
|
|
345
|
+
const literalsLengthBySeq = sequences.literalsLength;
|
|
346
|
+
const offsetBySeq = sequences.offset;
|
|
347
|
+
const matchLengthBySeq = sequences.matchLength;
|
|
348
|
+
for (let seqIndex = 0; seqIndex < seqCount; seqIndex++) {
|
|
349
|
+
const seqLiteralsLength = literalsLengthBySeq[seqIndex];
|
|
350
|
+
if (seqLiteralsLength > 0) {
|
|
351
|
+
const litEnd = litPos + seqLiteralsLength;
|
|
352
|
+
if (litEnd > literals.length) {
|
|
353
|
+
throw new ZstdError('Literals overrun while executing sequence', 'corruption_detected');
|
|
354
|
+
}
|
|
355
|
+
if (seqLiteralsLength <= FAST_LITERAL_COPY_LOOP_THRESHOLD) {
|
|
356
|
+
for (let i = 0; i < seqLiteralsLength; i++) {
|
|
357
|
+
target[outPos + i] = literals[litPos + i];
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
target.set(literals.subarray(litPos, litEnd), outPos);
|
|
362
|
+
}
|
|
363
|
+
outPos += seqLiteralsLength;
|
|
364
|
+
litPos = litEnd;
|
|
365
|
+
}
|
|
366
|
+
const ov = offsetBySeq[seqIndex];
|
|
367
|
+
const ll0 = seqLiteralsLength === 0;
|
|
368
|
+
let offset;
|
|
369
|
+
let repeatIndex = null;
|
|
370
|
+
const isNonRepeat = ov > 3 || (ov === 3 && ll0);
|
|
371
|
+
if (isNonRepeat) {
|
|
372
|
+
if (ov === 3) {
|
|
373
|
+
offset = repOffsets[0] - 1;
|
|
374
|
+
if (offset === 0) {
|
|
375
|
+
throw new ZstdError('Invalid match offset: repeat1-1 is 0', 'corruption_detected');
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
offset = ov - 3;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
if (ll0) {
|
|
384
|
+
repeatIndex = ov === 1 ? 1 : 2;
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
repeatIndex = (ov - 1);
|
|
388
|
+
}
|
|
389
|
+
offset = repOffsets[repeatIndex];
|
|
390
|
+
}
|
|
391
|
+
const produced = outPos - targetOffset;
|
|
392
|
+
const producedPlusHistory = produced + historyLength;
|
|
393
|
+
const maxReachBack = producedPlusHistory < windowSize ? producedPlusHistory : windowSize;
|
|
394
|
+
if (offset <= 0 || offset > maxReachBack) {
|
|
395
|
+
throw new ZstdError(`Invalid match offset: offset=${offset} maxReachBack=${maxReachBack} produced=${produced} history=${historyLength} window=${windowSize}`, 'corruption_detected');
|
|
396
|
+
}
|
|
397
|
+
const remainingMatch = matchLengthBySeq[seqIndex];
|
|
398
|
+
const historyBytesNeeded = offset > produced ? offset - produced : 0;
|
|
399
|
+
if (remainingMatch > 0) {
|
|
400
|
+
if (historyBytesNeeded === 0) {
|
|
401
|
+
const copyStart = outPos - offset;
|
|
402
|
+
if (offset >= remainingMatch) {
|
|
403
|
+
target.copyWithin(outPos, copyStart, copyStart + remainingMatch);
|
|
404
|
+
outPos += remainingMatch;
|
|
405
|
+
}
|
|
406
|
+
else if (offset <= FAST_SMALL_OFFSET_LOOP_THRESHOLD) {
|
|
407
|
+
for (let i = 0; i < remainingMatch; i++) {
|
|
408
|
+
target[outPos + i] = target[outPos - offset + i];
|
|
409
|
+
}
|
|
410
|
+
outPos += remainingMatch;
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
let copied = offset;
|
|
414
|
+
target.copyWithin(outPos, copyStart, copyStart + copied);
|
|
415
|
+
outPos += copied;
|
|
416
|
+
while (copied < remainingMatch) {
|
|
417
|
+
const toCopy = Math.min(copied, remainingMatch - copied);
|
|
418
|
+
target.copyWithin(outPos, outPos - copied, outPos - copied + toCopy);
|
|
419
|
+
outPos += toCopy;
|
|
420
|
+
copied += toCopy;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
outPos = copyMatchWithHistorySlowPath(target, outPos, offset, remainingMatch, historyBytesNeeded, historyLength, historyCap, historyOldestPos, historyBuffer);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (isNonRepeat) {
|
|
429
|
+
repOffsets[2] = repOffsets[1];
|
|
430
|
+
repOffsets[1] = repOffsets[0];
|
|
431
|
+
repOffsets[0] = offset;
|
|
432
|
+
}
|
|
433
|
+
else if (repeatIndex === 1) {
|
|
434
|
+
repOffsets[1] = repOffsets[0];
|
|
435
|
+
repOffsets[0] = offset;
|
|
436
|
+
}
|
|
437
|
+
else if (repeatIndex === 2) {
|
|
438
|
+
repOffsets[2] = repOffsets[1];
|
|
439
|
+
repOffsets[1] = repOffsets[0];
|
|
440
|
+
repOffsets[0] = offset;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (litPos < literals.length) {
|
|
444
|
+
const remaining = literals.length - litPos;
|
|
445
|
+
if (remaining <= FAST_LITERAL_COPY_LOOP_THRESHOLD) {
|
|
446
|
+
for (let i = 0; i < remaining; i++) {
|
|
447
|
+
target[outPos + i] = literals[litPos + i];
|
|
448
|
+
}
|
|
449
|
+
outPos += remaining;
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
target.set(literals.subarray(litPos), outPos);
|
|
453
|
+
outPos += remaining;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (updateHistory && outPos > targetOffset) {
|
|
457
|
+
appendRangeToHistoryWindow(history, target, targetOffset, outPos - targetOffset);
|
|
458
|
+
}
|
|
459
|
+
return outPos - targetOffset;
|
|
460
|
+
}
|
|
461
|
+
function executeSequencesIntoFastNoHistory(literals, sequences, windowSize, target, targetOffset, repOffsets, history, updateHistory) {
|
|
462
|
+
let outPos = targetOffset;
|
|
463
|
+
let litPos = 0;
|
|
464
|
+
const seqCount = sequences.length;
|
|
465
|
+
const literalsLengthBySeq = sequences.literalsLength;
|
|
466
|
+
const offsetBySeq = sequences.offset;
|
|
467
|
+
const matchLengthBySeq = sequences.matchLength;
|
|
468
|
+
for (let seqIndex = 0; seqIndex < seqCount; seqIndex++) {
|
|
469
|
+
const seqLiteralsLength = literalsLengthBySeq[seqIndex];
|
|
470
|
+
if (seqLiteralsLength > 0) {
|
|
471
|
+
const litEnd = litPos + seqLiteralsLength;
|
|
472
|
+
if (litEnd > literals.length) {
|
|
473
|
+
throw new ZstdError('Literals overrun while executing sequence', 'corruption_detected');
|
|
474
|
+
}
|
|
475
|
+
if (seqLiteralsLength <= FAST_LITERAL_COPY_LOOP_THRESHOLD) {
|
|
476
|
+
for (let i = 0; i < seqLiteralsLength; i++) {
|
|
477
|
+
target[outPos + i] = literals[litPos + i];
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
target.set(literals.subarray(litPos, litEnd), outPos);
|
|
482
|
+
}
|
|
483
|
+
outPos += seqLiteralsLength;
|
|
484
|
+
litPos = litEnd;
|
|
485
|
+
}
|
|
486
|
+
const ov = offsetBySeq[seqIndex];
|
|
487
|
+
const ll0 = seqLiteralsLength === 0;
|
|
488
|
+
let offset;
|
|
489
|
+
let repeatIndex = null;
|
|
490
|
+
const isNonRepeat = ov > 3 || (ov === 3 && ll0);
|
|
491
|
+
if (isNonRepeat) {
|
|
492
|
+
if (ov === 3) {
|
|
493
|
+
offset = repOffsets[0] - 1;
|
|
494
|
+
if (offset === 0) {
|
|
495
|
+
throw new ZstdError('Invalid match offset: repeat1-1 is 0', 'corruption_detected');
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
offset = ov - 3;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
if (ll0) {
|
|
504
|
+
repeatIndex = ov === 1 ? 1 : 2;
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
repeatIndex = (ov - 1);
|
|
508
|
+
}
|
|
509
|
+
offset = repOffsets[repeatIndex];
|
|
510
|
+
}
|
|
511
|
+
const produced = outPos - targetOffset;
|
|
512
|
+
const maxReachBack = produced < windowSize ? produced : windowSize;
|
|
513
|
+
if (offset <= 0 || offset > maxReachBack) {
|
|
514
|
+
throw new ZstdError(`Invalid match offset: offset=${offset} maxReachBack=${maxReachBack} produced=${produced} history=0 window=${windowSize}`, 'corruption_detected');
|
|
515
|
+
}
|
|
516
|
+
const remainingMatch = matchLengthBySeq[seqIndex];
|
|
517
|
+
if (remainingMatch > 0) {
|
|
518
|
+
const copyStart = outPos - offset;
|
|
519
|
+
if (offset >= remainingMatch) {
|
|
520
|
+
target.copyWithin(outPos, copyStart, copyStart + remainingMatch);
|
|
521
|
+
outPos += remainingMatch;
|
|
522
|
+
}
|
|
523
|
+
else if (offset <= FAST_SMALL_OFFSET_LOOP_THRESHOLD) {
|
|
524
|
+
for (let i = 0; i < remainingMatch; i++) {
|
|
525
|
+
target[outPos + i] = target[outPos - offset + i];
|
|
526
|
+
}
|
|
527
|
+
outPos += remainingMatch;
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
let copied = offset;
|
|
531
|
+
target.copyWithin(outPos, copyStart, copyStart + copied);
|
|
532
|
+
outPos += copied;
|
|
533
|
+
while (copied < remainingMatch) {
|
|
534
|
+
const toCopy = Math.min(copied, remainingMatch - copied);
|
|
535
|
+
target.copyWithin(outPos, outPos - copied, outPos - copied + toCopy);
|
|
536
|
+
outPos += toCopy;
|
|
537
|
+
copied += toCopy;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (isNonRepeat) {
|
|
542
|
+
repOffsets[2] = repOffsets[1];
|
|
543
|
+
repOffsets[1] = repOffsets[0];
|
|
544
|
+
repOffsets[0] = offset;
|
|
545
|
+
}
|
|
546
|
+
else if (repeatIndex === 1) {
|
|
547
|
+
repOffsets[1] = repOffsets[0];
|
|
548
|
+
repOffsets[0] = offset;
|
|
549
|
+
}
|
|
550
|
+
else if (repeatIndex === 2) {
|
|
551
|
+
repOffsets[2] = repOffsets[1];
|
|
552
|
+
repOffsets[1] = repOffsets[0];
|
|
553
|
+
repOffsets[0] = offset;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (litPos < literals.length) {
|
|
557
|
+
const remaining = literals.length - litPos;
|
|
558
|
+
if (remaining <= FAST_LITERAL_COPY_LOOP_THRESHOLD) {
|
|
559
|
+
for (let i = 0; i < remaining; i++) {
|
|
560
|
+
target[outPos + i] = literals[litPos + i];
|
|
561
|
+
}
|
|
562
|
+
outPos += remaining;
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
target.set(literals.subarray(litPos), outPos);
|
|
566
|
+
outPos += remaining;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (updateHistory && outPos > targetOffset) {
|
|
570
|
+
appendRangeToHistoryWindow(history, target, targetOffset, outPos - targetOffset);
|
|
571
|
+
}
|
|
572
|
+
return outPos - targetOffset;
|
|
573
|
+
}
|
|
574
|
+
function copyMatchWithHistorySlowPath(target, outPos, offset, remainingMatch, historyBytesNeeded, historyLength, historyCap, historyOldestPos, historyBuffer) {
|
|
575
|
+
if (historyCap === 0) {
|
|
576
|
+
throw new ZstdError('Invalid history read', 'corruption_detected');
|
|
577
|
+
}
|
|
578
|
+
const historyCopyLen = Math.min(historyBytesNeeded, remainingMatch);
|
|
579
|
+
const historyStart = historyLength - historyBytesNeeded;
|
|
580
|
+
if (historyStart < 0 || historyStart + historyCopyLen > historyLength) {
|
|
581
|
+
throw new ZstdError('Invalid history read', 'corruption_detected');
|
|
582
|
+
}
|
|
583
|
+
let physicalStart = historyOldestPos + historyStart;
|
|
584
|
+
if (physicalStart >= historyCap) {
|
|
585
|
+
physicalStart -= historyCap;
|
|
586
|
+
}
|
|
587
|
+
const firstHistoryChunk = Math.min(historyCopyLen, historyCap - physicalStart);
|
|
588
|
+
const remainingHistoryChunk = historyCopyLen - firstHistoryChunk;
|
|
589
|
+
if (historyCopyLen <= FAST_HISTORY_COPY_LOOP_THRESHOLD) {
|
|
590
|
+
let phys = physicalStart;
|
|
591
|
+
for (let i = 0; i < historyCopyLen; i++) {
|
|
592
|
+
target[outPos + i] = historyBuffer[phys];
|
|
593
|
+
phys = phys + 1 === historyCap ? 0 : phys + 1;
|
|
594
|
+
}
|
|
595
|
+
outPos += historyCopyLen;
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
target.set(historyBuffer.subarray(physicalStart, physicalStart + firstHistoryChunk), outPos);
|
|
599
|
+
outPos += firstHistoryChunk;
|
|
600
|
+
if (remainingHistoryChunk > 0) {
|
|
601
|
+
target.set(historyBuffer.subarray(0, remainingHistoryChunk), outPos);
|
|
602
|
+
outPos += remainingHistoryChunk;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
const matchRemaining = remainingMatch - historyCopyLen;
|
|
606
|
+
if (matchRemaining <= 0) {
|
|
607
|
+
return outPos;
|
|
608
|
+
}
|
|
609
|
+
const copyStart = outPos - offset;
|
|
610
|
+
if (offset >= matchRemaining) {
|
|
611
|
+
target.copyWithin(outPos, copyStart, copyStart + matchRemaining);
|
|
612
|
+
return outPos + matchRemaining;
|
|
613
|
+
}
|
|
614
|
+
if (offset <= FAST_SMALL_OFFSET_LOOP_THRESHOLD) {
|
|
615
|
+
for (let i = 0; i < matchRemaining; i++) {
|
|
616
|
+
target[outPos + i] = target[outPos - offset + i];
|
|
617
|
+
}
|
|
618
|
+
return outPos + matchRemaining;
|
|
619
|
+
}
|
|
620
|
+
let copied = offset;
|
|
621
|
+
target.copyWithin(outPos, copyStart, copyStart + copied);
|
|
622
|
+
outPos += copied;
|
|
623
|
+
while (copied < matchRemaining) {
|
|
624
|
+
const toCopy = Math.min(copied, matchRemaining - copied);
|
|
625
|
+
target.copyWithin(outPos, outPos - copied, outPos - copied + toCopy);
|
|
626
|
+
outPos += toCopy;
|
|
627
|
+
copied += toCopy;
|
|
628
|
+
}
|
|
629
|
+
return outPos;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Execute sequences to produce decompressed output.
|
|
633
|
+
* repOffsets: [Repeated_Offset1, Repeated_Offset2, Repeated_Offset3], updated in place.
|
|
634
|
+
*/
|
|
635
|
+
export function executeSequences(literals, sequences, windowSize, repOffsets = [1, 4, 8], historyInput = { buffer: new Uint8Array(0), length: 0, writePos: 0 }) {
|
|
636
|
+
const packed = packSequences(sequences);
|
|
637
|
+
// Sequence literals are slices of `literals`, so only matches expand output size.
|
|
638
|
+
let totalSize = literals.length;
|
|
639
|
+
for (let i = 0; i < packed.length; i++) {
|
|
640
|
+
totalSize += packed.matchLength[i];
|
|
77
641
|
}
|
|
78
|
-
|
|
642
|
+
const buffer = new Uint8Array(totalSize);
|
|
643
|
+
const outSize = executeSequencesInto(literals, packed, windowSize, buffer, 0, repOffsets, historyInput);
|
|
644
|
+
const outPos = outSize;
|
|
645
|
+
return outPos === buffer.length ? buffer : buffer.subarray(0, outPos);
|
|
79
646
|
}
|
|
80
647
|
//# sourceMappingURL=reconstruct.js.map
|