@patrickdk77/archive-defuse 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +345 -2
- package/dist/aes7z.d.ts +16 -0
- package/dist/aes7z.js +131 -0
- package/dist/alone.d.ts +21 -0
- package/dist/alone.js +65 -0
- package/dist/bcj2.d.ts +21 -0
- package/dist/bcj2.js +140 -0
- package/dist/bzip2.d.ts +21 -0
- package/dist/bzip2.js +688 -0
- package/dist/cab.d.ts +63 -0
- package/dist/cab.js +493 -0
- package/dist/checks.d.ts +23 -0
- package/dist/checks.js +123 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +364 -0
- package/dist/codecs.d.ts +39 -0
- package/dist/codecs.js +124 -0
- package/dist/coders.d.ts +58 -0
- package/dist/coders.js +392 -0
- package/dist/crc32.d.ts +8 -0
- package/dist/crc32.js +59 -0
- package/dist/encoder.d.ts +44 -0
- package/dist/encoder.js +114 -0
- package/dist/engine.d.ts +44 -0
- package/dist/engine.js +753 -0
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +98 -0
- package/dist/filters.d.ts +34 -0
- package/dist/filters.js +385 -0
- package/dist/findings.d.ts +26 -0
- package/dist/findings.js +176 -0
- package/dist/formats.d.ts +14 -0
- package/dist/formats.js +97 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +50 -0
- package/dist/index.mjs +3 -0
- package/dist/inflate64.d.ts +6 -0
- package/dist/inflate64.js +388 -0
- package/dist/io.d.ts +78 -0
- package/dist/io.js +379 -0
- package/dist/lzma-formats.d.ts +75 -0
- package/dist/lzma-formats.js +373 -0
- package/dist/lzma-sniff.d.ts +20 -0
- package/dist/lzma-sniff.js +73 -0
- package/dist/lzma-writers.d.ts +35 -0
- package/dist/lzma-writers.js +276 -0
- package/dist/lzma1/LICENSE +201 -0
- package/dist/lzma1/NOTICE +36 -0
- package/dist/lzma1/crc32.d.ts +4 -0
- package/dist/lzma1/crc32.js +19 -0
- package/dist/lzma1/hash234.d.ts +22 -0
- package/dist/lzma1/hash234.js +75 -0
- package/dist/lzma1/hc4.d.ts +30 -0
- package/dist/lzma1/hc4.js +142 -0
- package/dist/lzma1/header.d.ts +32 -0
- package/dist/lzma1/header.js +73 -0
- package/dist/lzma1/lz-decoder.d.ts +41 -0
- package/dist/lzma1/lz-decoder.js +128 -0
- package/dist/lzma1/lz-encoder.d.ts +87 -0
- package/dist/lzma1/lz-encoder.js +166 -0
- package/dist/lzma1/lzma-coder.d.ts +107 -0
- package/dist/lzma1/lzma-coder.js +162 -0
- package/dist/lzma1/lzma-decoder.d.ts +36 -0
- package/dist/lzma1/lzma-decoder.js +484 -0
- package/dist/lzma1/lzma-encoder-fast.d.ts +13 -0
- package/dist/lzma1/lzma-encoder-fast.js +114 -0
- package/dist/lzma1/lzma-encoder.d.ts +105 -0
- package/dist/lzma1/lzma-encoder.js +497 -0
- package/dist/lzma1/lzma2-decoder.d.ts +85 -0
- package/dist/lzma1/lzma2-decoder.js +249 -0
- package/dist/lzma1/range-coder.d.ts +18 -0
- package/dist/lzma1/range-coder.js +23 -0
- package/dist/lzma1/range-decoder.d.ts +41 -0
- package/dist/lzma1/range-decoder.js +78 -0
- package/dist/lzma1/range-encoder.d.ts +53 -0
- package/dist/lzma1/range-encoder.js +269 -0
- package/dist/lzma1-stream.d.ts +60 -0
- package/dist/lzma1-stream.js +202 -0
- package/dist/model.d.ts +141 -0
- package/dist/model.js +16 -0
- package/dist/names.d.ts +13 -0
- package/dist/names.js +66 -0
- package/dist/pack.d.ts +72 -0
- package/dist/pack.js +514 -0
- package/dist/plugins.d.ts +13 -0
- package/dist/plugins.js +55 -0
- package/dist/rules.d.ts +25 -0
- package/dist/rules.js +403 -0
- package/dist/score.d.ts +17 -0
- package/dist/score.js +58 -0
- package/dist/seven.d.ts +75 -0
- package/dist/seven.js +492 -0
- package/dist/sevenzip.d.ts +133 -0
- package/dist/sevenzip.js +529 -0
- package/dist/single.d.ts +103 -0
- package/dist/single.js +453 -0
- package/dist/sniff.d.ts +20 -0
- package/dist/sniff.js +224 -0
- package/dist/stream-meter.d.ts +39 -0
- package/dist/stream-meter.js +54 -0
- package/dist/tar.d.ts +102 -0
- package/dist/tar.js +765 -0
- package/dist/types.d.ts +284 -0
- package/dist/types.js +133 -0
- package/dist/unpack.d.ts +67 -0
- package/dist/unpack.js +194 -0
- package/dist/xz.d.ts +25 -0
- package/dist/xz.js +333 -0
- package/dist/zip-lzma.d.ts +15 -0
- package/dist/zip-lzma.js +137 -0
- package/dist/zip-writer.d.ts +41 -0
- package/dist/zip-writer.js +263 -0
- package/dist/zip.d.ts +99 -0
- package/dist/zip.js +901 -0
- package/dist/zipcrypt.d.ts +47 -0
- package/dist/zipcrypt.js +233 -0
- package/dist/zstd.d.ts +25 -0
- package/dist/zstd.js +160 -0
- package/package.json +94 -4
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RangeEncoder = void 0;
|
|
4
|
+
exports.getBitPrice = getBitPrice;
|
|
5
|
+
exports.getBitTreePrice = getBitTreePrice;
|
|
6
|
+
exports.getReverseBitTreePrice = getReverseBitTreePrice;
|
|
7
|
+
exports.getDirectBitsPrice = getDirectBitsPrice;
|
|
8
|
+
// Copied from lzma1 (Apache-2.0, Copyright Filip Seman) and changed for lzma-defuse. NOTICE in this folder lists the changes.
|
|
9
|
+
const range_coder_1 = require("./range-coder");
|
|
10
|
+
const MOVE_REDUCING_BITS = 4;
|
|
11
|
+
const BIT_PRICE_SHIFT_BITS = 4;
|
|
12
|
+
/**
|
|
13
|
+
* Price (approximate cost in 1/16 bits) of encoding a bit with a given
|
|
14
|
+
* probability, indexed by `probability >>> MOVE_REDUCING_BITS`.
|
|
15
|
+
*/
|
|
16
|
+
const PRICES = createPriceTable();
|
|
17
|
+
function createPriceTable() {
|
|
18
|
+
const prices = new Uint32Array(range_coder_1.BIT_MODEL_TOTAL >>> MOVE_REDUCING_BITS);
|
|
19
|
+
for (let i = (1 << MOVE_REDUCING_BITS) / 2; i < range_coder_1.BIT_MODEL_TOTAL; i += 1 << MOVE_REDUCING_BITS) {
|
|
20
|
+
// Approximate -log2(i / BIT_MODEL_TOTAL) using repeated squaring.
|
|
21
|
+
let w = i;
|
|
22
|
+
let bitCount = 0;
|
|
23
|
+
for (let j = 0; j < BIT_PRICE_SHIFT_BITS; ++j) {
|
|
24
|
+
w *= w;
|
|
25
|
+
bitCount <<= 1;
|
|
26
|
+
while (w >= 0x10000) {
|
|
27
|
+
w >>>= 1;
|
|
28
|
+
++bitCount;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
prices[i >> MOVE_REDUCING_BITS] = (range_coder_1.BIT_MODEL_TOTAL_BITS << BIT_PRICE_SHIFT_BITS) - 15 - bitCount;
|
|
32
|
+
}
|
|
33
|
+
return prices;
|
|
34
|
+
}
|
|
35
|
+
function getBitPrice(prob, bit) {
|
|
36
|
+
return PRICES[(prob ^ (-bit & (range_coder_1.BIT_MODEL_TOTAL - 1))) >>> MOVE_REDUCING_BITS];
|
|
37
|
+
}
|
|
38
|
+
/** Price of a `bits`-bit symbol coded MSB-first with the bit tree at `offset`. */
|
|
39
|
+
function getBitTreePrice(probs, offset, bits, symbolIn) {
|
|
40
|
+
let symbol = symbolIn;
|
|
41
|
+
let price = 0;
|
|
42
|
+
symbol |= 1 << bits;
|
|
43
|
+
do {
|
|
44
|
+
const bit = symbol & 1;
|
|
45
|
+
symbol >>>= 1;
|
|
46
|
+
price += getBitPrice(probs[offset + symbol], bit);
|
|
47
|
+
} while (symbol !== 1);
|
|
48
|
+
return price;
|
|
49
|
+
}
|
|
50
|
+
/** Price of a `bits`-bit symbol coded LSB-first with the bit tree at `offset`. */
|
|
51
|
+
function getReverseBitTreePrice(probs, offset, bits, symbolIn) {
|
|
52
|
+
let symbol = symbolIn;
|
|
53
|
+
let price = 0;
|
|
54
|
+
let index = 1;
|
|
55
|
+
for (let i = 0; i < bits; ++i) {
|
|
56
|
+
const bit = symbol & 1;
|
|
57
|
+
symbol >>>= 1;
|
|
58
|
+
price += getBitPrice(probs[offset + index], bit);
|
|
59
|
+
index = (index << 1) | bit;
|
|
60
|
+
}
|
|
61
|
+
return price;
|
|
62
|
+
}
|
|
63
|
+
/** Price of bits coded with a fixed 50% probability. */
|
|
64
|
+
function getDirectBitsPrice(count) {
|
|
65
|
+
return count << BIT_PRICE_SHIFT_BITS;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Range encoder writing to its own growable buffer.
|
|
69
|
+
*
|
|
70
|
+
* `low` needs 33 bits (32 bits plus a carry), so it is kept as a regular
|
|
71
|
+
* number instead of an int32. Doubles represent integers up to 2^53 exactly.
|
|
72
|
+
*
|
|
73
|
+
* Performance: like `RangeDecoder`, the methods that encode several bits
|
|
74
|
+
* keep `range` and `low` in local variables for the whole symbol.
|
|
75
|
+
*/
|
|
76
|
+
class RangeEncoder {
|
|
77
|
+
low = 0;
|
|
78
|
+
range = 0xffffffff;
|
|
79
|
+
cache = 0;
|
|
80
|
+
cacheSize = 1;
|
|
81
|
+
buf;
|
|
82
|
+
size = 0;
|
|
83
|
+
constructor(initialCapacity) {
|
|
84
|
+
this.buf = new Uint8Array(Math.max(64, initialCapacity));
|
|
85
|
+
}
|
|
86
|
+
/** Appends bytes that are not range coded, e.g. a header. */
|
|
87
|
+
writeBytes(bytes) {
|
|
88
|
+
this.ensureCapacity(bytes.length);
|
|
89
|
+
this.buf.set(bytes, this.size);
|
|
90
|
+
this.size += bytes.length;
|
|
91
|
+
}
|
|
92
|
+
/** Returns a copy of the output written so far and empties the buffer. */
|
|
93
|
+
take() {
|
|
94
|
+
const bytes = this.buf.slice(0, this.size);
|
|
95
|
+
this.size = 0;
|
|
96
|
+
return bytes;
|
|
97
|
+
}
|
|
98
|
+
/** Flushes all pending bytes and returns the rest of the output. */
|
|
99
|
+
finish() {
|
|
100
|
+
let low = this.low;
|
|
101
|
+
for (let i = 0; i < 5; ++i) {
|
|
102
|
+
low = this.shiftLow(low);
|
|
103
|
+
}
|
|
104
|
+
this.low = low;
|
|
105
|
+
return this.size === this.buf.length ? this.buf : this.buf.slice(0, this.size);
|
|
106
|
+
}
|
|
107
|
+
encodeBit(probs, index, bit) {
|
|
108
|
+
const prob = probs[index];
|
|
109
|
+
const bound = (this.range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
|
|
110
|
+
if (bit === 0) {
|
|
111
|
+
this.range = bound;
|
|
112
|
+
probs[index] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
this.low += bound;
|
|
116
|
+
this.range -= bound;
|
|
117
|
+
probs[index] = prob - (prob >>> range_coder_1.MOVE_BITS);
|
|
118
|
+
}
|
|
119
|
+
if (this.range < range_coder_1.TOP_VALUE) {
|
|
120
|
+
this.range = (this.range << 8) >>> 0;
|
|
121
|
+
this.low = this.shiftLow(this.low);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Encodes a `bits`-bit symbol MSB-first with the bit tree at `offset`. */
|
|
125
|
+
encodeBitTree(probs, offset, bits, symbol) {
|
|
126
|
+
let range = this.range;
|
|
127
|
+
let low = this.low;
|
|
128
|
+
let index = 1;
|
|
129
|
+
for (let i = bits - 1; i >= 0; --i) {
|
|
130
|
+
const bit = (symbol >>> i) & 1;
|
|
131
|
+
const prob = probs[offset + index];
|
|
132
|
+
const bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
|
|
133
|
+
if (bit === 0) {
|
|
134
|
+
range = bound;
|
|
135
|
+
probs[offset + index] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
low += bound;
|
|
139
|
+
range -= bound;
|
|
140
|
+
probs[offset + index] = prob - (prob >>> range_coder_1.MOVE_BITS);
|
|
141
|
+
}
|
|
142
|
+
if (range < range_coder_1.TOP_VALUE) {
|
|
143
|
+
range = (range << 8) >>> 0;
|
|
144
|
+
low = this.shiftLow(low);
|
|
145
|
+
}
|
|
146
|
+
index = (index << 1) | bit;
|
|
147
|
+
}
|
|
148
|
+
this.range = range;
|
|
149
|
+
this.low = low;
|
|
150
|
+
}
|
|
151
|
+
/** Encodes a `bits`-bit symbol LSB-first with the bit tree at `offset`. */
|
|
152
|
+
encodeReverseBitTree(probs, offset, bits, symbolIn) {
|
|
153
|
+
let symbol = symbolIn;
|
|
154
|
+
let range = this.range;
|
|
155
|
+
let low = this.low;
|
|
156
|
+
let index = 1;
|
|
157
|
+
for (let i = 0; i < bits; ++i) {
|
|
158
|
+
const bit = symbol & 1;
|
|
159
|
+
symbol >>>= 1;
|
|
160
|
+
const prob = probs[offset + index];
|
|
161
|
+
const bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
|
|
162
|
+
if (bit === 0) {
|
|
163
|
+
range = bound;
|
|
164
|
+
probs[offset + index] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
low += bound;
|
|
168
|
+
range -= bound;
|
|
169
|
+
probs[offset + index] = prob - (prob >>> range_coder_1.MOVE_BITS);
|
|
170
|
+
}
|
|
171
|
+
if (range < range_coder_1.TOP_VALUE) {
|
|
172
|
+
range = (range << 8) >>> 0;
|
|
173
|
+
low = this.shiftLow(low);
|
|
174
|
+
}
|
|
175
|
+
index = (index << 1) | bit;
|
|
176
|
+
}
|
|
177
|
+
this.range = range;
|
|
178
|
+
this.low = low;
|
|
179
|
+
}
|
|
180
|
+
/** Encodes a literal byte with the 0x100-leaf bit tree at `offset`. */
|
|
181
|
+
encodeLiteral(probs, offset, symbol) {
|
|
182
|
+
this.encodeBitTree(probs, offset, 8, symbol);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Encodes a literal after a match. The bits of `matchByte` (the byte at
|
|
186
|
+
* rep0) select separate probabilities until the first bit that differs.
|
|
187
|
+
*/
|
|
188
|
+
encodeMatchedLiteral(probs, offset, symbolIn, matchByteIn) {
|
|
189
|
+
let symbol = symbolIn;
|
|
190
|
+
let matchByte = matchByteIn;
|
|
191
|
+
let range = this.range;
|
|
192
|
+
let low = this.low;
|
|
193
|
+
let matchOffset = 0x100;
|
|
194
|
+
symbol |= 0x100;
|
|
195
|
+
do {
|
|
196
|
+
matchByte <<= 1;
|
|
197
|
+
const matchBit = matchByte & matchOffset;
|
|
198
|
+
const index = offset + matchOffset + matchBit + (symbol >>> 8);
|
|
199
|
+
const bit = (symbol >>> 7) & 1;
|
|
200
|
+
const prob = probs[index];
|
|
201
|
+
const bound = (range >>> range_coder_1.BIT_MODEL_TOTAL_BITS) * prob;
|
|
202
|
+
if (bit === 0) {
|
|
203
|
+
range = bound;
|
|
204
|
+
probs[index] = prob + ((range_coder_1.BIT_MODEL_TOTAL - prob) >>> range_coder_1.MOVE_BITS);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
low += bound;
|
|
208
|
+
range -= bound;
|
|
209
|
+
probs[index] = prob - (prob >>> range_coder_1.MOVE_BITS);
|
|
210
|
+
}
|
|
211
|
+
if (range < range_coder_1.TOP_VALUE) {
|
|
212
|
+
range = (range << 8) >>> 0;
|
|
213
|
+
low = this.shiftLow(low);
|
|
214
|
+
}
|
|
215
|
+
symbol <<= 1;
|
|
216
|
+
matchOffset &= ~(matchByte ^ symbol);
|
|
217
|
+
} while (symbol < 0x10000);
|
|
218
|
+
this.range = range;
|
|
219
|
+
this.low = low;
|
|
220
|
+
}
|
|
221
|
+
/** Encodes the `count` low bits of `value` with a fixed 50% probability. */
|
|
222
|
+
encodeDirectBits(value, countIn) {
|
|
223
|
+
let count = countIn;
|
|
224
|
+
let range = this.range;
|
|
225
|
+
let low = this.low;
|
|
226
|
+
do {
|
|
227
|
+
range >>>= 1;
|
|
228
|
+
if (((value >>> --count) & 1) !== 0) {
|
|
229
|
+
low += range;
|
|
230
|
+
}
|
|
231
|
+
if (range < range_coder_1.TOP_VALUE) {
|
|
232
|
+
range = (range << 8) >>> 0;
|
|
233
|
+
low = this.shiftLow(low);
|
|
234
|
+
}
|
|
235
|
+
} while (count !== 0);
|
|
236
|
+
this.range = range;
|
|
237
|
+
this.low = low;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Moves the top byte of `low` to the output and returns the new `low`.
|
|
241
|
+
* A run of 0xFF bytes is held back (`cache` + `cacheSize`) until it is
|
|
242
|
+
* known whether a carry will propagate into it.
|
|
243
|
+
*/
|
|
244
|
+
shiftLow(low) {
|
|
245
|
+
if (low < 0xff000000 || low >= 0x100000000) {
|
|
246
|
+
const carry = low >= 0x100000000 ? 1 : 0;
|
|
247
|
+
this.ensureCapacity(this.cacheSize);
|
|
248
|
+
const buf = this.buf;
|
|
249
|
+
let size = this.size;
|
|
250
|
+
buf[size++] = (this.cache + carry) & 0xff;
|
|
251
|
+
for (let i = 1; i < this.cacheSize; ++i) {
|
|
252
|
+
buf[size++] = (0xff + carry) & 0xff;
|
|
253
|
+
}
|
|
254
|
+
this.size = size;
|
|
255
|
+
this.cacheSize = 0;
|
|
256
|
+
this.cache = (low >>> 24) & 0xff;
|
|
257
|
+
}
|
|
258
|
+
++this.cacheSize;
|
|
259
|
+
return (low & 0x00ffffff) * 256;
|
|
260
|
+
}
|
|
261
|
+
ensureCapacity(extra) {
|
|
262
|
+
if (this.size + extra > this.buf.length) {
|
|
263
|
+
const grown = new Uint8Array(Math.max(this.size + extra, this.buf.length * 2));
|
|
264
|
+
grown.set(this.buf.subarray(0, this.size));
|
|
265
|
+
this.buf = grown;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
exports.RangeEncoder = RangeEncoder;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface Lzma1Props {
|
|
2
|
+
lc: number;
|
|
3
|
+
lp: number;
|
|
4
|
+
pb: number;
|
|
5
|
+
dictSize: number;
|
|
6
|
+
}
|
|
7
|
+
/** Splits the properties byte of an LZMA header or 7z coder: (pb * 5 + lp) * 9 + lc. */
|
|
8
|
+
export declare function decodeProps(byte: number, dictSize: number): Lzma1Props;
|
|
9
|
+
/** The dictionary a stream allocates at most: what the properties say, but no more than the data when its size is known. */
|
|
10
|
+
export declare function effectiveDictSize(dictSize: number, size: number | undefined): number;
|
|
11
|
+
/**
|
|
12
|
+
* Decodes raw LZMA1 data that arrives in pieces, built from lzma1's decoder like its AloneDecoder, with what this
|
|
13
|
+
* package needs to judge the end of the data: where it ended, whether an end marker ended it, and what follows.
|
|
14
|
+
*
|
|
15
|
+
* With a known size, decoding stops after that many bytes. `probe` then checks what the range coder holds next: a
|
|
16
|
+
* finished coder ends the data, an end marker may follow, and anything else means the data goes on past the size.
|
|
17
|
+
* Without a known size the data must end with an end marker.
|
|
18
|
+
*/
|
|
19
|
+
export declare class Lzma1Stream {
|
|
20
|
+
private readonly lz;
|
|
21
|
+
private readonly lzma;
|
|
22
|
+
private readonly rc;
|
|
23
|
+
private readonly size;
|
|
24
|
+
private readonly probe;
|
|
25
|
+
private pending;
|
|
26
|
+
/** Input offset of pending[0]. */
|
|
27
|
+
private base;
|
|
28
|
+
private rcStarted;
|
|
29
|
+
/** Bytes decoded after the end are no longer passed on, which the end-marker probe relies on. */
|
|
30
|
+
private sealed;
|
|
31
|
+
/** Bytes after the end, the first PROBE_KEEP of them. */
|
|
32
|
+
private after;
|
|
33
|
+
/** Set once the data has ended. */
|
|
34
|
+
done: boolean;
|
|
35
|
+
/** An end marker ended the data. */
|
|
36
|
+
endMarker: boolean;
|
|
37
|
+
/** Input bytes the data took, once done. */
|
|
38
|
+
consumed: number;
|
|
39
|
+
/** Input bytes after the end of the data. */
|
|
40
|
+
trailing: number;
|
|
41
|
+
/**
|
|
42
|
+
* @param size Decoded size, or undefined when an end marker ends the data
|
|
43
|
+
* @param sink Receives decoded bytes. The chunk is only valid during the call.
|
|
44
|
+
* @param probe Look past a known size for an end marker or more data, as for an .lzma file
|
|
45
|
+
*/
|
|
46
|
+
constructor(props: Lzma1Props, size: number | undefined, sink: (chunk: Uint8Array) => void, probe: boolean);
|
|
47
|
+
/** Bytes decoded so far. */
|
|
48
|
+
get decoded(): number;
|
|
49
|
+
/** Decodes as much of `chunk` as possible. */
|
|
50
|
+
write(chunk: Uint8Array): void;
|
|
51
|
+
/** Decodes the rest. Throws when the data is incomplete or goes on past its declared size. */
|
|
52
|
+
end(): void;
|
|
53
|
+
private needsProbe;
|
|
54
|
+
private keepAfter;
|
|
55
|
+
private decode;
|
|
56
|
+
private finish;
|
|
57
|
+
/** Decodes one more symbol, which must be the end marker. */
|
|
58
|
+
private runProbe;
|
|
59
|
+
}
|
|
60
|
+
export declare function concat(a: Uint8Array, b: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Lzma1Stream = void 0;
|
|
4
|
+
exports.decodeProps = decodeProps;
|
|
5
|
+
exports.effectiveDictSize = effectiveDictSize;
|
|
6
|
+
exports.concat = concat;
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
|
+
const lz_decoder_1 = require("./lzma1/lz-decoder");
|
|
9
|
+
const lzma_decoder_1 = require("./lzma1/lzma-decoder");
|
|
10
|
+
const range_decoder_1 = require("./lzma1/range-decoder");
|
|
11
|
+
/**
|
|
12
|
+
* Upper bound of input bytes a single LZMA symbol can consume, as lzma1's alone-decoder.ts defines it. Decoding pauses
|
|
13
|
+
* while fewer are left, so a symbol never runs out of input halfway.
|
|
14
|
+
*/
|
|
15
|
+
const INPUT_MARGIN = 64;
|
|
16
|
+
const DICT_SIZE_MIN = 1 << 12;
|
|
17
|
+
/** Bytes after the end of the data kept for the end-marker probe. The marker and the range coder flush fit in 16. */
|
|
18
|
+
const PROBE_KEEP = 256;
|
|
19
|
+
/** Splits the properties byte of an LZMA header or 7z coder: (pb * 5 + lp) * 9 + lc. */
|
|
20
|
+
function decodeProps(byte, dictSize) {
|
|
21
|
+
if (byte >= 9 * 5 * 5)
|
|
22
|
+
throw new errors_1.DataError('invalid LZMA properties');
|
|
23
|
+
return { lc: byte % 9, lp: Math.floor(byte / 9) % 5, pb: Math.floor(byte / 45), dictSize };
|
|
24
|
+
}
|
|
25
|
+
/** The dictionary a stream allocates at most: what the properties say, but no more than the data when its size is known. */
|
|
26
|
+
function effectiveDictSize(dictSize, size) {
|
|
27
|
+
const d = Math.max(dictSize, DICT_SIZE_MIN);
|
|
28
|
+
return size === undefined ? d : Math.max(Math.min(d, size), 1);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Decodes raw LZMA1 data that arrives in pieces, built from lzma1's decoder like its AloneDecoder, with what this
|
|
32
|
+
* package needs to judge the end of the data: where it ended, whether an end marker ended it, and what follows.
|
|
33
|
+
*
|
|
34
|
+
* With a known size, decoding stops after that many bytes. `probe` then checks what the range coder holds next: a
|
|
35
|
+
* finished coder ends the data, an end marker may follow, and anything else means the data goes on past the size.
|
|
36
|
+
* Without a known size the data must end with an end marker.
|
|
37
|
+
*/
|
|
38
|
+
class Lzma1Stream {
|
|
39
|
+
lz;
|
|
40
|
+
lzma;
|
|
41
|
+
rc = new range_decoder_1.RangeDecoder();
|
|
42
|
+
size;
|
|
43
|
+
probe;
|
|
44
|
+
pending = new Uint8Array(0);
|
|
45
|
+
/** Input offset of pending[0]. */
|
|
46
|
+
base = 0;
|
|
47
|
+
rcStarted = false;
|
|
48
|
+
/** Bytes decoded after the end are no longer passed on, which the end-marker probe relies on. */
|
|
49
|
+
sealed = false;
|
|
50
|
+
/** Bytes after the end, the first PROBE_KEEP of them. */
|
|
51
|
+
after = new Uint8Array(0);
|
|
52
|
+
/** Set once the data has ended. */
|
|
53
|
+
done = false;
|
|
54
|
+
/** An end marker ended the data. */
|
|
55
|
+
endMarker = false;
|
|
56
|
+
/** Input bytes the data took, once done. */
|
|
57
|
+
consumed = 0;
|
|
58
|
+
/** Input bytes after the end of the data. */
|
|
59
|
+
trailing = 0;
|
|
60
|
+
/**
|
|
61
|
+
* @param size Decoded size, or undefined when an end marker ends the data
|
|
62
|
+
* @param sink Receives decoded bytes. The chunk is only valid during the call.
|
|
63
|
+
* @param probe Look past a known size for an end marker or more data, as for an .lzma file
|
|
64
|
+
*/
|
|
65
|
+
constructor(props, size, sink, probe) {
|
|
66
|
+
this.size = size;
|
|
67
|
+
this.probe = probe;
|
|
68
|
+
this.lz = new lz_decoder_1.LzDecoder(effectiveDictSize(props.dictSize, size), chunk => {
|
|
69
|
+
if (!this.sealed)
|
|
70
|
+
sink(chunk);
|
|
71
|
+
});
|
|
72
|
+
this.lzma = new lzma_decoder_1.LzmaDecoder(this.lz, this.rc, props.lc, props.lp, props.pb);
|
|
73
|
+
}
|
|
74
|
+
/** Bytes decoded so far. */
|
|
75
|
+
get decoded() {
|
|
76
|
+
return this.lzma.outPos;
|
|
77
|
+
}
|
|
78
|
+
/** Decodes as much of `chunk` as possible. */
|
|
79
|
+
write(chunk) {
|
|
80
|
+
if (this.done) {
|
|
81
|
+
this.keepAfter(chunk);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.decode(concat(this.pending, chunk), false);
|
|
85
|
+
}
|
|
86
|
+
/** Decodes the rest. Throws when the data is incomplete or goes on past its declared size. */
|
|
87
|
+
end() {
|
|
88
|
+
if (!this.done)
|
|
89
|
+
this.decode(this.pending, true);
|
|
90
|
+
if (!this.done)
|
|
91
|
+
throw new errors_1.DataError('the data ends before its end', true);
|
|
92
|
+
if (this.needsProbe)
|
|
93
|
+
this.runProbe();
|
|
94
|
+
}
|
|
95
|
+
needsProbe = false;
|
|
96
|
+
keepAfter(chunk) {
|
|
97
|
+
this.trailing += chunk.length;
|
|
98
|
+
if (this.after.length < PROBE_KEEP)
|
|
99
|
+
this.after = concat(this.after, chunk.subarray(0, PROBE_KEEP - this.after.length));
|
|
100
|
+
}
|
|
101
|
+
decode(input, isLast) {
|
|
102
|
+
const rc = this.rc;
|
|
103
|
+
if (!this.rcStarted) {
|
|
104
|
+
if (input.length < range_decoder_1.RANGE_DECODER_INIT_SIZE) {
|
|
105
|
+
// An empty stream of known size 0 may hold nothing at all.
|
|
106
|
+
if (isLast && this.size === 0 && input.length === 0) {
|
|
107
|
+
this.finish(input, 0, false);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (isLast)
|
|
111
|
+
throw new errors_1.DataError('the data ends before its end', true);
|
|
112
|
+
this.pending = input.slice();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
rc.init(input, 0);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
throw new errors_1.DataError(String(e.message).replace(/^Corrupted input: /, ''));
|
|
120
|
+
}
|
|
121
|
+
this.rcStarted = true;
|
|
122
|
+
}
|
|
123
|
+
else
|
|
124
|
+
rc.setInput(input, 0);
|
|
125
|
+
const outLimit = this.size ?? Number.POSITIVE_INFINITY;
|
|
126
|
+
const inLimit = isLast ? Number.POSITIVE_INFINITY : input.length - INPUT_MARGIN;
|
|
127
|
+
let endMarker;
|
|
128
|
+
try {
|
|
129
|
+
endMarker = this.size === 0 ? false : this.lzma.decode(outLimit, inLimit);
|
|
130
|
+
}
|
|
131
|
+
catch (e) {
|
|
132
|
+
throw asDataError(e);
|
|
133
|
+
}
|
|
134
|
+
this.lz.flush();
|
|
135
|
+
if (endMarker) {
|
|
136
|
+
if (!rc.isFinished())
|
|
137
|
+
throw new errors_1.DataError('invalid end marker');
|
|
138
|
+
this.finish(input, rc.pos, true);
|
|
139
|
+
}
|
|
140
|
+
else if (this.lzma.outPos === this.size) {
|
|
141
|
+
this.finish(input, rc.pos, false);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
this.base += rc.pos;
|
|
145
|
+
this.pending = input.slice(rc.pos);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
finish(input, pos, endMarker) {
|
|
149
|
+
this.done = true;
|
|
150
|
+
this.sealed = true;
|
|
151
|
+
this.endMarker = endMarker;
|
|
152
|
+
this.consumed = this.base + pos;
|
|
153
|
+
this.pending = new Uint8Array(0);
|
|
154
|
+
this.keepAfter(input.subarray(pos));
|
|
155
|
+
// The data ended at its size. A finished range coder ends it cleanly; otherwise an end marker or more data follows.
|
|
156
|
+
this.needsProbe = !endMarker && this.probe && this.rcStarted && !this.rc.isFinished();
|
|
157
|
+
}
|
|
158
|
+
/** Decodes one more symbol, which must be the end marker. */
|
|
159
|
+
runProbe() {
|
|
160
|
+
this.needsProbe = false;
|
|
161
|
+
const rc = this.rc;
|
|
162
|
+
const after = this.after;
|
|
163
|
+
rc.setInput(after, 0);
|
|
164
|
+
let marker = false;
|
|
165
|
+
try {
|
|
166
|
+
marker = this.lzma.decode((this.size ?? 0) + 1, Number.POSITIVE_INFINITY);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
marker = false;
|
|
170
|
+
}
|
|
171
|
+
if (!marker || !rc.isFinished())
|
|
172
|
+
throw new errors_1.DataError('the data goes on past its declared size');
|
|
173
|
+
this.endMarker = true;
|
|
174
|
+
this.consumed += rc.pos;
|
|
175
|
+
this.trailing -= rc.pos;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
exports.Lzma1Stream = Lzma1Stream;
|
|
179
|
+
/** The decoder's errors as data errors, with lzma1's prefix taken off. */
|
|
180
|
+
function asDataError(e) {
|
|
181
|
+
if (e instanceof errors_1.DataError)
|
|
182
|
+
return e;
|
|
183
|
+
const message = String(e?.message ?? e);
|
|
184
|
+
if (message === 'Truncated input')
|
|
185
|
+
return new errors_1.DataError('the data ends before its end', true);
|
|
186
|
+
if (/declared size/.test(message))
|
|
187
|
+
return new errors_1.DataError('the data goes on past its declared size');
|
|
188
|
+
// An error from the sink, such as a limit, is not about the data.
|
|
189
|
+
if (!/^Corrupted input/.test(message))
|
|
190
|
+
throw e;
|
|
191
|
+
return new errors_1.DataError(message.replace(/^Corrupted input: /, ''));
|
|
192
|
+
}
|
|
193
|
+
function concat(a, b) {
|
|
194
|
+
if (a.length === 0)
|
|
195
|
+
return b;
|
|
196
|
+
if (b.length === 0)
|
|
197
|
+
return a;
|
|
198
|
+
const out = new Uint8Array(a.length + b.length);
|
|
199
|
+
out.set(a);
|
|
200
|
+
out.set(b, a.length);
|
|
201
|
+
return out;
|
|
202
|
+
}
|
package/dist/model.d.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { SpillSink, TempDir } from './io';
|
|
2
|
+
import type { ArchiveCategory, ArchiveDetail, ArchiveFormat, ByteSink } from './types';
|
|
3
|
+
/** Something a reader saw, which the engine turns into a finding. */
|
|
4
|
+
export interface Note {
|
|
5
|
+
category: ArchiveCategory;
|
|
6
|
+
detail: ArchiveDetail;
|
|
7
|
+
data?: Record<string, string | number>;
|
|
8
|
+
location?: string;
|
|
9
|
+
/** The rewrite keeps what the note reports when its rule is info, so an info override removes nothing. */
|
|
10
|
+
keptOnInfo?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export type EntryKind = 'file' | 'directory' | 'symlink' | 'hardlink' | 'device' | 'fifo' | 'socket' | 'other';
|
|
13
|
+
export type Encryption = {
|
|
14
|
+
kind: 'zipcrypto';
|
|
15
|
+
} | {
|
|
16
|
+
kind: 'aes';
|
|
17
|
+
bits: 128 | 192 | 256;
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'unsupported';
|
|
20
|
+
reason: string;
|
|
21
|
+
};
|
|
22
|
+
/** How an entry's bytes are compressed, as far as the engine needs to know. */
|
|
23
|
+
export interface Method {
|
|
24
|
+
/** The format's own name or number for it, for findings. */
|
|
25
|
+
name: string;
|
|
26
|
+
/** False when this package has no decoder for it. */
|
|
27
|
+
readable: boolean;
|
|
28
|
+
/** Readable, but few readers handle it. */
|
|
29
|
+
unusual: boolean;
|
|
30
|
+
/** Readable by this package, but not on the running Node. */
|
|
31
|
+
unavailable?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** One entry of an archive, as every format reader describes it. */
|
|
34
|
+
export interface Entry {
|
|
35
|
+
/** Position in the archive's own order. */
|
|
36
|
+
index: number;
|
|
37
|
+
/** The name as the format gives it, decoded, before any rule fixes it. Folders end in "/". */
|
|
38
|
+
name: string;
|
|
39
|
+
kind: EntryKind;
|
|
40
|
+
/** Permission bits, including setuid and setgid, when the format records them. */
|
|
41
|
+
mode?: number;
|
|
42
|
+
/** A link's target. A ZIP stores a symbolic link's target as its content, which the engine reads before the rules run. */
|
|
43
|
+
linkTarget?: string;
|
|
44
|
+
/** For an entry of a type no rule names, the format's code for it. */
|
|
45
|
+
typeCode?: string;
|
|
46
|
+
/** Decompressed size the headers declare. */
|
|
47
|
+
size: number;
|
|
48
|
+
/** Bytes the entry's data takes in the archive. */
|
|
49
|
+
compressedSize: number;
|
|
50
|
+
encryption?: Encryption;
|
|
51
|
+
method?: Method;
|
|
52
|
+
/** Why the entry's data cannot be read, when the headers already show it. The entry is removed. */
|
|
53
|
+
broken?: string;
|
|
54
|
+
/** Findings about this entry's headers. */
|
|
55
|
+
notes: Note[];
|
|
56
|
+
/** Extended attributes that grant capabilities, by name. */
|
|
57
|
+
capabilities?: string[];
|
|
58
|
+
/** The entry's comment, when the format has one. */
|
|
59
|
+
comment?: string;
|
|
60
|
+
/** A 7z anti-item, which tells an updater to delete the file of that name. */
|
|
61
|
+
anti?: boolean;
|
|
62
|
+
}
|
|
63
|
+
/** What the engine decided about one entry, for the writer. */
|
|
64
|
+
export interface Kept<E extends Entry> {
|
|
65
|
+
entry: E;
|
|
66
|
+
/** The name to write, after the rules fixed it. */
|
|
67
|
+
name: string;
|
|
68
|
+
/** Permission bits to write. */
|
|
69
|
+
mode?: number;
|
|
70
|
+
/** A hard link's target as written, after the rules fixed the target's name. */
|
|
71
|
+
linkTarget?: string;
|
|
72
|
+
/** Bytes a plugin wrote in place of the entry's own. */
|
|
73
|
+
replacement?: SpillSink;
|
|
74
|
+
/** Compress the entry again with the format's common method instead of copying its compressed bytes. */
|
|
75
|
+
recompress: boolean;
|
|
76
|
+
/** The password that opened the entry. */
|
|
77
|
+
password?: string;
|
|
78
|
+
/** CRC-32 of the entry's decoded content, known once the engine has read it. */
|
|
79
|
+
crc?: number;
|
|
80
|
+
/** Drop the extended attributes that grant capabilities. */
|
|
81
|
+
dropCapabilities: boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface WritePlan<E extends Entry> {
|
|
84
|
+
kept: Kept<E>[];
|
|
85
|
+
stripMetadata: boolean;
|
|
86
|
+
/** Write data found before the archive ahead of the rewritten one. */
|
|
87
|
+
keepLeading: boolean;
|
|
88
|
+
/** Write data found after the archive after the rewritten one. */
|
|
89
|
+
keepTrailing: boolean;
|
|
90
|
+
/** Keep header fields the rewrite would otherwise drop, such as unknown ZIP extra fields. */
|
|
91
|
+
keepExtraFields: boolean;
|
|
92
|
+
/** The ratio limit of the run. A writer stores data that compresses past it, so its output reads under the same limit. */
|
|
93
|
+
ratioLimit: number;
|
|
94
|
+
}
|
|
95
|
+
/** Counts the bytes one entry decodes to against the limits, and checks the deadline. */
|
|
96
|
+
export interface Meter {
|
|
97
|
+
/** Adds decoded bytes, with the compressed bytes read so far when the reader knows them. */
|
|
98
|
+
add(decoded: number, compressedSoFar?: number): void;
|
|
99
|
+
/** Throws once the deadline has passed. */
|
|
100
|
+
time(): void;
|
|
101
|
+
}
|
|
102
|
+
/** What a writer needs from the run. */
|
|
103
|
+
export interface WriteContext {
|
|
104
|
+
/** A meter that checks the deadline while the writer decodes entries again. */
|
|
105
|
+
meter(): Meter;
|
|
106
|
+
/** The run's temporary directory, for data a writer compresses before it knows the size. */
|
|
107
|
+
temp: TempDir;
|
|
108
|
+
/** Bytes a writer keeps in memory before it spills to a temporary file. */
|
|
109
|
+
threshold: number;
|
|
110
|
+
}
|
|
111
|
+
/** An archive opened for reading, with what the engine needs to inspect it and write it again. */
|
|
112
|
+
export interface Archive<E extends Entry = Entry> {
|
|
113
|
+
format: ArchiveFormat;
|
|
114
|
+
entries: E[];
|
|
115
|
+
/** True for gzip, bzip2, zstd and brotli, which hold one file. */
|
|
116
|
+
single: boolean;
|
|
117
|
+
/** True when the format stores no names for the entries, as a 7z archive without a names property can. */
|
|
118
|
+
nameless?: boolean;
|
|
119
|
+
/** Findings about the archive as a whole, known once it is open. */
|
|
120
|
+
notes: Note[];
|
|
121
|
+
/** Findings about the archive found while its single entry was read, such as the members of a gzip file. */
|
|
122
|
+
lateNotes: Note[];
|
|
123
|
+
/** The archive's own comment. */
|
|
124
|
+
comment?: string;
|
|
125
|
+
/** True when the archive holds metadata that stripMetadata removes: comments, owners, times or attributes. */
|
|
126
|
+
hasMetadata(): boolean;
|
|
127
|
+
/** True when `password` opens the encrypted entry. Only readers with encrypted entries are asked. */
|
|
128
|
+
unlock(e: E, password: string): Promise<boolean>;
|
|
129
|
+
/** A symbolic link's target, for a format that keeps it as the link's content. */
|
|
130
|
+
linkTarget?(e: E, meter: Meter): Promise<string | undefined>;
|
|
131
|
+
/** The entry's content, decrypted and decompressed, checked against its size and checksum as it goes. */
|
|
132
|
+
read(e: E, meter: Meter, password?: string): AsyncGenerator<Uint8Array>;
|
|
133
|
+
/** Writes the archive again with the entries in `plan`. The caller closes the sink. */
|
|
134
|
+
write(plan: WritePlan<E>, sink: ByteSink, context: WriteContext): Promise<void>;
|
|
135
|
+
}
|
|
136
|
+
/** The content a writer puts in an entry: what a plugin wrote, or the entry's own bytes decoded again. */
|
|
137
|
+
export declare function contentOf<E extends Entry>(archive: Archive<E>, k: Kept<E>, context: WriteContext): AsyncIterable<Uint8Array>;
|
|
138
|
+
/** No chunks, for an entry with no content. */
|
|
139
|
+
export declare function nothing(): AsyncGenerator<Uint8Array>;
|
|
140
|
+
/** The decoded size of what a writer puts in an entry. */
|
|
141
|
+
export declare const sizeOf: <E extends Entry>(k: Kept<E>) => number;
|
package/dist/model.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sizeOf = void 0;
|
|
4
|
+
exports.contentOf = contentOf;
|
|
5
|
+
exports.nothing = nothing;
|
|
6
|
+
/** The content a writer puts in an entry: what a plugin wrote, or the entry's own bytes decoded again. */
|
|
7
|
+
function contentOf(archive, k, context) {
|
|
8
|
+
return k.replacement ? k.replacement.read() : archive.read(k.entry, context.meter(), k.password);
|
|
9
|
+
}
|
|
10
|
+
/** No chunks, for an entry with no content. */
|
|
11
|
+
async function* nothing() {
|
|
12
|
+
// An empty stream yields nothing.
|
|
13
|
+
}
|
|
14
|
+
/** The decoded size of what a writer puts in an entry. */
|
|
15
|
+
const sizeOf = (k) => (k.replacement ? k.replacement.length : k.entry.size);
|
|
16
|
+
exports.sizeOf = sizeOf;
|