@ismail-elkorchi/bytefold 0.6.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 +48 -0
- package/SPEC.md +285 -0
- package/dist/abort.d.ts +3 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +33 -0
- package/dist/abort.js.map +1 -0
- package/dist/archive/errors.d.ts +34 -0
- package/dist/archive/errors.d.ts.map +1 -0
- package/dist/archive/errors.js +45 -0
- package/dist/archive/errors.js.map +1 -0
- package/dist/archive/httpArchiveErrors.d.ts +2 -0
- package/dist/archive/httpArchiveErrors.d.ts.map +1 -0
- package/dist/archive/httpArchiveErrors.js +25 -0
- package/dist/archive/httpArchiveErrors.js.map +1 -0
- package/dist/archive/index.d.ts +47 -0
- package/dist/archive/index.d.ts.map +1 -0
- package/dist/archive/index.js +1490 -0
- package/dist/archive/index.js.map +1 -0
- package/dist/archive/types.d.ts +91 -0
- package/dist/archive/types.d.ts.map +1 -0
- package/dist/archive/types.js +2 -0
- package/dist/archive/types.js.map +1 -0
- package/dist/archive/xzPreflight.d.ts +13 -0
- package/dist/archive/xzPreflight.d.ts.map +1 -0
- package/dist/archive/xzPreflight.js +44 -0
- package/dist/archive/xzPreflight.js.map +1 -0
- package/dist/archive/zipPreflight.d.ts +18 -0
- package/dist/archive/zipPreflight.d.ts.map +1 -0
- package/dist/archive/zipPreflight.js +50 -0
- package/dist/archive/zipPreflight.js.map +1 -0
- package/dist/binary.d.ts +12 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +59 -0
- package/dist/binary.js.map +1 -0
- package/dist/bun/index.d.ts +19 -0
- package/dist/bun/index.d.ts.map +1 -0
- package/dist/bun/index.js +427 -0
- package/dist/bun/index.js.map +1 -0
- package/dist/compress/errors.d.ts +30 -0
- package/dist/compress/errors.d.ts.map +1 -0
- package/dist/compress/errors.js +40 -0
- package/dist/compress/errors.js.map +1 -0
- package/dist/compress/index.d.ts +12 -0
- package/dist/compress/index.d.ts.map +1 -0
- package/dist/compress/index.js +339 -0
- package/dist/compress/index.js.map +1 -0
- package/dist/compress/types.d.ts +41 -0
- package/dist/compress/types.d.ts.map +1 -0
- package/dist/compress/types.js +2 -0
- package/dist/compress/types.js.map +1 -0
- package/dist/compression/bzip2.d.ts +9 -0
- package/dist/compression/bzip2.d.ts.map +1 -0
- package/dist/compression/bzip2.js +546 -0
- package/dist/compression/bzip2.js.map +1 -0
- package/dist/compression/codecs.d.ts +6 -0
- package/dist/compression/codecs.d.ts.map +1 -0
- package/dist/compression/codecs.js +82 -0
- package/dist/compression/codecs.js.map +1 -0
- package/dist/compression/deflate64.d.ts +3 -0
- package/dist/compression/deflate64.d.ts.map +1 -0
- package/dist/compression/deflate64.js +549 -0
- package/dist/compression/deflate64.js.map +1 -0
- package/dist/compression/node-backend.d.ts +9 -0
- package/dist/compression/node-backend.d.ts.map +1 -0
- package/dist/compression/node-backend.js +103 -0
- package/dist/compression/node-backend.js.map +1 -0
- package/dist/compression/registry.d.ts +10 -0
- package/dist/compression/registry.d.ts.map +1 -0
- package/dist/compression/registry.js +30 -0
- package/dist/compression/registry.js.map +1 -0
- package/dist/compression/streams.d.ts +31 -0
- package/dist/compression/streams.d.ts.map +1 -0
- package/dist/compression/streams.js +147 -0
- package/dist/compression/streams.js.map +1 -0
- package/dist/compression/types.d.ts +19 -0
- package/dist/compression/types.d.ts.map +1 -0
- package/dist/compression/types.js +2 -0
- package/dist/compression/types.js.map +1 -0
- package/dist/compression/xz.d.ts +21 -0
- package/dist/compression/xz.d.ts.map +1 -0
- package/dist/compression/xz.js +1455 -0
- package/dist/compression/xz.js.map +1 -0
- package/dist/compression/xzFilters.d.ts +14 -0
- package/dist/compression/xzFilters.d.ts.map +1 -0
- package/dist/compression/xzFilters.js +736 -0
- package/dist/compression/xzFilters.js.map +1 -0
- package/dist/compression/xzIndexPreflight.d.ts +20 -0
- package/dist/compression/xzIndexPreflight.d.ts.map +1 -0
- package/dist/compression/xzIndexPreflight.js +371 -0
- package/dist/compression/xzIndexPreflight.js.map +1 -0
- package/dist/compression/xzScan.d.ts +15 -0
- package/dist/compression/xzScan.d.ts.map +1 -0
- package/dist/compression/xzScan.js +310 -0
- package/dist/compression/xzScan.js.map +1 -0
- package/dist/cp437.d.ts +2 -0
- package/dist/cp437.d.ts.map +1 -0
- package/dist/cp437.js +31 -0
- package/dist/cp437.js.map +1 -0
- package/dist/crc32.d.ts +7 -0
- package/dist/crc32.d.ts.map +1 -0
- package/dist/crc32.js +37 -0
- package/dist/crc32.js.map +1 -0
- package/dist/crc64.d.ts +6 -0
- package/dist/crc64.d.ts.map +1 -0
- package/dist/crc64.js +32 -0
- package/dist/crc64.js.map +1 -0
- package/dist/crypto/ctr.d.ts +11 -0
- package/dist/crypto/ctr.d.ts.map +1 -0
- package/dist/crypto/ctr.js +56 -0
- package/dist/crypto/ctr.js.map +1 -0
- package/dist/crypto/sha256.d.ts +16 -0
- package/dist/crypto/sha256.d.ts.map +1 -0
- package/dist/crypto/sha256.js +152 -0
- package/dist/crypto/sha256.js.map +1 -0
- package/dist/crypto/winzip-aes.d.ts +17 -0
- package/dist/crypto/winzip-aes.d.ts.map +1 -0
- package/dist/crypto/winzip-aes.js +98 -0
- package/dist/crypto/winzip-aes.js.map +1 -0
- package/dist/crypto/zipcrypto.d.ts +23 -0
- package/dist/crypto/zipcrypto.d.ts.map +1 -0
- package/dist/crypto/zipcrypto.js +99 -0
- package/dist/crypto/zipcrypto.js.map +1 -0
- package/dist/deno/index.d.ts +19 -0
- package/dist/deno/index.d.ts.map +1 -0
- package/dist/deno/index.js +422 -0
- package/dist/deno/index.js.map +1 -0
- package/dist/dosTime.d.ts +7 -0
- package/dist/dosTime.d.ts.map +1 -0
- package/dist/dosTime.js +21 -0
- package/dist/dosTime.js.map +1 -0
- package/dist/errorContext.d.ts +2 -0
- package/dist/errorContext.d.ts.map +1 -0
- package/dist/errorContext.js +24 -0
- package/dist/errorContext.js.map +1 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +51 -0
- package/dist/errors.js.map +1 -0
- package/dist/extraFields.d.ts +29 -0
- package/dist/extraFields.d.ts.map +1 -0
- package/dist/extraFields.js +201 -0
- package/dist/extraFields.js.map +1 -0
- package/dist/generated/unicodeCaseFolding.d.ts +4 -0
- package/dist/generated/unicodeCaseFolding.d.ts.map +1 -0
- package/dist/generated/unicodeCaseFolding.js +1594 -0
- package/dist/generated/unicodeCaseFolding.js.map +1 -0
- package/dist/http/errors.d.ts +26 -0
- package/dist/http/errors.d.ts.map +1 -0
- package/dist/http/errors.js +33 -0
- package/dist/http/errors.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +22 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +39 -0
- package/dist/limits.js.map +1 -0
- package/dist/node/index.d.ts +13 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +448 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/zip/RandomAccess.d.ts +12 -0
- package/dist/node/zip/RandomAccess.d.ts.map +1 -0
- package/dist/node/zip/RandomAccess.js +38 -0
- package/dist/node/zip/RandomAccess.js.map +1 -0
- package/dist/node/zip/Sink.d.ts +17 -0
- package/dist/node/zip/Sink.d.ts.map +1 -0
- package/dist/node/zip/Sink.js +45 -0
- package/dist/node/zip/Sink.js.map +1 -0
- package/dist/node/zip/ZipReader.d.ts +51 -0
- package/dist/node/zip/ZipReader.d.ts.map +1 -0
- package/dist/node/zip/ZipReader.js +1540 -0
- package/dist/node/zip/ZipReader.js.map +1 -0
- package/dist/node/zip/ZipWriter.d.ts +21 -0
- package/dist/node/zip/ZipWriter.d.ts.map +1 -0
- package/dist/node/zip/ZipWriter.js +196 -0
- package/dist/node/zip/ZipWriter.js.map +1 -0
- package/dist/node/zip/entryStream.d.ts +22 -0
- package/dist/node/zip/entryStream.d.ts.map +1 -0
- package/dist/node/zip/entryStream.js +241 -0
- package/dist/node/zip/entryStream.js.map +1 -0
- package/dist/node/zip/entryWriter.d.ts +54 -0
- package/dist/node/zip/entryWriter.d.ts.map +1 -0
- package/dist/node/zip/entryWriter.js +512 -0
- package/dist/node/zip/entryWriter.js.map +1 -0
- package/dist/node/zip/index.d.ts +8 -0
- package/dist/node/zip/index.d.ts.map +1 -0
- package/dist/node/zip/index.js +5 -0
- package/dist/node/zip/index.js.map +1 -0
- package/dist/reader/RandomAccess.d.ts +55 -0
- package/dist/reader/RandomAccess.d.ts.map +1 -0
- package/dist/reader/RandomAccess.js +528 -0
- package/dist/reader/RandomAccess.js.map +1 -0
- package/dist/reader/ZipReader.d.ts +89 -0
- package/dist/reader/ZipReader.d.ts.map +1 -0
- package/dist/reader/ZipReader.js +1359 -0
- package/dist/reader/ZipReader.js.map +1 -0
- package/dist/reader/centralDirectory.d.ts +40 -0
- package/dist/reader/centralDirectory.d.ts.map +1 -0
- package/dist/reader/centralDirectory.js +311 -0
- package/dist/reader/centralDirectory.js.map +1 -0
- package/dist/reader/entryStream.d.ts +22 -0
- package/dist/reader/entryStream.d.ts.map +1 -0
- package/dist/reader/entryStream.js +122 -0
- package/dist/reader/entryStream.js.map +1 -0
- package/dist/reader/eocd.d.ts +22 -0
- package/dist/reader/eocd.d.ts.map +1 -0
- package/dist/reader/eocd.js +184 -0
- package/dist/reader/eocd.js.map +1 -0
- package/dist/reader/httpZipErrors.d.ts +4 -0
- package/dist/reader/httpZipErrors.d.ts.map +1 -0
- package/dist/reader/httpZipErrors.js +48 -0
- package/dist/reader/httpZipErrors.js.map +1 -0
- package/dist/reader/localHeader.d.ts +15 -0
- package/dist/reader/localHeader.d.ts.map +1 -0
- package/dist/reader/localHeader.js +37 -0
- package/dist/reader/localHeader.js.map +1 -0
- package/dist/reportSchema.d.ts +3 -0
- package/dist/reportSchema.d.ts.map +1 -0
- package/dist/reportSchema.js +3 -0
- package/dist/reportSchema.js.map +1 -0
- package/dist/streams/adapters.d.ts +10 -0
- package/dist/streams/adapters.d.ts.map +1 -0
- package/dist/streams/adapters.js +54 -0
- package/dist/streams/adapters.js.map +1 -0
- package/dist/streams/buffer.d.ts +5 -0
- package/dist/streams/buffer.d.ts.map +1 -0
- package/dist/streams/buffer.js +44 -0
- package/dist/streams/buffer.js.map +1 -0
- package/dist/streams/crcTransform.d.ts +15 -0
- package/dist/streams/crcTransform.d.ts.map +1 -0
- package/dist/streams/crcTransform.js +30 -0
- package/dist/streams/crcTransform.js.map +1 -0
- package/dist/streams/emit.d.ts +7 -0
- package/dist/streams/emit.d.ts.map +1 -0
- package/dist/streams/emit.js +13 -0
- package/dist/streams/emit.js.map +1 -0
- package/dist/streams/limits.d.ts +16 -0
- package/dist/streams/limits.d.ts.map +1 -0
- package/dist/streams/limits.js +39 -0
- package/dist/streams/limits.js.map +1 -0
- package/dist/streams/measure.d.ts +5 -0
- package/dist/streams/measure.d.ts.map +1 -0
- package/dist/streams/measure.js +9 -0
- package/dist/streams/measure.js.map +1 -0
- package/dist/streams/progress.d.ts +8 -0
- package/dist/streams/progress.d.ts.map +1 -0
- package/dist/streams/progress.js +69 -0
- package/dist/streams/progress.js.map +1 -0
- package/dist/streams/web.d.ts +5 -0
- package/dist/streams/web.d.ts.map +1 -0
- package/dist/streams/web.js +33 -0
- package/dist/streams/web.js.map +1 -0
- package/dist/tar/TarReader.d.ts +41 -0
- package/dist/tar/TarReader.d.ts.map +1 -0
- package/dist/tar/TarReader.js +930 -0
- package/dist/tar/TarReader.js.map +1 -0
- package/dist/tar/TarWriter.d.ts +25 -0
- package/dist/tar/TarWriter.d.ts.map +1 -0
- package/dist/tar/TarWriter.js +307 -0
- package/dist/tar/TarWriter.js.map +1 -0
- package/dist/tar/index.d.ts +4 -0
- package/dist/tar/index.d.ts.map +1 -0
- package/dist/tar/index.js +3 -0
- package/dist/tar/index.js.map +1 -0
- package/dist/tar/types.d.ts +67 -0
- package/dist/tar/types.d.ts.map +1 -0
- package/dist/tar/types.js +2 -0
- package/dist/tar/types.js.map +1 -0
- package/dist/text/caseFold.d.ts +7 -0
- package/dist/text/caseFold.d.ts.map +1 -0
- package/dist/text/caseFold.js +45 -0
- package/dist/text/caseFold.js.map +1 -0
- package/dist/types.d.ts +190 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/web/index.d.ts +11 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +95 -0
- package/dist/web/index.js.map +1 -0
- package/dist/writer/Sink.d.ts +21 -0
- package/dist/writer/Sink.d.ts.map +1 -0
- package/dist/writer/Sink.js +24 -0
- package/dist/writer/Sink.js.map +1 -0
- package/dist/writer/ZipWriter.d.ts +27 -0
- package/dist/writer/ZipWriter.d.ts.map +1 -0
- package/dist/writer/ZipWriter.js +153 -0
- package/dist/writer/ZipWriter.js.map +1 -0
- package/dist/writer/centralDirectoryWriter.d.ts +8 -0
- package/dist/writer/centralDirectoryWriter.d.ts.map +1 -0
- package/dist/writer/centralDirectoryWriter.js +77 -0
- package/dist/writer/centralDirectoryWriter.js.map +1 -0
- package/dist/writer/entryWriter.d.ts +54 -0
- package/dist/writer/entryWriter.d.ts.map +1 -0
- package/dist/writer/entryWriter.js +327 -0
- package/dist/writer/entryWriter.js.map +1 -0
- package/dist/writer/finalize.d.ts +10 -0
- package/dist/writer/finalize.d.ts.map +1 -0
- package/dist/writer/finalize.js +56 -0
- package/dist/writer/finalize.js.map +1 -0
- package/dist/zip/index.d.ts +8 -0
- package/dist/zip/index.d.ts.map +1 -0
- package/dist/zip/index.js +5 -0
- package/dist/zip/index.js.map +1 -0
- package/jsr.json +41 -0
- package/package.json +117 -0
- package/schemas/audit-report.schema.json +38 -0
- package/schemas/capabilities-report.schema.json +25 -0
- package/schemas/detection-report.schema.json +23 -0
- package/schemas/error.schema.json +22 -0
- package/schemas/normalize-report.schema.json +47 -0
|
@@ -0,0 +1,1455 @@
|
|
|
1
|
+
import { throwIfAborted } from '../abort.js';
|
|
2
|
+
import { readUint32LE } from '../binary.js';
|
|
3
|
+
import { Crc32 } from '../crc32.js';
|
|
4
|
+
import { Crc64 } from '../crc64.js';
|
|
5
|
+
import { Sha256 } from '../crypto/sha256.js';
|
|
6
|
+
import { CompressionError } from '../compress/errors.js';
|
|
7
|
+
import { emitStable } from '../streams/emit.js';
|
|
8
|
+
import { AGENT_RESOURCE_LIMITS, DEFAULT_RESOURCE_LIMITS } from '../limits.js';
|
|
9
|
+
import { createFilterChain, validateFilterChain } from './xzFilters.js';
|
|
10
|
+
const HEADER_MAGIC = new Uint8Array([0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00]);
|
|
11
|
+
const FOOTER_MAGIC = new Uint8Array([0x59, 0x5a]);
|
|
12
|
+
const OUTPUT_CHUNK_SIZE = 32 * 1024;
|
|
13
|
+
const DEFAULT_MAX_BUFFERED_INPUT = DEFAULT_RESOURCE_LIMITS.maxXzBufferedBytes;
|
|
14
|
+
export function createXzDecompressStream(options = {}) {
|
|
15
|
+
const profile = options.profile ?? 'strict';
|
|
16
|
+
const limitOptions = { profile };
|
|
17
|
+
if (options.maxDictionaryBytes !== undefined)
|
|
18
|
+
limitOptions.maxDictionaryBytes = options.maxDictionaryBytes;
|
|
19
|
+
if (options.maxBufferedInputBytes !== undefined)
|
|
20
|
+
limitOptions.maxBufferedInputBytes = options.maxBufferedInputBytes;
|
|
21
|
+
const resolvedLimits = resolveXzLimits(limitOptions);
|
|
22
|
+
const resolved = {
|
|
23
|
+
maxDictionaryBytes: resolvedLimits.maxDictionaryBytes,
|
|
24
|
+
maxBufferedInputBytes: resolvedLimits.maxBufferedInputBytes,
|
|
25
|
+
profile,
|
|
26
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
27
|
+
...(options.maxOutputBytes !== undefined ? { maxOutputBytes: toBigInt(options.maxOutputBytes) } : {}),
|
|
28
|
+
...(typeof options.maxCompressionRatio === 'number' && Number.isFinite(options.maxCompressionRatio)
|
|
29
|
+
? options.maxCompressionRatio > 0
|
|
30
|
+
? { maxCompressionRatio: options.maxCompressionRatio }
|
|
31
|
+
: {}
|
|
32
|
+
: {})
|
|
33
|
+
};
|
|
34
|
+
const debug = options.__xzDebug;
|
|
35
|
+
let decoder = null;
|
|
36
|
+
return new TransformStream({
|
|
37
|
+
start(controller) {
|
|
38
|
+
decoder = new XzDecoder(resolved, (part) => emitStable(controller, part), debug);
|
|
39
|
+
},
|
|
40
|
+
transform(chunk) {
|
|
41
|
+
if (options.signal)
|
|
42
|
+
throwIfAborted(options.signal);
|
|
43
|
+
if (!chunk || chunk.length === 0)
|
|
44
|
+
return;
|
|
45
|
+
decoder?.push(chunk);
|
|
46
|
+
},
|
|
47
|
+
flush() {
|
|
48
|
+
if (options.signal)
|
|
49
|
+
throwIfAborted(options.signal);
|
|
50
|
+
decoder?.finish();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
export function resolveXzLimits(options = {}) {
|
|
55
|
+
const profile = options.profile ?? 'strict';
|
|
56
|
+
return {
|
|
57
|
+
maxDictionaryBytes: resolveMaxDictionaryBytes(options.maxDictionaryBytes, profile),
|
|
58
|
+
maxBufferedInputBytes: typeof options.maxBufferedInputBytes === 'number' && Number.isFinite(options.maxBufferedInputBytes)
|
|
59
|
+
? Math.max(1, Math.floor(options.maxBufferedInputBytes))
|
|
60
|
+
: DEFAULT_MAX_BUFFERED_INPUT
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function readXzDictionarySize(data) {
|
|
64
|
+
if (data.length < 12)
|
|
65
|
+
return undefined;
|
|
66
|
+
for (let i = 0; i < HEADER_MAGIC.length; i += 1) {
|
|
67
|
+
if (data[i] !== HEADER_MAGIC[i])
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
let offset = 12;
|
|
71
|
+
if (offset >= data.length)
|
|
72
|
+
return undefined;
|
|
73
|
+
const headerSizeByte = data[offset];
|
|
74
|
+
if (headerSizeByte === 0x00)
|
|
75
|
+
return undefined;
|
|
76
|
+
const headerSize = (headerSizeByte + 1) * 4;
|
|
77
|
+
if (headerSize < 8 || headerSize > 1024)
|
|
78
|
+
return undefined;
|
|
79
|
+
if (offset + headerSize > data.length)
|
|
80
|
+
return undefined;
|
|
81
|
+
const header = data.subarray(offset, offset + headerSize);
|
|
82
|
+
try {
|
|
83
|
+
const storedCrc = readUint32LE(header, header.length - 4);
|
|
84
|
+
const crc = new Crc32();
|
|
85
|
+
crc.update(header.subarray(0, header.length - 4));
|
|
86
|
+
if (crc.digest() !== storedCrc)
|
|
87
|
+
return undefined;
|
|
88
|
+
let pos = 1;
|
|
89
|
+
const flags = header[pos++];
|
|
90
|
+
if ((flags & 0x3c) !== 0)
|
|
91
|
+
return undefined;
|
|
92
|
+
const filterCount = (flags & 0x03) + 1;
|
|
93
|
+
if (filterCount > 4)
|
|
94
|
+
return undefined;
|
|
95
|
+
const hasCompressedSize = (flags & 0x40) !== 0;
|
|
96
|
+
const hasUncompressedSize = (flags & 0x80) !== 0;
|
|
97
|
+
if (hasCompressedSize) {
|
|
98
|
+
const read = readVliFromBuffer(header, pos);
|
|
99
|
+
pos = read.offset;
|
|
100
|
+
}
|
|
101
|
+
if (hasUncompressedSize) {
|
|
102
|
+
const read = readVliFromBuffer(header, pos);
|
|
103
|
+
pos = read.offset;
|
|
104
|
+
}
|
|
105
|
+
const filters = [];
|
|
106
|
+
for (let i = 0; i < filterCount; i += 1) {
|
|
107
|
+
const id = readVliFromBuffer(header, pos);
|
|
108
|
+
pos = id.offset;
|
|
109
|
+
const propsSize = readVliFromBuffer(header, pos);
|
|
110
|
+
pos = propsSize.offset;
|
|
111
|
+
const propsBytes = toNumberOrThrow(propsSize.value, 'Filter property size');
|
|
112
|
+
if (pos + propsBytes > header.length - 4)
|
|
113
|
+
return undefined;
|
|
114
|
+
const props = header.subarray(pos, pos + propsBytes);
|
|
115
|
+
pos += propsBytes;
|
|
116
|
+
filters.push({ id: id.value, props });
|
|
117
|
+
}
|
|
118
|
+
const { lzma2Props } = validateFilterChain(filters);
|
|
119
|
+
return decodeDictionarySize(lzma2Props);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
class XzDecoder {
|
|
126
|
+
options;
|
|
127
|
+
queue;
|
|
128
|
+
output;
|
|
129
|
+
debug;
|
|
130
|
+
blocks = [];
|
|
131
|
+
streamFlags = new Uint8Array(2);
|
|
132
|
+
checkType = 0;
|
|
133
|
+
checkSize = 0;
|
|
134
|
+
skipCheck = false;
|
|
135
|
+
state = 'stream-header';
|
|
136
|
+
block = null;
|
|
137
|
+
index = null;
|
|
138
|
+
indexSize = 0;
|
|
139
|
+
streamStartOffset = 0;
|
|
140
|
+
streamPaddingRemaining = null;
|
|
141
|
+
bytesIn = 0;
|
|
142
|
+
done = false;
|
|
143
|
+
constructor(options, emit, debug) {
|
|
144
|
+
this.options = options;
|
|
145
|
+
this.debug = debug;
|
|
146
|
+
this.queue = new ByteQueue(debug);
|
|
147
|
+
this.output = new OutputSink(emit, options, debug);
|
|
148
|
+
if (this.debug) {
|
|
149
|
+
if (this.debug.totalBytesIn === undefined)
|
|
150
|
+
this.debug.totalBytesIn = 0;
|
|
151
|
+
if (this.debug.totalBytesOut === undefined)
|
|
152
|
+
this.debug.totalBytesOut = 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
push(chunk) {
|
|
156
|
+
this.bytesIn += chunk.length;
|
|
157
|
+
if (this.debug)
|
|
158
|
+
this.debug.totalBytesIn = this.bytesIn;
|
|
159
|
+
this.queue.push(chunk);
|
|
160
|
+
this.process();
|
|
161
|
+
this.enforceBufferLimit();
|
|
162
|
+
}
|
|
163
|
+
finish() {
|
|
164
|
+
this.queue.markDone();
|
|
165
|
+
this.process();
|
|
166
|
+
this.enforceBufferLimit();
|
|
167
|
+
if (!this.done) {
|
|
168
|
+
throw xzTruncated('Unexpected end of XZ stream');
|
|
169
|
+
}
|
|
170
|
+
this.output.flush();
|
|
171
|
+
this.output.verifyRatio(this.bytesIn, this.options.maxCompressionRatio);
|
|
172
|
+
}
|
|
173
|
+
enforceBufferLimit() {
|
|
174
|
+
if (this.queue.length > this.options.maxBufferedInputBytes) {
|
|
175
|
+
throw new CompressionError('COMPRESSION_XZ_BUFFER_LIMIT', 'XZ buffered input exceeds limit', {
|
|
176
|
+
algorithm: 'xz'
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
process() {
|
|
181
|
+
while (true) {
|
|
182
|
+
const progressed = (() => {
|
|
183
|
+
switch (this.state) {
|
|
184
|
+
case 'stream-header':
|
|
185
|
+
return this.readStreamHeader();
|
|
186
|
+
case 'block-header':
|
|
187
|
+
return this.readBlockHeader();
|
|
188
|
+
case 'block-data':
|
|
189
|
+
return this.decodeBlockData();
|
|
190
|
+
case 'block-padding':
|
|
191
|
+
return this.readBlockPadding();
|
|
192
|
+
case 'block-check':
|
|
193
|
+
return this.readBlockCheck();
|
|
194
|
+
case 'index':
|
|
195
|
+
return this.decodeIndex();
|
|
196
|
+
case 'footer':
|
|
197
|
+
return this.decodeFooter();
|
|
198
|
+
case 'stream-padding':
|
|
199
|
+
return this.decodeStreamPadding();
|
|
200
|
+
case 'done':
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
})();
|
|
204
|
+
if (!progressed)
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
readStreamHeader() {
|
|
209
|
+
const header = this.queue.readBytes(12);
|
|
210
|
+
if (!header) {
|
|
211
|
+
if (this.queue.done)
|
|
212
|
+
throw xzTruncated('Truncated XZ stream header');
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
this.streamStartOffset = this.queue.totalRead - 12;
|
|
216
|
+
const magic = header.subarray(0, 6);
|
|
217
|
+
if (!matches(magic, HEADER_MAGIC)) {
|
|
218
|
+
throw xzBadData('Invalid XZ header magic');
|
|
219
|
+
}
|
|
220
|
+
const flags = header.subarray(6, 8);
|
|
221
|
+
if (flags[0] !== 0x00 || (flags[1] & 0xf0) !== 0) {
|
|
222
|
+
throw xzBadData('Invalid XZ stream flags');
|
|
223
|
+
}
|
|
224
|
+
const storedCrc = readUint32LE(header, 8);
|
|
225
|
+
const crc = new Crc32();
|
|
226
|
+
crc.update(flags);
|
|
227
|
+
if (crc.digest() !== storedCrc) {
|
|
228
|
+
throw xzBadData('XZ stream header CRC mismatch');
|
|
229
|
+
}
|
|
230
|
+
const checkType = flags[1] & 0x0f;
|
|
231
|
+
const checkSize = checkSizeForId(checkType);
|
|
232
|
+
const supported = isSupportedCheckType(checkType);
|
|
233
|
+
if (!supported && this.options.profile !== 'compat') {
|
|
234
|
+
throw new CompressionError('COMPRESSION_XZ_UNSUPPORTED_CHECK', `XZ check type ${describeCheck(checkType)} is not supported`, { algorithm: 'xz' });
|
|
235
|
+
}
|
|
236
|
+
this.streamFlags = flags;
|
|
237
|
+
this.checkType = checkType;
|
|
238
|
+
this.checkSize = checkSize;
|
|
239
|
+
this.skipCheck = !supported;
|
|
240
|
+
this.blocks.length = 0;
|
|
241
|
+
this.indexSize = 0;
|
|
242
|
+
this.streamPaddingRemaining = null;
|
|
243
|
+
this.state = 'block-header';
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
readBlockHeader() {
|
|
247
|
+
const peek = this.queue.peekByte();
|
|
248
|
+
if (peek === null) {
|
|
249
|
+
if (this.queue.done)
|
|
250
|
+
throw xzTruncated('Missing XZ index');
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
if (peek === 0x00) {
|
|
254
|
+
this.state = 'index';
|
|
255
|
+
this.index = {
|
|
256
|
+
startOffset: this.queue.totalRead,
|
|
257
|
+
crc: new Crc32(),
|
|
258
|
+
recordCount: null,
|
|
259
|
+
recordsRead: 0,
|
|
260
|
+
paddingRemaining: null,
|
|
261
|
+
indicatorRead: false,
|
|
262
|
+
pendingUnpadded: null
|
|
263
|
+
};
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
const headerSizeByte = peek;
|
|
267
|
+
if (headerSizeByte === 0x00) {
|
|
268
|
+
throw xzBadData('Unexpected index indicator in block header');
|
|
269
|
+
}
|
|
270
|
+
const headerSize = (headerSizeByte + 1) * 4;
|
|
271
|
+
if (headerSize < 8 || headerSize > 1024) {
|
|
272
|
+
throw xzBadData('Invalid XZ block header size');
|
|
273
|
+
}
|
|
274
|
+
if (this.queue.length < headerSize) {
|
|
275
|
+
if (this.queue.done)
|
|
276
|
+
throw xzTruncated('Truncated XZ block header');
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
const header = this.queue.readBytes(headerSize);
|
|
280
|
+
const storedCrc = readUint32LE(header, header.length - 4);
|
|
281
|
+
const crc = new Crc32();
|
|
282
|
+
crc.update(header.subarray(0, header.length - 4));
|
|
283
|
+
if (crc.digest() !== storedCrc) {
|
|
284
|
+
throw xzBadData('XZ block header CRC mismatch');
|
|
285
|
+
}
|
|
286
|
+
let offset = 1;
|
|
287
|
+
const flags = header[offset++];
|
|
288
|
+
if ((flags & 0x3c) !== 0) {
|
|
289
|
+
throw new CompressionError('COMPRESSION_XZ_UNSUPPORTED_FILTER', 'XZ block header uses unsupported filter flags', {
|
|
290
|
+
algorithm: 'xz'
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
const filterCount = (flags & 0x03) + 1;
|
|
294
|
+
if (filterCount > 4) {
|
|
295
|
+
throw xzBadData('Invalid XZ filter count');
|
|
296
|
+
}
|
|
297
|
+
const hasCompressedSize = (flags & 0x40) !== 0;
|
|
298
|
+
const hasUncompressedSize = (flags & 0x80) !== 0;
|
|
299
|
+
let compressedSizeValue;
|
|
300
|
+
if (hasCompressedSize) {
|
|
301
|
+
const read = readVliFromBuffer(header, offset);
|
|
302
|
+
compressedSizeValue = read.value;
|
|
303
|
+
offset = read.offset;
|
|
304
|
+
}
|
|
305
|
+
let uncompressedSizeValue;
|
|
306
|
+
if (hasUncompressedSize) {
|
|
307
|
+
const read = readVliFromBuffer(header, offset);
|
|
308
|
+
uncompressedSizeValue = read.value;
|
|
309
|
+
offset = read.offset;
|
|
310
|
+
}
|
|
311
|
+
const filters = [];
|
|
312
|
+
for (let i = 0; i < filterCount; i += 1) {
|
|
313
|
+
const id = readVliFromBuffer(header, offset);
|
|
314
|
+
offset = id.offset;
|
|
315
|
+
const propsSize = readVliFromBuffer(header, offset);
|
|
316
|
+
offset = propsSize.offset;
|
|
317
|
+
const propsBytes = toNumberOrThrow(propsSize.value, 'Filter property size');
|
|
318
|
+
if (offset + propsBytes > header.length - 4) {
|
|
319
|
+
throw xzBadData('XZ filter properties exceed header size');
|
|
320
|
+
}
|
|
321
|
+
const props = header.subarray(offset, offset + propsBytes);
|
|
322
|
+
offset += propsBytes;
|
|
323
|
+
filters.push({ id: id.value, props });
|
|
324
|
+
}
|
|
325
|
+
for (let i = offset; i < header.length - 4; i += 1) {
|
|
326
|
+
if (header[i] !== 0x00) {
|
|
327
|
+
throw xzBadData('Non-zero bytes in XZ block header padding');
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
const { lzma2Props } = validateFilterChain(filters);
|
|
331
|
+
const dictionarySize = decodeDictionarySize(lzma2Props);
|
|
332
|
+
if (this.debug) {
|
|
333
|
+
const current = this.debug.maxDictionaryBytesUsed ?? 0;
|
|
334
|
+
if (dictionarySize > current)
|
|
335
|
+
this.debug.maxDictionaryBytesUsed = dictionarySize;
|
|
336
|
+
}
|
|
337
|
+
if (BigInt(dictionarySize) > this.options.maxDictionaryBytes) {
|
|
338
|
+
throw new CompressionError('COMPRESSION_RESOURCE_LIMIT', `XZ dictionary size ${dictionarySize} exceeds limit`, {
|
|
339
|
+
algorithm: 'xz',
|
|
340
|
+
context: {
|
|
341
|
+
requiredDictionaryBytes: String(dictionarySize),
|
|
342
|
+
limitDictionaryBytes: this.options.maxDictionaryBytes.toString()
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
const expectedCompressed = compressedSizeValue !== undefined ? toNumberOrThrow(compressedSizeValue, 'Compressed size') : undefined;
|
|
347
|
+
const expectedUncompressed = uncompressedSizeValue;
|
|
348
|
+
if (expectedCompressed !== undefined && expectedCompressed <= 0) {
|
|
349
|
+
throw xzBadData('Invalid XZ block compressed size');
|
|
350
|
+
}
|
|
351
|
+
const check = createCheck(this.checkType, this.skipCheck);
|
|
352
|
+
this.output.setCheck(check);
|
|
353
|
+
const outputStart = this.output.totalOut;
|
|
354
|
+
const filterSink = createFilterChain(filters.slice(0, -1), this.output);
|
|
355
|
+
const lzma2 = new Lzma2StreamDecoder(dictionarySize, filterSink, this.options.signal);
|
|
356
|
+
if (expectedCompressed !== undefined) {
|
|
357
|
+
lzma2.setCompressedLimit(expectedCompressed);
|
|
358
|
+
}
|
|
359
|
+
const block = {
|
|
360
|
+
headerSize,
|
|
361
|
+
compressedConsumed: 0,
|
|
362
|
+
outputStart,
|
|
363
|
+
check,
|
|
364
|
+
filterSink,
|
|
365
|
+
lzma2,
|
|
366
|
+
paddingBytes: 0,
|
|
367
|
+
...(expectedCompressed !== undefined ? { expectedCompressed } : {}),
|
|
368
|
+
...(expectedUncompressed !== undefined ? { expectedUncompressed } : {})
|
|
369
|
+
};
|
|
370
|
+
this.block = block;
|
|
371
|
+
this.state = 'block-data';
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
decodeBlockData() {
|
|
375
|
+
if (!this.block)
|
|
376
|
+
return false;
|
|
377
|
+
const done = this.block.lzma2.process(this.queue);
|
|
378
|
+
if (!done) {
|
|
379
|
+
if (this.queue.done)
|
|
380
|
+
throw xzTruncated('Truncated XZ block data');
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
this.block.filterSink.flush();
|
|
384
|
+
const compressedConsumed = this.block.lzma2.bytesConsumed;
|
|
385
|
+
this.block.compressedConsumed = compressedConsumed;
|
|
386
|
+
if (this.block.expectedCompressed !== undefined && compressedConsumed !== this.block.expectedCompressed) {
|
|
387
|
+
throw xzBadData('XZ block compressed size mismatch');
|
|
388
|
+
}
|
|
389
|
+
const actualUncompressed = this.output.totalOut - this.block.outputStart;
|
|
390
|
+
if (this.block.expectedUncompressed !== undefined && actualUncompressed !== this.block.expectedUncompressed) {
|
|
391
|
+
throw xzBadData('XZ block uncompressed size mismatch');
|
|
392
|
+
}
|
|
393
|
+
this.block.paddingBytes = (4 - (compressedConsumed % 4)) & 3;
|
|
394
|
+
this.state = 'block-padding';
|
|
395
|
+
return true;
|
|
396
|
+
}
|
|
397
|
+
readBlockPadding() {
|
|
398
|
+
if (!this.block)
|
|
399
|
+
return false;
|
|
400
|
+
if (this.block.paddingBytes === 0) {
|
|
401
|
+
this.state = 'block-check';
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
if (this.queue.length < this.block.paddingBytes) {
|
|
405
|
+
if (this.queue.done)
|
|
406
|
+
throw xzTruncated('Truncated XZ block padding');
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
const pad = this.queue.readBytes(this.block.paddingBytes);
|
|
410
|
+
for (const byte of pad) {
|
|
411
|
+
if (byte !== 0x00)
|
|
412
|
+
throw xzBadData('Non-zero bytes in XZ block padding');
|
|
413
|
+
}
|
|
414
|
+
this.state = 'block-check';
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
readBlockCheck() {
|
|
418
|
+
if (!this.block)
|
|
419
|
+
return false;
|
|
420
|
+
if (this.checkSize > 0) {
|
|
421
|
+
if (this.queue.length < this.checkSize) {
|
|
422
|
+
if (this.queue.done)
|
|
423
|
+
throw xzTruncated('Truncated XZ block check');
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
const stored = this.queue.readBytes(this.checkSize);
|
|
427
|
+
if (!this.skipCheck) {
|
|
428
|
+
const computed = this.block.check?.digestBytes() ?? new Uint8Array();
|
|
429
|
+
if (!matches(stored, computed)) {
|
|
430
|
+
throw new CompressionError('COMPRESSION_XZ_BAD_CHECK', 'XZ check mismatch', {
|
|
431
|
+
algorithm: 'xz',
|
|
432
|
+
context: { check: describeCheck(this.checkType) }
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
this.output.clearCheck();
|
|
438
|
+
const unpaddedSize = BigInt(this.block.headerSize + this.block.compressedConsumed + this.checkSize);
|
|
439
|
+
const uncompressedSize = this.output.totalOut - this.block.outputStart;
|
|
440
|
+
this.blocks.push({ unpaddedSize, uncompressedSize });
|
|
441
|
+
this.block = null;
|
|
442
|
+
this.state = 'block-header';
|
|
443
|
+
return true;
|
|
444
|
+
}
|
|
445
|
+
decodeIndex() {
|
|
446
|
+
if (!this.index) {
|
|
447
|
+
this.index = {
|
|
448
|
+
startOffset: this.queue.totalRead,
|
|
449
|
+
crc: new Crc32(),
|
|
450
|
+
recordCount: null,
|
|
451
|
+
recordsRead: 0,
|
|
452
|
+
paddingRemaining: null,
|
|
453
|
+
indicatorRead: false,
|
|
454
|
+
pendingUnpadded: null
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
const index = this.index;
|
|
458
|
+
if (index.recordCount === null) {
|
|
459
|
+
if (!index.indicatorRead) {
|
|
460
|
+
const indicator = this.queue.readByte();
|
|
461
|
+
if (indicator === null) {
|
|
462
|
+
if (this.queue.done)
|
|
463
|
+
throw xzTruncated('Missing XZ index indicator');
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
if (indicator !== 0x00) {
|
|
467
|
+
throw xzBadData('Missing XZ index indicator');
|
|
468
|
+
}
|
|
469
|
+
index.crc.update(new Uint8Array([indicator]));
|
|
470
|
+
index.indicatorRead = true;
|
|
471
|
+
}
|
|
472
|
+
const vli = tryReadVliWithBytes(this.queue);
|
|
473
|
+
if (!vli) {
|
|
474
|
+
if (this.queue.done)
|
|
475
|
+
throw xzTruncated('Truncated XZ index');
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
index.crc.update(vli.bytes);
|
|
479
|
+
index.recordCount = toNumberOrThrow(vli.value, 'Index record count');
|
|
480
|
+
if (index.recordCount !== this.blocks.length) {
|
|
481
|
+
throw xzBadData('XZ index record count mismatch');
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
while (index.recordsRead < index.recordCount) {
|
|
485
|
+
let unpadded = index.pendingUnpadded;
|
|
486
|
+
if (!unpadded) {
|
|
487
|
+
const read = tryReadVliWithBytes(this.queue);
|
|
488
|
+
if (!read) {
|
|
489
|
+
if (this.queue.done)
|
|
490
|
+
throw xzTruncated('Truncated XZ index record');
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
index.crc.update(read.bytes);
|
|
494
|
+
unpadded = read;
|
|
495
|
+
index.pendingUnpadded = read;
|
|
496
|
+
}
|
|
497
|
+
const uncompressed = tryReadVliWithBytes(this.queue);
|
|
498
|
+
if (!uncompressed) {
|
|
499
|
+
if (this.queue.done)
|
|
500
|
+
throw xzTruncated('Truncated XZ index record');
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
index.crc.update(uncompressed.bytes);
|
|
504
|
+
const expected = this.blocks[index.recordsRead];
|
|
505
|
+
if (unpadded.value !== expected.unpaddedSize || uncompressed.value !== expected.uncompressedSize) {
|
|
506
|
+
throw xzBadData('XZ index entries do not match decoded blocks');
|
|
507
|
+
}
|
|
508
|
+
index.recordsRead += 1;
|
|
509
|
+
index.pendingUnpadded = null;
|
|
510
|
+
}
|
|
511
|
+
if (index.paddingRemaining === null) {
|
|
512
|
+
const bytesSoFar = this.queue.totalRead - index.startOffset;
|
|
513
|
+
index.paddingRemaining = (4 - (bytesSoFar % 4)) & 3;
|
|
514
|
+
}
|
|
515
|
+
while (index.paddingRemaining > 0) {
|
|
516
|
+
const byte = this.queue.readByte();
|
|
517
|
+
if (byte === null) {
|
|
518
|
+
if (this.queue.done)
|
|
519
|
+
throw xzTruncated('Truncated XZ index padding');
|
|
520
|
+
return false;
|
|
521
|
+
}
|
|
522
|
+
index.crc.update(new Uint8Array([byte]));
|
|
523
|
+
if (byte !== 0x00)
|
|
524
|
+
throw xzBadData('Non-zero bytes in XZ index padding');
|
|
525
|
+
index.paddingRemaining -= 1;
|
|
526
|
+
}
|
|
527
|
+
if (this.queue.length < 4) {
|
|
528
|
+
if (this.queue.done)
|
|
529
|
+
throw xzTruncated('Truncated XZ index');
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
const storedBytes = this.queue.readBytes(4);
|
|
533
|
+
const storedCrc = readUint32LE(storedBytes, 0);
|
|
534
|
+
if (index.crc.digest() !== storedCrc) {
|
|
535
|
+
throw xzBadData('XZ index CRC mismatch');
|
|
536
|
+
}
|
|
537
|
+
this.indexSize = this.queue.totalRead - index.startOffset;
|
|
538
|
+
this.index = null;
|
|
539
|
+
this.state = 'footer';
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
decodeFooter() {
|
|
543
|
+
if (this.queue.length < 12) {
|
|
544
|
+
if (this.queue.done)
|
|
545
|
+
throw xzTruncated('Truncated XZ stream footer');
|
|
546
|
+
return false;
|
|
547
|
+
}
|
|
548
|
+
const footer = this.queue.readBytes(12);
|
|
549
|
+
const storedCrc = readUint32LE(footer, 0);
|
|
550
|
+
const backwardSize = readUint32LE(footer, 4);
|
|
551
|
+
const flags = footer.subarray(8, 10);
|
|
552
|
+
const magic = footer.subarray(10, 12);
|
|
553
|
+
if (!matches(magic, FOOTER_MAGIC)) {
|
|
554
|
+
throw xzBadData('Invalid XZ footer magic');
|
|
555
|
+
}
|
|
556
|
+
if (!matches(flags, this.streamFlags)) {
|
|
557
|
+
throw xzBadData('XZ stream footer flags mismatch');
|
|
558
|
+
}
|
|
559
|
+
const crc = new Crc32();
|
|
560
|
+
crc.update(footer.subarray(4, 10));
|
|
561
|
+
if (crc.digest() !== storedCrc) {
|
|
562
|
+
throw xzBadData('XZ stream footer CRC mismatch');
|
|
563
|
+
}
|
|
564
|
+
const realBackwardSize = (backwardSize + 1) * 4;
|
|
565
|
+
if (realBackwardSize !== this.indexSize) {
|
|
566
|
+
throw xzBadData('XZ backward size mismatch');
|
|
567
|
+
}
|
|
568
|
+
this.streamPaddingRemaining = null;
|
|
569
|
+
this.state = 'stream-padding';
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
decodeStreamPadding() {
|
|
573
|
+
if (this.streamPaddingRemaining === null) {
|
|
574
|
+
const streamBytes = this.queue.totalRead - this.streamStartOffset;
|
|
575
|
+
this.streamPaddingRemaining = (4 - (streamBytes % 4)) & 3;
|
|
576
|
+
}
|
|
577
|
+
while (this.streamPaddingRemaining > 0) {
|
|
578
|
+
const byte = this.queue.readByte();
|
|
579
|
+
if (byte === null) {
|
|
580
|
+
if (this.queue.done)
|
|
581
|
+
throw xzTruncated('Truncated XZ stream padding');
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
if (byte !== 0x00) {
|
|
585
|
+
throw xzBadData('Non-zero bytes found after XZ stream');
|
|
586
|
+
}
|
|
587
|
+
this.streamPaddingRemaining -= 1;
|
|
588
|
+
}
|
|
589
|
+
while (true) {
|
|
590
|
+
if (this.queue.length < 4) {
|
|
591
|
+
if (this.queue.done) {
|
|
592
|
+
if (this.queue.length === 0) {
|
|
593
|
+
this.state = 'done';
|
|
594
|
+
this.done = true;
|
|
595
|
+
return true;
|
|
596
|
+
}
|
|
597
|
+
const tail = this.queue.readBytes(this.queue.length);
|
|
598
|
+
for (const byte of tail) {
|
|
599
|
+
if (byte !== 0x00) {
|
|
600
|
+
throw xzBadData('Non-zero bytes found after XZ stream');
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
throw xzBadData('Invalid XZ stream padding length');
|
|
604
|
+
}
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
const padding = this.queue.peekBytes(4);
|
|
608
|
+
if (padding[0] === 0x00 && padding[1] === 0x00 && padding[2] === 0x00 && padding[3] === 0x00) {
|
|
609
|
+
this.queue.readBytes(4);
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
this.streamPaddingRemaining = null;
|
|
613
|
+
this.state = 'stream-header';
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
class ByteQueue {
|
|
619
|
+
debug;
|
|
620
|
+
chunks = [];
|
|
621
|
+
offset = 0;
|
|
622
|
+
length = 0;
|
|
623
|
+
totalRead = 0;
|
|
624
|
+
done = false;
|
|
625
|
+
maxBuffered = 0;
|
|
626
|
+
constructor(debug) {
|
|
627
|
+
this.debug = debug;
|
|
628
|
+
}
|
|
629
|
+
push(chunk) {
|
|
630
|
+
if (!chunk || chunk.length === 0)
|
|
631
|
+
return;
|
|
632
|
+
this.chunks.push(chunk);
|
|
633
|
+
this.length += chunk.length;
|
|
634
|
+
if (this.length > this.maxBuffered) {
|
|
635
|
+
this.maxBuffered = this.length;
|
|
636
|
+
if (this.debug)
|
|
637
|
+
this.debug.maxBufferedInputBytes = this.maxBuffered;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
markDone() {
|
|
641
|
+
this.done = true;
|
|
642
|
+
}
|
|
643
|
+
peekByte() {
|
|
644
|
+
if (this.length === 0)
|
|
645
|
+
return null;
|
|
646
|
+
const chunk = this.chunks[0];
|
|
647
|
+
return chunk[this.offset];
|
|
648
|
+
}
|
|
649
|
+
readByte() {
|
|
650
|
+
if (this.length === 0)
|
|
651
|
+
return null;
|
|
652
|
+
const chunk = this.chunks[0];
|
|
653
|
+
const value = chunk[this.offset];
|
|
654
|
+
this.offset += 1;
|
|
655
|
+
this.length -= 1;
|
|
656
|
+
this.totalRead += 1;
|
|
657
|
+
if (this.offset >= chunk.length) {
|
|
658
|
+
this.chunks.shift();
|
|
659
|
+
this.offset = 0;
|
|
660
|
+
}
|
|
661
|
+
return value;
|
|
662
|
+
}
|
|
663
|
+
readBytes(length) {
|
|
664
|
+
if (length === 0)
|
|
665
|
+
return new Uint8Array(0);
|
|
666
|
+
if (this.length < length)
|
|
667
|
+
return null;
|
|
668
|
+
const first = this.chunks[0];
|
|
669
|
+
const available = first.length - this.offset;
|
|
670
|
+
if (available >= length) {
|
|
671
|
+
const out = first.subarray(this.offset, this.offset + length);
|
|
672
|
+
this.offset += length;
|
|
673
|
+
this.length -= length;
|
|
674
|
+
this.totalRead += length;
|
|
675
|
+
if (this.offset >= first.length) {
|
|
676
|
+
this.chunks.shift();
|
|
677
|
+
this.offset = 0;
|
|
678
|
+
}
|
|
679
|
+
return out;
|
|
680
|
+
}
|
|
681
|
+
const out = new Uint8Array(length);
|
|
682
|
+
let offset = 0;
|
|
683
|
+
let remaining = length;
|
|
684
|
+
while (remaining > 0) {
|
|
685
|
+
const chunk = this.chunks[0];
|
|
686
|
+
const take = Math.min(chunk.length - this.offset, remaining);
|
|
687
|
+
out.set(chunk.subarray(this.offset, this.offset + take), offset);
|
|
688
|
+
this.offset += take;
|
|
689
|
+
this.length -= take;
|
|
690
|
+
this.totalRead += take;
|
|
691
|
+
offset += take;
|
|
692
|
+
remaining -= take;
|
|
693
|
+
if (this.offset >= chunk.length) {
|
|
694
|
+
this.chunks.shift();
|
|
695
|
+
this.offset = 0;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return out;
|
|
699
|
+
}
|
|
700
|
+
peekBytes(length) {
|
|
701
|
+
if (length === 0)
|
|
702
|
+
return new Uint8Array(0);
|
|
703
|
+
if (this.length < length)
|
|
704
|
+
return null;
|
|
705
|
+
const out = new Uint8Array(length);
|
|
706
|
+
let offset = 0;
|
|
707
|
+
let remaining = length;
|
|
708
|
+
let chunkIndex = 0;
|
|
709
|
+
let chunkOffset = this.offset;
|
|
710
|
+
while (remaining > 0) {
|
|
711
|
+
const chunk = this.chunks[chunkIndex];
|
|
712
|
+
const take = Math.min(chunk.length - chunkOffset, remaining);
|
|
713
|
+
out.set(chunk.subarray(chunkOffset, chunkOffset + take), offset);
|
|
714
|
+
offset += take;
|
|
715
|
+
remaining -= take;
|
|
716
|
+
chunkIndex += 1;
|
|
717
|
+
chunkOffset = 0;
|
|
718
|
+
}
|
|
719
|
+
return out;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
class Lzma2StreamDecoder {
|
|
723
|
+
needDictionaryReset = true;
|
|
724
|
+
needProperties = true;
|
|
725
|
+
dict;
|
|
726
|
+
lzma;
|
|
727
|
+
state = 'control';
|
|
728
|
+
control = 0;
|
|
729
|
+
uncompressedSize = 0;
|
|
730
|
+
compressedSize = 0;
|
|
731
|
+
expectedCompressed;
|
|
732
|
+
compressedConsumed = 0;
|
|
733
|
+
constructor(dictionarySize, output, signal) {
|
|
734
|
+
this.dict = new Dictionary(dictionarySize, output, signal);
|
|
735
|
+
this.lzma = new LzmaDecoder(this.dict, signal);
|
|
736
|
+
}
|
|
737
|
+
setCompressedLimit(limit) {
|
|
738
|
+
this.expectedCompressed = limit;
|
|
739
|
+
}
|
|
740
|
+
get bytesConsumed() {
|
|
741
|
+
return this.compressedConsumed;
|
|
742
|
+
}
|
|
743
|
+
process(queue) {
|
|
744
|
+
while (true) {
|
|
745
|
+
if (this.state === 'control') {
|
|
746
|
+
const control = this.readByte(queue);
|
|
747
|
+
if (control === null)
|
|
748
|
+
return false;
|
|
749
|
+
this.control = control;
|
|
750
|
+
if (control === 0x00)
|
|
751
|
+
return true;
|
|
752
|
+
if (control >= 0xe0 || control === 0x01) {
|
|
753
|
+
this.needProperties = true;
|
|
754
|
+
this.needDictionaryReset = true;
|
|
755
|
+
}
|
|
756
|
+
else if (this.needDictionaryReset) {
|
|
757
|
+
throw lzmaBadData('LZMA2 dictionary reset missing');
|
|
758
|
+
}
|
|
759
|
+
this.state = control >= 0x80 ? 'lzma-header' : 'uncompressed-header';
|
|
760
|
+
}
|
|
761
|
+
if (this.state === 'lzma-header') {
|
|
762
|
+
const needsProps = this.control >= 0xc0;
|
|
763
|
+
const header = this.readBytes(queue, needsProps ? 5 : 4);
|
|
764
|
+
if (!header)
|
|
765
|
+
return false;
|
|
766
|
+
const control = this.control;
|
|
767
|
+
const uncompressedSize = (((control & 0x1f) << 16) | (header[0] << 8) | header[1]) + 1;
|
|
768
|
+
const compressedSize = ((header[2] << 8) | header[3]) + 1;
|
|
769
|
+
if (compressedSize <= 0)
|
|
770
|
+
throw lzmaBadData('Invalid LZMA2 compressed size');
|
|
771
|
+
if (needsProps) {
|
|
772
|
+
const props = header[4];
|
|
773
|
+
this.lzma.resetProperties(props);
|
|
774
|
+
this.needProperties = false;
|
|
775
|
+
}
|
|
776
|
+
else if (this.needProperties) {
|
|
777
|
+
throw lzmaBadData('Missing LZMA2 properties');
|
|
778
|
+
}
|
|
779
|
+
else if (control >= 0xa0) {
|
|
780
|
+
this.lzma.resetState();
|
|
781
|
+
}
|
|
782
|
+
if (this.needDictionaryReset) {
|
|
783
|
+
this.dict.reset();
|
|
784
|
+
this.needDictionaryReset = false;
|
|
785
|
+
}
|
|
786
|
+
this.uncompressedSize = uncompressedSize;
|
|
787
|
+
this.compressedSize = compressedSize;
|
|
788
|
+
this.state = 'lzma-data';
|
|
789
|
+
}
|
|
790
|
+
if (this.state === 'lzma-data') {
|
|
791
|
+
const data = this.readBytes(queue, this.compressedSize);
|
|
792
|
+
if (!data)
|
|
793
|
+
return false;
|
|
794
|
+
const range = new RangeDecoder(data, 0, this.compressedSize);
|
|
795
|
+
this.lzma.decode(range, this.uncompressedSize);
|
|
796
|
+
if (range.position !== range.limit) {
|
|
797
|
+
throw lzmaBadData('LZMA2 chunk has unused compressed bytes');
|
|
798
|
+
}
|
|
799
|
+
this.state = 'control';
|
|
800
|
+
}
|
|
801
|
+
if (this.state === 'uncompressed-header') {
|
|
802
|
+
const header = this.readBytes(queue, 2);
|
|
803
|
+
if (!header)
|
|
804
|
+
return false;
|
|
805
|
+
const control = this.control;
|
|
806
|
+
if (control > 0x02)
|
|
807
|
+
throw lzmaBadData('Invalid LZMA2 control byte');
|
|
808
|
+
const size = ((header[0] << 8) | header[1]) + 1;
|
|
809
|
+
if (this.needDictionaryReset) {
|
|
810
|
+
this.dict.reset();
|
|
811
|
+
this.needDictionaryReset = false;
|
|
812
|
+
}
|
|
813
|
+
this.uncompressedSize = size;
|
|
814
|
+
this.state = 'uncompressed-data';
|
|
815
|
+
}
|
|
816
|
+
if (this.state === 'uncompressed-data') {
|
|
817
|
+
const data = this.readBytes(queue, this.uncompressedSize);
|
|
818
|
+
if (!data)
|
|
819
|
+
return false;
|
|
820
|
+
this.dict.copyUncompressed(data);
|
|
821
|
+
this.state = 'control';
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
readByte(queue) {
|
|
826
|
+
if (this.expectedCompressed !== undefined && this.compressedConsumed >= this.expectedCompressed) {
|
|
827
|
+
throw xzBadData('XZ block compressed size mismatch');
|
|
828
|
+
}
|
|
829
|
+
const byte = queue.readByte();
|
|
830
|
+
if (byte === null)
|
|
831
|
+
return null;
|
|
832
|
+
this.compressedConsumed += 1;
|
|
833
|
+
return byte;
|
|
834
|
+
}
|
|
835
|
+
readBytes(queue, length) {
|
|
836
|
+
if (this.expectedCompressed !== undefined && this.compressedConsumed + length > this.expectedCompressed) {
|
|
837
|
+
throw xzBadData('XZ block compressed size mismatch');
|
|
838
|
+
}
|
|
839
|
+
const bytes = queue.readBytes(length);
|
|
840
|
+
if (!bytes)
|
|
841
|
+
return null;
|
|
842
|
+
this.compressedConsumed += length;
|
|
843
|
+
return bytes;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
class LzmaDecoder {
|
|
847
|
+
dict;
|
|
848
|
+
signal;
|
|
849
|
+
lc = 0;
|
|
850
|
+
lp = 0;
|
|
851
|
+
pb = 0;
|
|
852
|
+
state = 0;
|
|
853
|
+
reps = [0, 0, 0, 0];
|
|
854
|
+
isMatch = new Uint16Array(K_NUM_STATES * K_NUM_POS_STATES_MAX);
|
|
855
|
+
isRep = new Uint16Array(K_NUM_STATES);
|
|
856
|
+
isRepG0 = new Uint16Array(K_NUM_STATES);
|
|
857
|
+
isRepG1 = new Uint16Array(K_NUM_STATES);
|
|
858
|
+
isRepG2 = new Uint16Array(K_NUM_STATES);
|
|
859
|
+
isRep0Long = new Uint16Array(K_NUM_STATES * K_NUM_POS_STATES_MAX);
|
|
860
|
+
posSlot = new Uint16Array(K_NUM_LEN_TO_POS_STATES * (1 << K_NUM_POS_SLOT_BITS));
|
|
861
|
+
posDecoders = new Uint16Array(K_NUM_FULL_DISTANCES);
|
|
862
|
+
align = new Uint16Array(1 << K_NUM_ALIGN_BITS);
|
|
863
|
+
lenDecoder = new LenDecoder();
|
|
864
|
+
repLenDecoder = new LenDecoder();
|
|
865
|
+
literalProbs = new Uint16Array(0);
|
|
866
|
+
constructor(dict, signal) {
|
|
867
|
+
this.dict = dict;
|
|
868
|
+
this.signal = signal;
|
|
869
|
+
}
|
|
870
|
+
resetProperties(props) {
|
|
871
|
+
const lc = props % 9;
|
|
872
|
+
let rest = Math.floor(props / 9);
|
|
873
|
+
const lp = rest % 5;
|
|
874
|
+
const pb = Math.floor(rest / 5);
|
|
875
|
+
if (pb > 4)
|
|
876
|
+
throw lzmaBadData('Invalid LZMA properties');
|
|
877
|
+
if (lc + lp > 4)
|
|
878
|
+
throw lzmaBadData('Unsupported LZMA2 properties (lc + lp > 4)');
|
|
879
|
+
this.lc = lc;
|
|
880
|
+
this.lp = lp;
|
|
881
|
+
this.pb = pb;
|
|
882
|
+
this.literalProbs = new Uint16Array(0x300 << (lc + lp));
|
|
883
|
+
initProbs(this.literalProbs);
|
|
884
|
+
initProbs(this.isMatch);
|
|
885
|
+
initProbs(this.isRep);
|
|
886
|
+
initProbs(this.isRepG0);
|
|
887
|
+
initProbs(this.isRepG1);
|
|
888
|
+
initProbs(this.isRepG2);
|
|
889
|
+
initProbs(this.isRep0Long);
|
|
890
|
+
initProbs(this.posSlot);
|
|
891
|
+
initProbs(this.posDecoders);
|
|
892
|
+
initProbs(this.align);
|
|
893
|
+
this.lenDecoder.reset();
|
|
894
|
+
this.repLenDecoder.reset();
|
|
895
|
+
this.resetState();
|
|
896
|
+
}
|
|
897
|
+
resetState() {
|
|
898
|
+
this.state = 0;
|
|
899
|
+
this.reps = [0, 0, 0, 0];
|
|
900
|
+
}
|
|
901
|
+
decode(range, expectedOutput) {
|
|
902
|
+
const target = this.dict.written + expectedOutput;
|
|
903
|
+
const pbMask = (1 << this.pb) - 1;
|
|
904
|
+
while (this.dict.written < target) {
|
|
905
|
+
if (this.signal && (this.dict.written & 0x3fff) === 0) {
|
|
906
|
+
throwIfAborted(this.signal);
|
|
907
|
+
}
|
|
908
|
+
const posState = this.dict.written & pbMask;
|
|
909
|
+
const stateIndex = this.state << K_NUM_POS_BITS_MAX;
|
|
910
|
+
const isMatch = range.decodeBit(this.isMatch, stateIndex + posState);
|
|
911
|
+
if (isMatch === 0) {
|
|
912
|
+
const prevByte = this.dict.getPrevByte();
|
|
913
|
+
const context = ((this.dict.written & ((1 << this.lp) - 1)) << this.lc) + (prevByte >> (8 - this.lc));
|
|
914
|
+
const base = context * 0x300;
|
|
915
|
+
const symbol = this.state < K_NUM_LIT_STATES
|
|
916
|
+
? decodeLiteral(range, this.literalProbs, base)
|
|
917
|
+
: decodeMatchedLiteral(range, this.literalProbs, base, this.dict.getByte(this.reps[0] + 1));
|
|
918
|
+
if (this.dict.written + 1 > target)
|
|
919
|
+
throw lzmaBadData('LZMA output exceeds expected size');
|
|
920
|
+
this.dict.putByte(symbol);
|
|
921
|
+
this.state = updateStateLiteral(this.state);
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
const isRep = range.decodeBit(this.isRep, this.state);
|
|
925
|
+
let length;
|
|
926
|
+
if (isRep === 1) {
|
|
927
|
+
if (range.decodeBit(this.isRepG0, this.state) === 0) {
|
|
928
|
+
if (range.decodeBit(this.isRep0Long, stateIndex + posState) === 0) {
|
|
929
|
+
if (this.dict.written + 1 > target)
|
|
930
|
+
throw lzmaBadData('LZMA output exceeds expected size');
|
|
931
|
+
this.dict.putByte(this.dict.getByte(this.reps[0] + 1));
|
|
932
|
+
this.state = updateStateShortRep(this.state);
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
let distance;
|
|
938
|
+
const [rep0, rep1, rep2, rep3] = this.reps;
|
|
939
|
+
if (range.decodeBit(this.isRepG1, this.state) === 0) {
|
|
940
|
+
distance = rep1;
|
|
941
|
+
this.reps = [distance, rep0, rep2, rep3];
|
|
942
|
+
}
|
|
943
|
+
else if (range.decodeBit(this.isRepG2, this.state) === 0) {
|
|
944
|
+
distance = rep2;
|
|
945
|
+
this.reps = [distance, rep0, rep1, rep3];
|
|
946
|
+
}
|
|
947
|
+
else {
|
|
948
|
+
distance = rep3;
|
|
949
|
+
this.reps = [distance, rep0, rep1, rep2];
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
length = this.repLenDecoder.decode(range, posState) + K_MATCH_MIN_LEN;
|
|
953
|
+
this.state = updateStateRep(this.state);
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
length = this.lenDecoder.decode(range, posState) + K_MATCH_MIN_LEN;
|
|
957
|
+
const lenToPosState = (length - K_MATCH_MIN_LEN) < K_NUM_LEN_TO_POS_STATES ? length - K_MATCH_MIN_LEN : K_NUM_LEN_TO_POS_STATES - 1;
|
|
958
|
+
const posSlot = decodeBitTree(range, this.posSlot, lenToPosState << K_NUM_POS_SLOT_BITS, K_NUM_POS_SLOT_BITS);
|
|
959
|
+
let distance;
|
|
960
|
+
if (posSlot < 4) {
|
|
961
|
+
distance = posSlot;
|
|
962
|
+
}
|
|
963
|
+
else {
|
|
964
|
+
const directBits = (posSlot >> 1) - 1;
|
|
965
|
+
distance = (2 | (posSlot & 1)) << directBits;
|
|
966
|
+
if (posSlot < K_END_POS_MODEL_INDEX) {
|
|
967
|
+
distance += decodeReverseBitTree(range, this.posDecoders, distance - posSlot, directBits);
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
distance += range.decodeDirectBits(directBits - K_NUM_ALIGN_BITS) << K_NUM_ALIGN_BITS;
|
|
971
|
+
distance += decodeReverseBitTree(range, this.align, 0, K_NUM_ALIGN_BITS);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
this.reps = [distance, this.reps[0], this.reps[1], this.reps[2]];
|
|
975
|
+
this.state = updateStateMatch(this.state);
|
|
976
|
+
}
|
|
977
|
+
if (this.dict.written + length > target) {
|
|
978
|
+
throw lzmaBadData('LZMA output exceeds expected size');
|
|
979
|
+
}
|
|
980
|
+
this.dict.copyMatch(this.reps[0] + 1, length);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
class LenDecoder {
|
|
985
|
+
choice = new Uint16Array(2);
|
|
986
|
+
low = new Uint16Array(K_NUM_POS_STATES_MAX << K_LEN_NUM_LOW_BITS);
|
|
987
|
+
mid = new Uint16Array(K_NUM_POS_STATES_MAX << K_LEN_NUM_LOW_BITS);
|
|
988
|
+
high = new Uint16Array(K_LEN_NUM_HIGH_SYMBOLS);
|
|
989
|
+
reset() {
|
|
990
|
+
initProbs(this.choice);
|
|
991
|
+
initProbs(this.low);
|
|
992
|
+
initProbs(this.mid);
|
|
993
|
+
initProbs(this.high);
|
|
994
|
+
}
|
|
995
|
+
decode(range, posState) {
|
|
996
|
+
if (range.decodeBit(this.choice, 0) === 0) {
|
|
997
|
+
return decodeBitTree(range, this.low, posState << K_LEN_NUM_LOW_BITS, K_LEN_NUM_LOW_BITS);
|
|
998
|
+
}
|
|
999
|
+
if (range.decodeBit(this.choice, 1) === 0) {
|
|
1000
|
+
return K_LEN_NUM_LOW_SYMBOLS + decodeBitTree(range, this.mid, posState << K_LEN_NUM_LOW_BITS, K_LEN_NUM_LOW_BITS);
|
|
1001
|
+
}
|
|
1002
|
+
return K_LEN_NUM_LOW_SYMBOLS * 2 + decodeBitTree(range, this.high, 0, K_LEN_NUM_HIGH_BITS);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
class Dictionary {
|
|
1006
|
+
output;
|
|
1007
|
+
signal;
|
|
1008
|
+
buffer;
|
|
1009
|
+
pos = 0;
|
|
1010
|
+
full = false;
|
|
1011
|
+
written = 0;
|
|
1012
|
+
byteCounter = 0;
|
|
1013
|
+
constructor(size, output, signal) {
|
|
1014
|
+
this.output = output;
|
|
1015
|
+
this.signal = signal;
|
|
1016
|
+
this.buffer = new Uint8Array(size);
|
|
1017
|
+
}
|
|
1018
|
+
reset() {
|
|
1019
|
+
this.pos = 0;
|
|
1020
|
+
this.full = false;
|
|
1021
|
+
this.written = 0;
|
|
1022
|
+
}
|
|
1023
|
+
getPrevByte() {
|
|
1024
|
+
if (this.written === 0)
|
|
1025
|
+
return 0;
|
|
1026
|
+
const index = this.pos === 0 ? this.buffer.length - 1 : this.pos - 1;
|
|
1027
|
+
return this.buffer[index];
|
|
1028
|
+
}
|
|
1029
|
+
getByte(distance) {
|
|
1030
|
+
if (distance <= 0 || distance > this.buffer.length) {
|
|
1031
|
+
throw lzmaBadData(`LZMA distance out of range (distance=${distance}, size=${this.buffer.length})`);
|
|
1032
|
+
}
|
|
1033
|
+
if (!this.full && distance > this.pos) {
|
|
1034
|
+
throw lzmaBadData(`LZMA distance exceeds dictionary (distance=${distance}, pos=${this.pos})`);
|
|
1035
|
+
}
|
|
1036
|
+
let index = this.pos - distance;
|
|
1037
|
+
if (index < 0)
|
|
1038
|
+
index += this.buffer.length;
|
|
1039
|
+
return this.buffer[index];
|
|
1040
|
+
}
|
|
1041
|
+
putByte(value) {
|
|
1042
|
+
this.buffer[this.pos] = value;
|
|
1043
|
+
this.pos += 1;
|
|
1044
|
+
if (this.pos >= this.buffer.length) {
|
|
1045
|
+
this.pos = 0;
|
|
1046
|
+
this.full = true;
|
|
1047
|
+
}
|
|
1048
|
+
this.written += 1;
|
|
1049
|
+
this.output.writeByte(value);
|
|
1050
|
+
this.checkAbort();
|
|
1051
|
+
}
|
|
1052
|
+
copyMatch(distance, length) {
|
|
1053
|
+
if (distance <= 0 || distance > this.buffer.length) {
|
|
1054
|
+
throw lzmaBadData('LZMA distance out of range');
|
|
1055
|
+
}
|
|
1056
|
+
if (!this.full && distance > this.pos) {
|
|
1057
|
+
throw lzmaBadData('LZMA distance exceeds dictionary');
|
|
1058
|
+
}
|
|
1059
|
+
let src = this.pos - distance;
|
|
1060
|
+
if (src < 0)
|
|
1061
|
+
src += this.buffer.length;
|
|
1062
|
+
for (let i = 0; i < length; i += 1) {
|
|
1063
|
+
const value = this.buffer[src];
|
|
1064
|
+
this.buffer[this.pos] = value;
|
|
1065
|
+
this.pos += 1;
|
|
1066
|
+
if (this.pos >= this.buffer.length) {
|
|
1067
|
+
this.pos = 0;
|
|
1068
|
+
this.full = true;
|
|
1069
|
+
}
|
|
1070
|
+
src += 1;
|
|
1071
|
+
if (src >= this.buffer.length)
|
|
1072
|
+
src = 0;
|
|
1073
|
+
this.written += 1;
|
|
1074
|
+
this.output.writeByte(value);
|
|
1075
|
+
this.checkAbort();
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
copyUncompressed(chunk) {
|
|
1079
|
+
for (let i = 0; i < chunk.length; i += 1) {
|
|
1080
|
+
this.buffer[this.pos] = chunk[i];
|
|
1081
|
+
this.pos += 1;
|
|
1082
|
+
if (this.pos >= this.buffer.length) {
|
|
1083
|
+
this.pos = 0;
|
|
1084
|
+
this.full = true;
|
|
1085
|
+
}
|
|
1086
|
+
this.written += 1;
|
|
1087
|
+
this.output.writeByte(chunk[i]);
|
|
1088
|
+
this.checkAbort();
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
checkAbort() {
|
|
1092
|
+
if (!this.signal)
|
|
1093
|
+
return;
|
|
1094
|
+
this.byteCounter = (this.byteCounter + 1) & 0x3fff;
|
|
1095
|
+
if (this.byteCounter === 0)
|
|
1096
|
+
throwIfAborted(this.signal);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
class OutputSink {
|
|
1100
|
+
emit;
|
|
1101
|
+
options;
|
|
1102
|
+
debug;
|
|
1103
|
+
buffer = new Uint8Array(OUTPUT_CHUNK_SIZE);
|
|
1104
|
+
length = 0;
|
|
1105
|
+
bytesOut = 0n;
|
|
1106
|
+
check = null;
|
|
1107
|
+
constructor(emit, options, debug) {
|
|
1108
|
+
this.emit = emit;
|
|
1109
|
+
this.options = options;
|
|
1110
|
+
this.debug = debug;
|
|
1111
|
+
}
|
|
1112
|
+
get totalOut() {
|
|
1113
|
+
return this.bytesOut;
|
|
1114
|
+
}
|
|
1115
|
+
setCheck(check) {
|
|
1116
|
+
this.check = check;
|
|
1117
|
+
}
|
|
1118
|
+
clearCheck() {
|
|
1119
|
+
this.check = null;
|
|
1120
|
+
}
|
|
1121
|
+
writeByte(value) {
|
|
1122
|
+
this.buffer[this.length++] = value;
|
|
1123
|
+
this.bytesOut += 1n;
|
|
1124
|
+
if (this.debug)
|
|
1125
|
+
this.debug.totalBytesOut = Number(this.bytesOut);
|
|
1126
|
+
this.ensureLimits();
|
|
1127
|
+
if (this.length >= this.buffer.length)
|
|
1128
|
+
this.flush();
|
|
1129
|
+
}
|
|
1130
|
+
flush() {
|
|
1131
|
+
if (this.length === 0)
|
|
1132
|
+
return;
|
|
1133
|
+
const chunk = this.buffer.subarray(0, this.length);
|
|
1134
|
+
this.check?.update(chunk);
|
|
1135
|
+
this.emit(chunk);
|
|
1136
|
+
this.length = 0;
|
|
1137
|
+
if (this.debug)
|
|
1138
|
+
this.debug.totalBytesOut = Number(this.bytesOut);
|
|
1139
|
+
}
|
|
1140
|
+
ensureLimits() {
|
|
1141
|
+
if (this.options.maxOutputBytes !== undefined && this.bytesOut > this.options.maxOutputBytes) {
|
|
1142
|
+
throw new CompressionError('COMPRESSION_XZ_LIMIT_EXCEEDED', 'XZ output exceeds maxOutputBytes', {
|
|
1143
|
+
algorithm: 'xz'
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
if (this.options.signal && (this.bytesOut & 0x3fffn) === 0n) {
|
|
1147
|
+
throwIfAborted(this.options.signal);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
verifyRatio(totalIn, maxCompressionRatio) {
|
|
1151
|
+
if (!maxCompressionRatio || maxCompressionRatio <= 0)
|
|
1152
|
+
return;
|
|
1153
|
+
const limit = BigInt(Math.ceil(totalIn * maxCompressionRatio));
|
|
1154
|
+
if (this.bytesOut > limit) {
|
|
1155
|
+
throw new CompressionError('COMPRESSION_XZ_LIMIT_EXCEEDED', 'XZ output exceeds maxCompressionRatio', {
|
|
1156
|
+
algorithm: 'xz'
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
function createCheck(checkType, skip) {
|
|
1162
|
+
if (skip || checkType === 0x00)
|
|
1163
|
+
return null;
|
|
1164
|
+
if (checkType === 0x01) {
|
|
1165
|
+
const crc = new Crc32();
|
|
1166
|
+
return {
|
|
1167
|
+
update: (chunk) => crc.update(chunk),
|
|
1168
|
+
digestBytes: () => {
|
|
1169
|
+
const value = crc.digest();
|
|
1170
|
+
const out = new Uint8Array(4);
|
|
1171
|
+
out[0] = value & 0xff;
|
|
1172
|
+
out[1] = (value >>> 8) & 0xff;
|
|
1173
|
+
out[2] = (value >>> 16) & 0xff;
|
|
1174
|
+
out[3] = (value >>> 24) & 0xff;
|
|
1175
|
+
return out;
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
if (checkType === 0x04) {
|
|
1180
|
+
const crc = new Crc64();
|
|
1181
|
+
return {
|
|
1182
|
+
update: (chunk) => crc.update(chunk),
|
|
1183
|
+
digestBytes: () => {
|
|
1184
|
+
const value = crc.digest();
|
|
1185
|
+
const out = new Uint8Array(8);
|
|
1186
|
+
const view = new DataView(out.buffer);
|
|
1187
|
+
view.setBigUint64(0, value, true);
|
|
1188
|
+
return out;
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
if (checkType === 0x0a) {
|
|
1193
|
+
const sha = new Sha256();
|
|
1194
|
+
return {
|
|
1195
|
+
update: (chunk) => sha.update(chunk),
|
|
1196
|
+
digestBytes: () => sha.digestBytes()
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
return null;
|
|
1200
|
+
}
|
|
1201
|
+
class RangeDecoder {
|
|
1202
|
+
buffer;
|
|
1203
|
+
range = 0xffffffff;
|
|
1204
|
+
code = 0;
|
|
1205
|
+
pos;
|
|
1206
|
+
limit;
|
|
1207
|
+
constructor(buffer, start, size) {
|
|
1208
|
+
this.buffer = buffer;
|
|
1209
|
+
if (size < 5)
|
|
1210
|
+
throw lzmaBadData('Truncated LZMA stream');
|
|
1211
|
+
this.pos = start;
|
|
1212
|
+
this.limit = start + size;
|
|
1213
|
+
for (let i = 0; i < 5; i += 1) {
|
|
1214
|
+
this.code = ((this.code << 8) | this.readByte()) >>> 0;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
get position() {
|
|
1218
|
+
return this.pos;
|
|
1219
|
+
}
|
|
1220
|
+
decodeBit(probs, index) {
|
|
1221
|
+
const prob = probs[index];
|
|
1222
|
+
const bound = ((this.range >>> 11) * prob) >>> 0;
|
|
1223
|
+
if (this.code < bound) {
|
|
1224
|
+
this.range = bound >>> 0;
|
|
1225
|
+
probs[index] = prob + ((2048 - prob) >>> 5);
|
|
1226
|
+
this.normalize();
|
|
1227
|
+
return 0;
|
|
1228
|
+
}
|
|
1229
|
+
this.range = (this.range - bound) >>> 0;
|
|
1230
|
+
this.code = (this.code - bound) >>> 0;
|
|
1231
|
+
probs[index] = prob - (prob >>> 5);
|
|
1232
|
+
this.normalize();
|
|
1233
|
+
return 1;
|
|
1234
|
+
}
|
|
1235
|
+
decodeDirectBits(numBits) {
|
|
1236
|
+
let result = 0;
|
|
1237
|
+
for (let i = 0; i < numBits; i += 1) {
|
|
1238
|
+
this.range >>>= 1;
|
|
1239
|
+
const t = this.code - this.range;
|
|
1240
|
+
if (t >= 0) {
|
|
1241
|
+
this.code = t >>> 0;
|
|
1242
|
+
result = (result << 1) | 1;
|
|
1243
|
+
}
|
|
1244
|
+
else {
|
|
1245
|
+
result <<= 1;
|
|
1246
|
+
}
|
|
1247
|
+
if (this.range < 0x01000000) {
|
|
1248
|
+
this.range = (this.range << 8) >>> 0;
|
|
1249
|
+
this.code = ((this.code << 8) | this.readByte()) >>> 0;
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return result;
|
|
1253
|
+
}
|
|
1254
|
+
normalize() {
|
|
1255
|
+
if (this.range < 0x01000000) {
|
|
1256
|
+
this.range = (this.range << 8) >>> 0;
|
|
1257
|
+
this.code = ((this.code << 8) | this.readByte()) >>> 0;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
readByte() {
|
|
1261
|
+
if (this.pos >= this.limit) {
|
|
1262
|
+
throw lzmaBadData('Truncated LZMA stream');
|
|
1263
|
+
}
|
|
1264
|
+
return this.buffer[this.pos++];
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
const MAX_VLI = (1n << 63n) - 1n;
|
|
1268
|
+
const K_NUM_POS_BITS_MAX = 4;
|
|
1269
|
+
const K_NUM_POS_STATES_MAX = 1 << K_NUM_POS_BITS_MAX;
|
|
1270
|
+
const K_LEN_NUM_LOW_BITS = 3;
|
|
1271
|
+
const K_LEN_NUM_LOW_SYMBOLS = 1 << K_LEN_NUM_LOW_BITS;
|
|
1272
|
+
const K_LEN_NUM_HIGH_BITS = 8;
|
|
1273
|
+
const K_LEN_NUM_HIGH_SYMBOLS = 1 << K_LEN_NUM_HIGH_BITS;
|
|
1274
|
+
const K_NUM_STATES = 12;
|
|
1275
|
+
const K_NUM_LIT_STATES = 7;
|
|
1276
|
+
const K_END_POS_MODEL_INDEX = 14;
|
|
1277
|
+
const K_NUM_FULL_DISTANCES = 1 << (K_END_POS_MODEL_INDEX >> 1);
|
|
1278
|
+
const K_NUM_POS_SLOT_BITS = 6;
|
|
1279
|
+
const K_NUM_LEN_TO_POS_STATES = 4;
|
|
1280
|
+
const K_NUM_ALIGN_BITS = 4;
|
|
1281
|
+
const K_MATCH_MIN_LEN = 2;
|
|
1282
|
+
function initProbs(probs) {
|
|
1283
|
+
probs.fill(1024);
|
|
1284
|
+
}
|
|
1285
|
+
function decodeBitTree(range, probs, offset, bits) {
|
|
1286
|
+
let symbol = 1;
|
|
1287
|
+
for (let i = 0; i < bits; i += 1) {
|
|
1288
|
+
symbol = (symbol << 1) | range.decodeBit(probs, offset + symbol);
|
|
1289
|
+
}
|
|
1290
|
+
return symbol - (1 << bits);
|
|
1291
|
+
}
|
|
1292
|
+
function decodeReverseBitTree(range, probs, offset, bits) {
|
|
1293
|
+
let symbol = 1;
|
|
1294
|
+
let result = 0;
|
|
1295
|
+
for (let i = 0; i < bits; i += 1) {
|
|
1296
|
+
const bit = range.decodeBit(probs, offset + symbol);
|
|
1297
|
+
symbol = (symbol << 1) | bit;
|
|
1298
|
+
result |= bit << i;
|
|
1299
|
+
}
|
|
1300
|
+
return result;
|
|
1301
|
+
}
|
|
1302
|
+
function decodeLiteral(range, probs, base) {
|
|
1303
|
+
let symbol = 1;
|
|
1304
|
+
for (let i = 0; i < 8; i += 1) {
|
|
1305
|
+
symbol = (symbol << 1) | range.decodeBit(probs, base + symbol);
|
|
1306
|
+
}
|
|
1307
|
+
return symbol - 0x100;
|
|
1308
|
+
}
|
|
1309
|
+
function decodeMatchedLiteral(range, probs, base, matchByte) {
|
|
1310
|
+
let symbol = 1;
|
|
1311
|
+
let match = matchByte;
|
|
1312
|
+
while (symbol < 0x100) {
|
|
1313
|
+
const matchBit = (match >> 7) & 1;
|
|
1314
|
+
match = (match << 1) & 0xff;
|
|
1315
|
+
const bit = range.decodeBit(probs, base + 0x100 + (matchBit << 8) + symbol);
|
|
1316
|
+
symbol = (symbol << 1) | bit;
|
|
1317
|
+
if (matchBit !== bit) {
|
|
1318
|
+
while (symbol < 0x100) {
|
|
1319
|
+
symbol = (symbol << 1) | range.decodeBit(probs, base + symbol);
|
|
1320
|
+
}
|
|
1321
|
+
break;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
return symbol - 0x100;
|
|
1325
|
+
}
|
|
1326
|
+
function updateStateLiteral(state) {
|
|
1327
|
+
if (state < 4)
|
|
1328
|
+
return 0;
|
|
1329
|
+
if (state < 10)
|
|
1330
|
+
return state - 3;
|
|
1331
|
+
return state - 6;
|
|
1332
|
+
}
|
|
1333
|
+
function updateStateMatch(state) {
|
|
1334
|
+
return state < 7 ? 7 : 10;
|
|
1335
|
+
}
|
|
1336
|
+
function updateStateRep(state) {
|
|
1337
|
+
return state < 7 ? 8 : 11;
|
|
1338
|
+
}
|
|
1339
|
+
function updateStateShortRep(state) {
|
|
1340
|
+
return state < 7 ? 9 : 11;
|
|
1341
|
+
}
|
|
1342
|
+
function readVliFromBuffer(buffer, start) {
|
|
1343
|
+
let offset = start;
|
|
1344
|
+
let value = 0n;
|
|
1345
|
+
let shift = 0n;
|
|
1346
|
+
for (let i = 0; i < 9; i += 1) {
|
|
1347
|
+
if (offset >= buffer.length - 4)
|
|
1348
|
+
throw xzBadData('XZ block header truncated');
|
|
1349
|
+
const byte = buffer[offset++];
|
|
1350
|
+
value |= BigInt(byte & 0x7f) << shift;
|
|
1351
|
+
if ((byte & 0x80) === 0) {
|
|
1352
|
+
if (value > MAX_VLI)
|
|
1353
|
+
throw xzBadData('XZ VLI exceeds 63 bits');
|
|
1354
|
+
return { value, offset };
|
|
1355
|
+
}
|
|
1356
|
+
shift += 7n;
|
|
1357
|
+
}
|
|
1358
|
+
throw xzBadData('XZ VLI is too long');
|
|
1359
|
+
}
|
|
1360
|
+
function tryReadVliWithBytes(queue) {
|
|
1361
|
+
const available = Math.min(queue.length, 9);
|
|
1362
|
+
if (available === 0)
|
|
1363
|
+
return null;
|
|
1364
|
+
const peek = queue.peekBytes(available);
|
|
1365
|
+
if (!peek)
|
|
1366
|
+
return null;
|
|
1367
|
+
let value = 0n;
|
|
1368
|
+
let shift = 0n;
|
|
1369
|
+
for (let i = 0; i < peek.length; i += 1) {
|
|
1370
|
+
const byte = peek[i];
|
|
1371
|
+
value |= BigInt(byte & 0x7f) << shift;
|
|
1372
|
+
if ((byte & 0x80) === 0) {
|
|
1373
|
+
if (value > MAX_VLI)
|
|
1374
|
+
throw xzBadData('XZ VLI exceeds 63 bits');
|
|
1375
|
+
const bytes = queue.readBytes(i + 1);
|
|
1376
|
+
return { value, bytes };
|
|
1377
|
+
}
|
|
1378
|
+
shift += 7n;
|
|
1379
|
+
}
|
|
1380
|
+
if (available < 9)
|
|
1381
|
+
return null;
|
|
1382
|
+
throw xzBadData('XZ VLI is too long');
|
|
1383
|
+
}
|
|
1384
|
+
function decodeDictionarySize(props) {
|
|
1385
|
+
const bits = props & 0x3f;
|
|
1386
|
+
if (bits > 40)
|
|
1387
|
+
throw xzBadData('Invalid LZMA2 dictionary size');
|
|
1388
|
+
if (bits === 40)
|
|
1389
|
+
return 0xffffffff;
|
|
1390
|
+
const base = 2 | (bits & 1);
|
|
1391
|
+
const shift = (bits >> 1) + 11;
|
|
1392
|
+
return base * 2 ** shift;
|
|
1393
|
+
}
|
|
1394
|
+
function resolveMaxDictionaryBytes(value, profile) {
|
|
1395
|
+
if (value !== undefined)
|
|
1396
|
+
return toBigInt(value);
|
|
1397
|
+
if (profile === 'agent')
|
|
1398
|
+
return toBigInt(AGENT_RESOURCE_LIMITS.maxXzDictionaryBytes);
|
|
1399
|
+
return toBigInt(DEFAULT_RESOURCE_LIMITS.maxXzDictionaryBytes);
|
|
1400
|
+
}
|
|
1401
|
+
function toBigInt(value) {
|
|
1402
|
+
return typeof value === 'bigint' ? value : BigInt(value);
|
|
1403
|
+
}
|
|
1404
|
+
function toNumberOrThrow(value, label) {
|
|
1405
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
1406
|
+
throw xzBadData(`${label} exceeds safe integer range`);
|
|
1407
|
+
}
|
|
1408
|
+
return Number(value);
|
|
1409
|
+
}
|
|
1410
|
+
function checkSizeForId(id) {
|
|
1411
|
+
if (id === 0x00)
|
|
1412
|
+
return 0;
|
|
1413
|
+
if (id <= 0x03)
|
|
1414
|
+
return 4;
|
|
1415
|
+
if (id <= 0x06)
|
|
1416
|
+
return 8;
|
|
1417
|
+
if (id <= 0x09)
|
|
1418
|
+
return 16;
|
|
1419
|
+
if (id <= 0x0c)
|
|
1420
|
+
return 32;
|
|
1421
|
+
return 64;
|
|
1422
|
+
}
|
|
1423
|
+
function isSupportedCheckType(id) {
|
|
1424
|
+
return id === 0x00 || id === 0x01 || id === 0x04 || id === 0x0a;
|
|
1425
|
+
}
|
|
1426
|
+
function describeCheck(id) {
|
|
1427
|
+
if (id === 0x00)
|
|
1428
|
+
return 'none';
|
|
1429
|
+
if (id === 0x01)
|
|
1430
|
+
return 'crc32';
|
|
1431
|
+
if (id === 0x04)
|
|
1432
|
+
return 'crc64';
|
|
1433
|
+
if (id === 0x0a)
|
|
1434
|
+
return 'sha256';
|
|
1435
|
+
return `0x${id.toString(16)}`;
|
|
1436
|
+
}
|
|
1437
|
+
function matches(a, b) {
|
|
1438
|
+
if (a.length !== b.length)
|
|
1439
|
+
return false;
|
|
1440
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
1441
|
+
if (a[i] !== b[i])
|
|
1442
|
+
return false;
|
|
1443
|
+
}
|
|
1444
|
+
return true;
|
|
1445
|
+
}
|
|
1446
|
+
function xzBadData(message) {
|
|
1447
|
+
return new CompressionError('COMPRESSION_XZ_BAD_DATA', message, { algorithm: 'xz' });
|
|
1448
|
+
}
|
|
1449
|
+
function xzTruncated(message) {
|
|
1450
|
+
return new CompressionError('COMPRESSION_XZ_TRUNCATED', message, { algorithm: 'xz' });
|
|
1451
|
+
}
|
|
1452
|
+
function lzmaBadData(message) {
|
|
1453
|
+
return new CompressionError('COMPRESSION_LZMA_BAD_DATA', message, { algorithm: 'xz' });
|
|
1454
|
+
}
|
|
1455
|
+
//# sourceMappingURL=xz.js.map
|