@patrickdk77/archive-defuse 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +378 -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/detect.d.ts +10 -0
- package/dist/detect.js +95 -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 +24 -0
- package/dist/formats.js +106 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +53 -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 +79 -0
- package/dist/pack.js +590 -0
- package/dist/plugins.d.ts +13 -0
- package/dist/plugins.js +56 -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 +311 -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 +51 -0
- package/dist/zip-writer.js +305 -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,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copied from lzma1 (Apache-2.0, Copyright Filip Seman) and changed for lzma-defuse. NOTICE in this folder lists the changes.
|
|
3
|
+
/**
|
|
4
|
+
* Hash chain match finder with 2-, 3- and 4-byte hashing.
|
|
5
|
+
*
|
|
6
|
+
* Every position links to the previous position with the same 4-byte hash.
|
|
7
|
+
* Faster than the binary tree finder but finds fewer long matches.
|
|
8
|
+
*
|
|
9
|
+
* Ported from XZ for Java (0BSD) by Lasse Collin and Igor Pavlov.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.HC4 = void 0;
|
|
13
|
+
const hash234_1 = require("./hash234");
|
|
14
|
+
const lz_encoder_1 = require("./lz-encoder");
|
|
15
|
+
const MAX_POS = 0x7fffffff;
|
|
16
|
+
class HC4 extends lz_encoder_1.LzEncoder {
|
|
17
|
+
hash;
|
|
18
|
+
/** Previous position with the same hash, per position in the cyclic buffer. */
|
|
19
|
+
chain;
|
|
20
|
+
matches;
|
|
21
|
+
depthLimit;
|
|
22
|
+
cyclicSize;
|
|
23
|
+
cyclicPos = -1;
|
|
24
|
+
/** Position counter stored in the hash tables and chain. */
|
|
25
|
+
lzPos;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
super(config);
|
|
28
|
+
this.hash = new hash234_1.Hash234(config.dictSize);
|
|
29
|
+
this.cyclicSize = config.dictSize + 1;
|
|
30
|
+
this.chain = new Int32Array(this.cyclicSize);
|
|
31
|
+
this.lzPos = this.cyclicSize;
|
|
32
|
+
this.matches = new lz_encoder_1.Matches(config.niceLen - 1);
|
|
33
|
+
this.depthLimit = config.depthLimit > 0 ? config.depthLimit : 4 + (config.niceLen >>> 2);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Prepares for a new input without clearing the tables: positions
|
|
37
|
+
* continue after the previous input, so its entries are too far back
|
|
38
|
+
* (`delta >= cyclicSize`) and get ignored like empty ones.
|
|
39
|
+
*/
|
|
40
|
+
reset() {
|
|
41
|
+
super.reset();
|
|
42
|
+
this.cyclicPos = -1;
|
|
43
|
+
this.lzPos += this.cyclicSize;
|
|
44
|
+
if (this.lzPos >= MAX_POS - this.cyclicSize) {
|
|
45
|
+
this.hash.clear();
|
|
46
|
+
this.chain.fill(0);
|
|
47
|
+
this.lzPos = this.cyclicSize;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
getMatches() {
|
|
51
|
+
const matches = this.matches;
|
|
52
|
+
const buf = this.buf;
|
|
53
|
+
matches.count = 0;
|
|
54
|
+
let matchLenLimit = this.matchLenMax;
|
|
55
|
+
let niceLenLimit = this.niceLen;
|
|
56
|
+
const avail = this.movePosition();
|
|
57
|
+
if (avail < matchLenLimit) {
|
|
58
|
+
if (avail === 0)
|
|
59
|
+
return matches;
|
|
60
|
+
matchLenLimit = avail;
|
|
61
|
+
if (niceLenLimit > avail)
|
|
62
|
+
niceLenLimit = avail;
|
|
63
|
+
}
|
|
64
|
+
const readPos = this.readPos;
|
|
65
|
+
this.hash.calcHashes(buf, readPos);
|
|
66
|
+
let delta2 = this.lzPos - this.hash.getHash2Pos();
|
|
67
|
+
const delta3 = this.lzPos - this.hash.getHash3Pos();
|
|
68
|
+
let match = this.hash.getHash4Pos();
|
|
69
|
+
this.hash.updateTables(this.lzPos);
|
|
70
|
+
this.chain[this.cyclicPos] = match;
|
|
71
|
+
let lenBest = 0;
|
|
72
|
+
// A 2-byte match from the hash table.
|
|
73
|
+
if (delta2 < this.cyclicSize && buf[readPos - delta2] === buf[readPos]) {
|
|
74
|
+
lenBest = 2;
|
|
75
|
+
matches.len[0] = 2;
|
|
76
|
+
matches.dist[0] = delta2 - 1;
|
|
77
|
+
matches.count = 1;
|
|
78
|
+
}
|
|
79
|
+
// A 3-byte match, if it's at a different distance.
|
|
80
|
+
if (delta2 !== delta3 && delta3 < this.cyclicSize && buf[readPos - delta3] === buf[readPos]) {
|
|
81
|
+
lenBest = 3;
|
|
82
|
+
matches.dist[matches.count++] = delta3 - 1;
|
|
83
|
+
delta2 = delta3;
|
|
84
|
+
}
|
|
85
|
+
// Extend the hashed match as far as possible.
|
|
86
|
+
if (matches.count > 0) {
|
|
87
|
+
lenBest = (0, lz_encoder_1.getMatchLen)(buf, readPos, delta2, lenBest, matchLenLimit);
|
|
88
|
+
matches.len[matches.count - 1] = lenBest;
|
|
89
|
+
if (lenBest >= niceLenLimit)
|
|
90
|
+
return matches;
|
|
91
|
+
}
|
|
92
|
+
if (lenBest < 3)
|
|
93
|
+
lenBest = 3;
|
|
94
|
+
// Follow the chain of earlier positions with the same 4-byte hash.
|
|
95
|
+
let depth = this.depthLimit;
|
|
96
|
+
while (true) {
|
|
97
|
+
const delta = this.lzPos - match;
|
|
98
|
+
if (depth-- === 0 || delta >= this.cyclicSize) {
|
|
99
|
+
return matches;
|
|
100
|
+
}
|
|
101
|
+
match = this.chain[this.cyclicPos - delta + (delta > this.cyclicPos ? this.cyclicSize : 0)];
|
|
102
|
+
// Cheap checks first: a longer match must differ from the best
|
|
103
|
+
// one at `lenBest`, and must start with the same byte.
|
|
104
|
+
if (buf[readPos + lenBest - delta] === buf[readPos + lenBest] && buf[readPos - delta] === buf[readPos]) {
|
|
105
|
+
const len = (0, lz_encoder_1.getMatchLen)(buf, readPos, delta, 1, matchLenLimit);
|
|
106
|
+
if (len > lenBest) {
|
|
107
|
+
lenBest = len;
|
|
108
|
+
matches.len[matches.count] = len;
|
|
109
|
+
matches.dist[matches.count] = delta - 1;
|
|
110
|
+
++matches.count;
|
|
111
|
+
if (len >= niceLenLimit)
|
|
112
|
+
return matches;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
skip(len) {
|
|
118
|
+
for (let left = len; left > 0; --left) {
|
|
119
|
+
if (this.movePosition() !== 0) {
|
|
120
|
+
this.hash.calcHashes(this.buf, this.readPos);
|
|
121
|
+
this.chain[this.cyclicPos] = this.hash.getHash4Pos();
|
|
122
|
+
this.hash.updateTables(this.lzPos);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
movePosition() {
|
|
127
|
+
const avail = this.movePos(4, 4);
|
|
128
|
+
if (avail !== 0) {
|
|
129
|
+
if (++this.lzPos === MAX_POS) {
|
|
130
|
+
const offset = MAX_POS - this.cyclicSize;
|
|
131
|
+
this.hash.normalize(offset);
|
|
132
|
+
(0, lz_encoder_1.normalizePositions)(this.chain, offset);
|
|
133
|
+
this.lzPos -= offset;
|
|
134
|
+
}
|
|
135
|
+
if (++this.cyclicPos === this.cyclicSize) {
|
|
136
|
+
this.cyclicPos = 0;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return avail;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.HC4 = HC4;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 13-byte header of the `.lzma` ("LZMA_Alone") format:
|
|
3
|
+
*
|
|
4
|
+
* | bytes | field |
|
|
5
|
+
* | ----- | -------------------------------------------- |
|
|
6
|
+
* | 0 | properties: `(pb * 5 + lp) * 9 + lc` |
|
|
7
|
+
* | 1-4 | dictionary size, uint32 little-endian |
|
|
8
|
+
* | 5-12 | uncompressed size, uint64 little-endian, |
|
|
9
|
+
* | | or all 0xFF when unknown (end marker is used)|
|
|
10
|
+
*/
|
|
11
|
+
export declare const HEADER_SIZE = 13;
|
|
12
|
+
/** Uncompressed size value meaning "unknown, ends with an end marker". */
|
|
13
|
+
export declare const UNKNOWN_SIZE = -1;
|
|
14
|
+
export interface LzmaHeader {
|
|
15
|
+
/** Literal context bits (0-8) */
|
|
16
|
+
lc: number;
|
|
17
|
+
/** Literal position bits (0-4) */
|
|
18
|
+
lp: number;
|
|
19
|
+
/** Position bits (0-4) */
|
|
20
|
+
pb: number;
|
|
21
|
+
dictSize: number;
|
|
22
|
+
/** Uncompressed size in bytes, or `UNKNOWN_SIZE` */
|
|
23
|
+
uncompressedSize: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Rounds up to `2^n` or `2^n + 2^(n-1)`, the only dictionary sizes xz and
|
|
27
|
+
* 7-Zip accept in a `.lzma` header. A larger size than the encoder used is
|
|
28
|
+
* always valid, and liblzma rounds the same way.
|
|
29
|
+
*/
|
|
30
|
+
export declare function roundDictSize(dictSize: number): number;
|
|
31
|
+
export declare function encodeHeader(header: LzmaHeader): Uint8Array;
|
|
32
|
+
export declare function decodeHeader(bytes: Uint8Array): LzmaHeader;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copied from lzma1 (Apache-2.0, Copyright Filip Seman) and changed for lzma-defuse. NOTICE in this folder lists the changes.
|
|
3
|
+
/**
|
|
4
|
+
* The 13-byte header of the `.lzma` ("LZMA_Alone") format:
|
|
5
|
+
*
|
|
6
|
+
* | bytes | field |
|
|
7
|
+
* | ----- | -------------------------------------------- |
|
|
8
|
+
* | 0 | properties: `(pb * 5 + lp) * 9 + lc` |
|
|
9
|
+
* | 1-4 | dictionary size, uint32 little-endian |
|
|
10
|
+
* | 5-12 | uncompressed size, uint64 little-endian, |
|
|
11
|
+
* | | or all 0xFF when unknown (end marker is used)|
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.UNKNOWN_SIZE = exports.HEADER_SIZE = void 0;
|
|
15
|
+
exports.roundDictSize = roundDictSize;
|
|
16
|
+
exports.encodeHeader = encodeHeader;
|
|
17
|
+
exports.decodeHeader = decodeHeader;
|
|
18
|
+
exports.HEADER_SIZE = 13;
|
|
19
|
+
/** Uncompressed size value meaning "unknown, ends with an end marker". */
|
|
20
|
+
exports.UNKNOWN_SIZE = -1;
|
|
21
|
+
/**
|
|
22
|
+
* Rounds up to `2^n` or `2^n + 2^(n-1)`, the only dictionary sizes xz and
|
|
23
|
+
* 7-Zip accept in a `.lzma` header. A larger size than the encoder used is
|
|
24
|
+
* always valid, and liblzma rounds the same way.
|
|
25
|
+
*/
|
|
26
|
+
function roundDictSize(dictSize) {
|
|
27
|
+
let d = dictSize - 1;
|
|
28
|
+
d |= d >>> 2;
|
|
29
|
+
d |= d >>> 3;
|
|
30
|
+
d |= d >>> 4;
|
|
31
|
+
d |= d >>> 8;
|
|
32
|
+
d |= d >>> 16;
|
|
33
|
+
return Math.min((d >>> 0) + 1, 0xffffffff);
|
|
34
|
+
}
|
|
35
|
+
function encodeHeader(header) {
|
|
36
|
+
const bytes = new Uint8Array(exports.HEADER_SIZE);
|
|
37
|
+
const view = new DataView(bytes.buffer);
|
|
38
|
+
bytes[0] = (header.pb * 5 + header.lp) * 9 + header.lc;
|
|
39
|
+
view.setUint32(1, roundDictSize(header.dictSize), true);
|
|
40
|
+
if (header.uncompressedSize === exports.UNKNOWN_SIZE) {
|
|
41
|
+
bytes.fill(0xff, 5);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
view.setUint32(5, header.uncompressedSize % 0x100000000, true);
|
|
45
|
+
view.setUint32(9, Math.floor(header.uncompressedSize / 0x100000000), true);
|
|
46
|
+
}
|
|
47
|
+
return bytes;
|
|
48
|
+
}
|
|
49
|
+
function decodeHeader(bytes) {
|
|
50
|
+
if (bytes.length < exports.HEADER_SIZE) {
|
|
51
|
+
throw new Error('Truncated input');
|
|
52
|
+
}
|
|
53
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, exports.HEADER_SIZE);
|
|
54
|
+
let props = bytes[0];
|
|
55
|
+
if (props >= 9 * 5 * 5) {
|
|
56
|
+
throw new Error('Corrupted input: invalid LZMA properties');
|
|
57
|
+
}
|
|
58
|
+
const lc = props % 9;
|
|
59
|
+
props = (props / 9) | 0;
|
|
60
|
+
const lp = props % 5;
|
|
61
|
+
const pb = (props / 5) | 0;
|
|
62
|
+
const dictSize = view.getUint32(1, true);
|
|
63
|
+
const sizeLow = view.getUint32(5, true);
|
|
64
|
+
const sizeHigh = view.getUint32(9, true);
|
|
65
|
+
let uncompressedSize = exports.UNKNOWN_SIZE;
|
|
66
|
+
if (sizeLow !== 0xffffffff || sizeHigh !== 0xffffffff) {
|
|
67
|
+
uncompressedSize = sizeHigh * 0x100000000 + sizeLow;
|
|
68
|
+
if (!Number.isSafeInteger(uncompressedSize)) {
|
|
69
|
+
throw new Error('Unsupported input: uncompressed size is too large');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { lc, lp, pb, dictSize, uncompressedSize };
|
|
73
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decoder-side LZ window: a circular buffer holding the most recent output
|
|
3
|
+
* (the dictionary), which matches copy from.
|
|
4
|
+
*
|
|
5
|
+
* The buffer starts small and doubles until it reaches the dictionary size,
|
|
6
|
+
* so small outputs don't allocate the whole dictionary up front, unless
|
|
7
|
+
* `preallocate` is set. Bytes are passed to `sink` before they get
|
|
8
|
+
* overwritten.
|
|
9
|
+
*/
|
|
10
|
+
export declare class LzDecoder {
|
|
11
|
+
private buf;
|
|
12
|
+
private readonly maxSize;
|
|
13
|
+
private readonly sink;
|
|
14
|
+
/** Next write position. */
|
|
15
|
+
private pos;
|
|
16
|
+
/** Start of the bytes not yet passed to the sink. */
|
|
17
|
+
private start;
|
|
18
|
+
private wrapped;
|
|
19
|
+
/**
|
|
20
|
+
* @param dictSize Largest distance a match may reach back
|
|
21
|
+
* @param sink Receives decoded data. The chunk is only valid during the call.
|
|
22
|
+
* @param preallocate Allocate the whole dictionary now instead of growing
|
|
23
|
+
*/
|
|
24
|
+
constructor(dictSize: number, sink: (chunk: Uint8Array) => void, preallocate?: boolean);
|
|
25
|
+
/** Returns the byte `dist + 1` positions back. */
|
|
26
|
+
getByte(dist: number): number;
|
|
27
|
+
putByte(byte: number): void;
|
|
28
|
+
/** Copies `len` bytes starting `dist + 1` positions back. */
|
|
29
|
+
repeat(dist: number, length: number): void;
|
|
30
|
+
/**
|
|
31
|
+
* Copies `len` bytes of uncompressed data from `input` at `inPos`. XZ for
|
|
32
|
+
* Java copies up to the end of the buffer and leaves the rest to its
|
|
33
|
+
* caller; this copy continues past the end like `repeat`.
|
|
34
|
+
*/
|
|
35
|
+
copyUncompressed(input: Uint8Array, offset: number, length: number): void;
|
|
36
|
+
/** Empties the dictionary, so matches can't reach back before this point. */
|
|
37
|
+
reset(): void;
|
|
38
|
+
/** Passes all pending bytes to the sink. */
|
|
39
|
+
flush(): void;
|
|
40
|
+
private onBufferEnd;
|
|
41
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LzDecoder = void 0;
|
|
4
|
+
// Copied from lzma1 (Apache-2.0, Copyright Filip Seman) and changed for lzma-defuse. NOTICE in this folder lists the changes.
|
|
5
|
+
/**
|
|
6
|
+
* Decoder-side LZ window: a circular buffer holding the most recent output
|
|
7
|
+
* (the dictionary), which matches copy from.
|
|
8
|
+
*
|
|
9
|
+
* The buffer starts small and doubles until it reaches the dictionary size,
|
|
10
|
+
* so small outputs don't allocate the whole dictionary up front, unless
|
|
11
|
+
* `preallocate` is set. Bytes are passed to `sink` before they get
|
|
12
|
+
* overwritten.
|
|
13
|
+
*/
|
|
14
|
+
class LzDecoder {
|
|
15
|
+
buf;
|
|
16
|
+
maxSize;
|
|
17
|
+
sink;
|
|
18
|
+
/** Next write position. */
|
|
19
|
+
pos = 0;
|
|
20
|
+
/** Start of the bytes not yet passed to the sink. */
|
|
21
|
+
start = 0;
|
|
22
|
+
wrapped = false;
|
|
23
|
+
/**
|
|
24
|
+
* @param dictSize Largest distance a match may reach back
|
|
25
|
+
* @param sink Receives decoded data. The chunk is only valid during the call.
|
|
26
|
+
* @param preallocate Allocate the whole dictionary now instead of growing
|
|
27
|
+
*/
|
|
28
|
+
constructor(dictSize, sink, preallocate = false) {
|
|
29
|
+
this.maxSize = dictSize;
|
|
30
|
+
this.buf = new Uint8Array(preallocate ? dictSize : Math.min(dictSize, 1 << 16));
|
|
31
|
+
this.sink = sink;
|
|
32
|
+
}
|
|
33
|
+
/** Returns the byte `dist + 1` positions back. */
|
|
34
|
+
getByte(dist) {
|
|
35
|
+
let offset = this.pos - dist - 1;
|
|
36
|
+
if (offset < 0) {
|
|
37
|
+
offset += this.buf.length;
|
|
38
|
+
}
|
|
39
|
+
return this.buf[offset];
|
|
40
|
+
}
|
|
41
|
+
putByte(byte) {
|
|
42
|
+
this.buf[this.pos++] = byte;
|
|
43
|
+
if (this.pos === this.buf.length) {
|
|
44
|
+
this.onBufferEnd();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Copies `len` bytes starting `dist + 1` positions back. */
|
|
48
|
+
repeat(dist, length) {
|
|
49
|
+
let len = length;
|
|
50
|
+
const history = this.wrapped ? this.buf.length : this.pos;
|
|
51
|
+
if (dist < 0 || dist >= history) {
|
|
52
|
+
throw new Error('Corrupted input: match distance is too large');
|
|
53
|
+
}
|
|
54
|
+
while (len > 0) {
|
|
55
|
+
const buf = this.buf;
|
|
56
|
+
let back = this.pos - dist - 1;
|
|
57
|
+
if (back < 0) {
|
|
58
|
+
back += buf.length;
|
|
59
|
+
}
|
|
60
|
+
const count = Math.min(len, buf.length - this.pos, buf.length - back);
|
|
61
|
+
if (count <= dist && count >= 32) {
|
|
62
|
+
// Source and destination don't overlap.
|
|
63
|
+
buf.copyWithin(this.pos, back, back + count);
|
|
64
|
+
this.pos += count;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// A forward byte copy repeats short distances correctly.
|
|
68
|
+
for (let i = 0; i < count; ++i) {
|
|
69
|
+
buf[this.pos++] = buf[back + i];
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
len -= count;
|
|
73
|
+
if (this.pos === buf.length) {
|
|
74
|
+
this.onBufferEnd();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Copies `len` bytes of uncompressed data from `input` at `inPos`. XZ for
|
|
80
|
+
* Java copies up to the end of the buffer and leaves the rest to its
|
|
81
|
+
* caller; this copy continues past the end like `repeat`.
|
|
82
|
+
*/
|
|
83
|
+
copyUncompressed(input, offset, length) {
|
|
84
|
+
let inPos = offset;
|
|
85
|
+
let len = length;
|
|
86
|
+
while (len > 0) {
|
|
87
|
+
const copySize = Math.min(this.buf.length - this.pos, len);
|
|
88
|
+
this.buf.set(input.subarray(inPos, inPos + copySize), this.pos);
|
|
89
|
+
this.pos += copySize;
|
|
90
|
+
inPos += copySize;
|
|
91
|
+
len -= copySize;
|
|
92
|
+
if (this.pos === this.buf.length) {
|
|
93
|
+
this.onBufferEnd();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Empties the dictionary, so matches can't reach back before this point. */
|
|
98
|
+
reset() {
|
|
99
|
+
// In XZ for Java the caller flushes first. Here the sink has to get
|
|
100
|
+
// the pending bytes before the positions restart, or they are lost.
|
|
101
|
+
this.flush();
|
|
102
|
+
this.start = 0;
|
|
103
|
+
this.pos = 0;
|
|
104
|
+
this.wrapped = false;
|
|
105
|
+
// getByte(0) has to return 0x00 when nothing has been decoded.
|
|
106
|
+
this.buf[this.buf.length - 1] = 0x00;
|
|
107
|
+
}
|
|
108
|
+
/** Passes all pending bytes to the sink. */
|
|
109
|
+
flush() {
|
|
110
|
+
if (this.pos > this.start) {
|
|
111
|
+
this.sink(this.buf.subarray(this.start, this.pos));
|
|
112
|
+
}
|
|
113
|
+
this.start = this.pos;
|
|
114
|
+
}
|
|
115
|
+
onBufferEnd() {
|
|
116
|
+
if (!this.wrapped && this.buf.length < this.maxSize) {
|
|
117
|
+
const grown = new Uint8Array(Math.min(this.buf.length * 2, this.maxSize));
|
|
118
|
+
grown.set(this.buf);
|
|
119
|
+
this.buf = grown;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
this.flush();
|
|
123
|
+
this.pos = 0;
|
|
124
|
+
this.start = 0;
|
|
125
|
+
this.wrapped = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.LzDecoder = LzDecoder;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encoder-side LZ window and the base class of the match finders.
|
|
3
|
+
*
|
|
4
|
+
* The window holds `keepSizeBefore` bytes of history (the dictionary plus
|
|
5
|
+
* what the encoder needs) and `keepSizeAfter` bytes of lookahead. When the
|
|
6
|
+
* read position gets close to the end of the buffer, the window is moved
|
|
7
|
+
* back to the start of the buffer.
|
|
8
|
+
*
|
|
9
|
+
* Ported from XZ for Java (0BSD) by Lasse Collin and Igor Pavlov.
|
|
10
|
+
*/
|
|
11
|
+
export type MatchFinderType = 'hc4' | 'bt4';
|
|
12
|
+
/** Matches found at one position, sorted by increasing length. */
|
|
13
|
+
export declare class Matches {
|
|
14
|
+
readonly len: Int32Array;
|
|
15
|
+
/** Distances minus one (0 means the previous byte). */
|
|
16
|
+
readonly dist: Int32Array;
|
|
17
|
+
count: number;
|
|
18
|
+
constructor(countMax: number);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns how many bytes starting at `off + len` equal the bytes `delta`
|
|
22
|
+
* positions earlier, up to `lenLimit` in total.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getMatchLen(buf: Uint8Array, off: number, delta: number, len: number, lenLimit: number): number;
|
|
25
|
+
/** Subtracts `offset` from all positions, clamping at zero. */
|
|
26
|
+
export declare function normalizePositions(positions: Int32Array, offset: number): void;
|
|
27
|
+
export interface LzEncoderConfig {
|
|
28
|
+
dictSize: number;
|
|
29
|
+
extraSizeBefore: number;
|
|
30
|
+
extraSizeAfter: number;
|
|
31
|
+
niceLen: number;
|
|
32
|
+
matchLenMax: number;
|
|
33
|
+
/** Search depth limit, 0 = automatic */
|
|
34
|
+
depthLimit: number;
|
|
35
|
+
/** Total input size, when known in advance, to avoid oversized buffers */
|
|
36
|
+
inputSize?: number;
|
|
37
|
+
}
|
|
38
|
+
export declare abstract class LzEncoder {
|
|
39
|
+
private readonly keepSizeBefore;
|
|
40
|
+
private readonly keepSizeAfter;
|
|
41
|
+
readonly matchLenMax: number;
|
|
42
|
+
readonly niceLen: number;
|
|
43
|
+
readonly buf: Uint8Array;
|
|
44
|
+
/** Position of the byte most recently returned by the match finder. */
|
|
45
|
+
protected readPos: number;
|
|
46
|
+
private readLimit;
|
|
47
|
+
private finishing;
|
|
48
|
+
private writePos;
|
|
49
|
+
/** Bytes that were skipped because there wasn't enough lookahead yet. */
|
|
50
|
+
private pendingSize;
|
|
51
|
+
constructor(config: LzEncoderConfig);
|
|
52
|
+
/** Prepares the window for a new, independent input. */
|
|
53
|
+
reset(): void;
|
|
54
|
+
/** Returns matches at the next position. */
|
|
55
|
+
abstract getMatches(): Matches;
|
|
56
|
+
/** Advances `len` positions, updating the match finder structures. */
|
|
57
|
+
abstract skip(len: number): void;
|
|
58
|
+
/**
|
|
59
|
+
* Copies input into the window.
|
|
60
|
+
*
|
|
61
|
+
* @returns number of bytes consumed; call again with the rest
|
|
62
|
+
*/
|
|
63
|
+
fillWindow(input: Uint8Array, off: number, length: number): number;
|
|
64
|
+
/** Marks the end of input so that the lookahead can be used up. */
|
|
65
|
+
setFinishing(): void;
|
|
66
|
+
isStarted(): boolean;
|
|
67
|
+
/** True if there is enough input to encode more symbols. */
|
|
68
|
+
hasEnoughData(alreadyReadLen: number): boolean;
|
|
69
|
+
/** Bytes available from the read position, including it. */
|
|
70
|
+
getAvail(): number;
|
|
71
|
+
getPos(): number;
|
|
72
|
+
/** Byte `backward` positions before the read position. */
|
|
73
|
+
getByte(backward: number): number;
|
|
74
|
+
/** Byte `backward` positions before `forward` bytes after the read position. */
|
|
75
|
+
getByteAt(forward: number, backward: number): number;
|
|
76
|
+
/** Length of the match at distance `dist` starting `forward` bytes ahead. */
|
|
77
|
+
getMatchLen(forward: number, dist: number, lenLimit: number): number;
|
|
78
|
+
/**
|
|
79
|
+
* Advances the read position.
|
|
80
|
+
*
|
|
81
|
+
* @returns number of bytes available, or 0 if the position must be
|
|
82
|
+
* processed later when more input has arrived
|
|
83
|
+
*/
|
|
84
|
+
protected movePos(requiredForFlushing: number, requiredForFinishing: number): number;
|
|
85
|
+
private moveWindow;
|
|
86
|
+
private processPendingBytes;
|
|
87
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copied from lzma1 (Apache-2.0, Copyright Filip Seman) and changed for lzma-defuse. NOTICE in this folder lists the changes.
|
|
3
|
+
/**
|
|
4
|
+
* Encoder-side LZ window and the base class of the match finders.
|
|
5
|
+
*
|
|
6
|
+
* The window holds `keepSizeBefore` bytes of history (the dictionary plus
|
|
7
|
+
* what the encoder needs) and `keepSizeAfter` bytes of lookahead. When the
|
|
8
|
+
* read position gets close to the end of the buffer, the window is moved
|
|
9
|
+
* back to the start of the buffer.
|
|
10
|
+
*
|
|
11
|
+
* Ported from XZ for Java (0BSD) by Lasse Collin and Igor Pavlov.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.LzEncoder = exports.Matches = void 0;
|
|
15
|
+
exports.getMatchLen = getMatchLen;
|
|
16
|
+
exports.normalizePositions = normalizePositions;
|
|
17
|
+
/** Matches found at one position, sorted by increasing length. */
|
|
18
|
+
class Matches {
|
|
19
|
+
len;
|
|
20
|
+
/** Distances minus one (0 means the previous byte). */
|
|
21
|
+
dist;
|
|
22
|
+
count = 0;
|
|
23
|
+
constructor(countMax) {
|
|
24
|
+
this.len = new Int32Array(countMax);
|
|
25
|
+
this.dist = new Int32Array(countMax);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.Matches = Matches;
|
|
29
|
+
/**
|
|
30
|
+
* Returns how many bytes starting at `off + len` equal the bytes `delta`
|
|
31
|
+
* positions earlier, up to `lenLimit` in total.
|
|
32
|
+
*/
|
|
33
|
+
function getMatchLen(buf, off, delta, len, lenLimit) {
|
|
34
|
+
const end = off + lenLimit;
|
|
35
|
+
let i = off + len;
|
|
36
|
+
while (i < end && buf[i] === buf[i - delta]) {
|
|
37
|
+
++i;
|
|
38
|
+
}
|
|
39
|
+
return i - off;
|
|
40
|
+
}
|
|
41
|
+
/** Subtracts `offset` from all positions, clamping at zero. */
|
|
42
|
+
function normalizePositions(positions, offset) {
|
|
43
|
+
for (let i = 0; i < positions.length; ++i) {
|
|
44
|
+
positions[i] = positions[i] <= offset ? 0 : positions[i] - offset;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
class LzEncoder {
|
|
48
|
+
keepSizeBefore;
|
|
49
|
+
keepSizeAfter;
|
|
50
|
+
matchLenMax;
|
|
51
|
+
niceLen;
|
|
52
|
+
buf;
|
|
53
|
+
/** Position of the byte most recently returned by the match finder. */
|
|
54
|
+
readPos = -1;
|
|
55
|
+
readLimit = -1;
|
|
56
|
+
finishing = false;
|
|
57
|
+
writePos = 0;
|
|
58
|
+
/** Bytes that were skipped because there wasn't enough lookahead yet. */
|
|
59
|
+
pendingSize = 0;
|
|
60
|
+
constructor(config) {
|
|
61
|
+
this.keepSizeBefore = config.extraSizeBefore + config.dictSize;
|
|
62
|
+
this.keepSizeAfter = config.extraSizeAfter + config.matchLenMax;
|
|
63
|
+
this.matchLenMax = config.matchLenMax;
|
|
64
|
+
this.niceLen = config.niceLen;
|
|
65
|
+
const reserveSize = Math.min((config.dictSize >>> 1) + (256 << 10), 512 << 20);
|
|
66
|
+
let bufSize = this.keepSizeBefore + this.keepSizeAfter + reserveSize;
|
|
67
|
+
if (config.inputSize !== undefined) {
|
|
68
|
+
// The whole input fits, so the window never has to move.
|
|
69
|
+
bufSize = Math.min(bufSize, config.inputSize + this.keepSizeAfter);
|
|
70
|
+
}
|
|
71
|
+
this.buf = new Uint8Array(bufSize);
|
|
72
|
+
}
|
|
73
|
+
/** Prepares the window for a new, independent input. */
|
|
74
|
+
reset() {
|
|
75
|
+
this.readPos = -1;
|
|
76
|
+
this.readLimit = -1;
|
|
77
|
+
this.finishing = false;
|
|
78
|
+
this.writePos = 0;
|
|
79
|
+
this.pendingSize = 0;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Copies input into the window.
|
|
83
|
+
*
|
|
84
|
+
* @returns number of bytes consumed; call again with the rest
|
|
85
|
+
*/
|
|
86
|
+
fillWindow(input, off, length) {
|
|
87
|
+
if (this.readPos >= this.buf.length - this.keepSizeAfter) {
|
|
88
|
+
this.moveWindow();
|
|
89
|
+
}
|
|
90
|
+
const len = Math.min(length, this.buf.length - this.writePos);
|
|
91
|
+
this.buf.set(input.subarray(off, off + len), this.writePos);
|
|
92
|
+
this.writePos += len;
|
|
93
|
+
if (this.writePos >= this.keepSizeAfter) {
|
|
94
|
+
this.readLimit = this.writePos - this.keepSizeAfter;
|
|
95
|
+
}
|
|
96
|
+
this.processPendingBytes();
|
|
97
|
+
return len;
|
|
98
|
+
}
|
|
99
|
+
/** Marks the end of input so that the lookahead can be used up. */
|
|
100
|
+
setFinishing() {
|
|
101
|
+
this.readLimit = this.writePos - 1;
|
|
102
|
+
this.finishing = true;
|
|
103
|
+
this.processPendingBytes();
|
|
104
|
+
}
|
|
105
|
+
isStarted() {
|
|
106
|
+
return this.readPos !== -1;
|
|
107
|
+
}
|
|
108
|
+
/** True if there is enough input to encode more symbols. */
|
|
109
|
+
hasEnoughData(alreadyReadLen) {
|
|
110
|
+
return this.readPos - alreadyReadLen < this.readLimit;
|
|
111
|
+
}
|
|
112
|
+
/** Bytes available from the read position, including it. */
|
|
113
|
+
getAvail() {
|
|
114
|
+
return this.writePos - this.readPos;
|
|
115
|
+
}
|
|
116
|
+
getPos() {
|
|
117
|
+
return this.readPos;
|
|
118
|
+
}
|
|
119
|
+
/** Byte `backward` positions before the read position. */
|
|
120
|
+
getByte(backward) {
|
|
121
|
+
return this.buf[this.readPos - backward];
|
|
122
|
+
}
|
|
123
|
+
/** Byte `backward` positions before `forward` bytes after the read position. */
|
|
124
|
+
getByteAt(forward, backward) {
|
|
125
|
+
return this.buf[this.readPos + forward - backward];
|
|
126
|
+
}
|
|
127
|
+
/** Length of the match at distance `dist` starting `forward` bytes ahead. */
|
|
128
|
+
getMatchLen(forward, dist, lenLimit) {
|
|
129
|
+
return getMatchLen(this.buf, this.readPos + forward, dist + 1, 0, lenLimit);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Advances the read position.
|
|
133
|
+
*
|
|
134
|
+
* @returns number of bytes available, or 0 if the position must be
|
|
135
|
+
* processed later when more input has arrived
|
|
136
|
+
*/
|
|
137
|
+
movePos(requiredForFlushing, requiredForFinishing) {
|
|
138
|
+
++this.readPos;
|
|
139
|
+
let avail = this.writePos - this.readPos;
|
|
140
|
+
if (avail < requiredForFlushing) {
|
|
141
|
+
if (avail < requiredForFinishing || !this.finishing) {
|
|
142
|
+
++this.pendingSize;
|
|
143
|
+
avail = 0;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return avail;
|
|
147
|
+
}
|
|
148
|
+
moveWindow() {
|
|
149
|
+
// Keep the offset a multiple of 16 so that the low bits of positions,
|
|
150
|
+
// which select probabilities, don't change.
|
|
151
|
+
const moveOffset = (this.readPos + 1 - this.keepSizeBefore) & ~15;
|
|
152
|
+
this.buf.copyWithin(0, moveOffset, this.writePos);
|
|
153
|
+
this.readPos -= moveOffset;
|
|
154
|
+
this.readLimit -= moveOffset;
|
|
155
|
+
this.writePos -= moveOffset;
|
|
156
|
+
}
|
|
157
|
+
processPendingBytes() {
|
|
158
|
+
if (this.pendingSize > 0 && this.readPos < this.readLimit) {
|
|
159
|
+
this.readPos -= this.pendingSize;
|
|
160
|
+
const oldPendingSize = this.pendingSize;
|
|
161
|
+
this.pendingSize = 0;
|
|
162
|
+
this.skip(oldPendingSize);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.LzEncoder = LzEncoder;
|