@bis-toolkit/utils 1.0.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 +674 -0
- package/README.md +30 -0
- package/dist/BinaryReader.d.ts +30 -0
- package/dist/Lz4.d.ts +10 -0
- package/dist/Lzo.d.ts +53 -0
- package/dist/Lzss.d.ts +18 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +484 -0
- package/dist/index.js.map +7 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @bis-toolkit/utils
|
|
2
|
+
|
|
3
|
+
Shared utilities for BIS Toolkit - binary I/O and decompression algorithms.
|
|
4
|
+
|
|
5
|
+
Part of the [BIS Toolkit TypeScript](../../README.md) monorepo.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **BinaryReader** - Read binary data from buffers
|
|
10
|
+
- **LZO** - LZO1X-1 decompression
|
|
11
|
+
- **LZSS** - LZSS decompression
|
|
12
|
+
- **LZ4** - LZ4 block decompression
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @bis-toolkit/utils
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or if developing from source:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# From monorepo root
|
|
24
|
+
npm install
|
|
25
|
+
npm run build
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## License
|
|
29
|
+
|
|
30
|
+
GPLv3 © Alpine Labs - see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary reader utility for reading binary data from a buffer
|
|
3
|
+
* Works with both Node.js Buffer and browser Uint8Array
|
|
4
|
+
*/
|
|
5
|
+
export declare class BinaryReader {
|
|
6
|
+
protected buffer: Uint8Array;
|
|
7
|
+
protected view: DataView;
|
|
8
|
+
protected position: number;
|
|
9
|
+
constructor(buffer: Buffer | Uint8Array);
|
|
10
|
+
get length(): number;
|
|
11
|
+
get pos(): number;
|
|
12
|
+
seek(offset: number, origin?: 'begin' | 'current' | 'end'): void;
|
|
13
|
+
readByte(): number;
|
|
14
|
+
readUInt16(): number;
|
|
15
|
+
readUInt32(): number;
|
|
16
|
+
readInt32(): number;
|
|
17
|
+
readInt24(): number;
|
|
18
|
+
readBytes(count: number): Uint8Array;
|
|
19
|
+
readRawString(length: number): string;
|
|
20
|
+
readFloat(): number;
|
|
21
|
+
readBoolean(): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Read a null-terminated C-style string
|
|
24
|
+
*/
|
|
25
|
+
readCString(): string;
|
|
26
|
+
/**
|
|
27
|
+
* Alias for readRawString for compatibility
|
|
28
|
+
*/
|
|
29
|
+
readString(length: number): string;
|
|
30
|
+
}
|
package/dist/Lz4.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BinaryReader } from './BinaryReader';
|
|
2
|
+
/**
|
|
3
|
+
* Decompresses an LZ4 block with the declared size from the reader.
|
|
4
|
+
* This implementation supports LZ4 chain decoder which maintains a dictionary across chunks.
|
|
5
|
+
*
|
|
6
|
+
* @param reader - Binary reader positioned at the start of the LZ4 block
|
|
7
|
+
* @param declaredSize - The declared size of the LZ4 block (including headers)
|
|
8
|
+
* @returns Decompressed data as Uint8Array
|
|
9
|
+
*/
|
|
10
|
+
export declare function decompressLz4Block(reader: BinaryReader, declaredSize: number): Uint8Array;
|
package/dist/Lzo.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LZO1X compression and decompression
|
|
3
|
+
* Based on https://github.com/thaumictom/lzo-ts
|
|
4
|
+
* @license GPL-3.0
|
|
5
|
+
*/
|
|
6
|
+
export interface LzoDecompressResult {
|
|
7
|
+
data: Uint8Array;
|
|
8
|
+
bytesRead: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Compress and decompress data using the LZO1X-1 algorithm.
|
|
12
|
+
*/
|
|
13
|
+
export declare class LZO {
|
|
14
|
+
private _blockSize;
|
|
15
|
+
get blockSize(): number;
|
|
16
|
+
set blockSize(value: number);
|
|
17
|
+
private _minNewSize;
|
|
18
|
+
private _out;
|
|
19
|
+
private _cbl;
|
|
20
|
+
private _t;
|
|
21
|
+
private _inputPointer;
|
|
22
|
+
private _outputPointer;
|
|
23
|
+
private _matchPosition;
|
|
24
|
+
private _skipToFirstLiteralFunc;
|
|
25
|
+
private _buffer;
|
|
26
|
+
private _extendBuffer;
|
|
27
|
+
private _matchNext;
|
|
28
|
+
private _matchDone;
|
|
29
|
+
private _copyMatch;
|
|
30
|
+
private _copyFromBuffer;
|
|
31
|
+
private _match;
|
|
32
|
+
private _decompressBuffer;
|
|
33
|
+
/**
|
|
34
|
+
* Decompresses the given buffer using the LZO1X-1 algorithm.
|
|
35
|
+
* @param buffer The buffer to decompress.
|
|
36
|
+
* @returns The decompressed buffer.
|
|
37
|
+
*/
|
|
38
|
+
static decompress(buffer: Uint8Array | number[]): Uint8Array;
|
|
39
|
+
/**
|
|
40
|
+
* Decompresses the given buffer and returns both the decompressed data and bytes read.
|
|
41
|
+
* @param buffer The buffer to decompress.
|
|
42
|
+
* @returns Object containing decompressed data and number of bytes consumed from input.
|
|
43
|
+
*/
|
|
44
|
+
static decompressWithSize(buffer: Uint8Array | number[]): LzoDecompressResult;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Simple decompression helper
|
|
48
|
+
*/
|
|
49
|
+
export declare function lzoDecompress(src: Uint8Array | Buffer, expectedSize: number): Uint8Array;
|
|
50
|
+
/**
|
|
51
|
+
* Decompression with size tracking
|
|
52
|
+
*/
|
|
53
|
+
export declare function lzoDecompressWithSize(src: Uint8Array | Buffer, expectedSize: number): LzoDecompressResult;
|
package/dist/Lzss.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LZSS (Lempel-Ziv-Storer-Szymanski) decompression
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Decompress LZSS compressed data
|
|
6
|
+
* @param input Input stream containing compressed data
|
|
7
|
+
* @param expectedSize Expected size of decompressed output
|
|
8
|
+
* @param useSignedChecksum Whether to use signed checksum calculation
|
|
9
|
+
* @returns Object containing decompressed data and bytes read
|
|
10
|
+
*/
|
|
11
|
+
export declare function lzssDecompress(input: Buffer | Uint8Array, inputOffset: number, expectedSize: number, useSignedChecksum?: boolean): {
|
|
12
|
+
data: Uint8Array;
|
|
13
|
+
bytesRead: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Calculate CRC/checksum for data
|
|
17
|
+
*/
|
|
18
|
+
export declare function calculateChecksum(data: Buffer, signed?: boolean): number;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
// src/BinaryReader.ts
|
|
2
|
+
var BinaryReader = class {
|
|
3
|
+
constructor(buffer) {
|
|
4
|
+
this.position = 0;
|
|
5
|
+
this.buffer = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
6
|
+
this.view = new DataView(this.buffer.buffer, this.buffer.byteOffset, this.buffer.byteLength);
|
|
7
|
+
}
|
|
8
|
+
get length() {
|
|
9
|
+
return this.buffer.length;
|
|
10
|
+
}
|
|
11
|
+
get pos() {
|
|
12
|
+
return this.position;
|
|
13
|
+
}
|
|
14
|
+
seek(offset, origin = "begin") {
|
|
15
|
+
switch (origin) {
|
|
16
|
+
case "begin":
|
|
17
|
+
this.position = offset;
|
|
18
|
+
break;
|
|
19
|
+
case "current":
|
|
20
|
+
this.position += offset;
|
|
21
|
+
break;
|
|
22
|
+
case "end":
|
|
23
|
+
this.position = this.buffer.length + offset;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
readByte() {
|
|
28
|
+
const value = this.view.getUint8(this.position);
|
|
29
|
+
this.position += 1;
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
readUInt16() {
|
|
33
|
+
const value = this.view.getUint16(this.position, true);
|
|
34
|
+
this.position += 2;
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
readUInt32() {
|
|
38
|
+
const value = this.view.getUint32(this.position, true);
|
|
39
|
+
this.position += 4;
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
readInt32() {
|
|
43
|
+
const value = this.view.getInt32(this.position, true);
|
|
44
|
+
this.position += 4;
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
readInt24() {
|
|
48
|
+
const b1 = this.view.getUint8(this.position);
|
|
49
|
+
const b2 = this.view.getUint8(this.position + 1);
|
|
50
|
+
const b3 = this.view.getUint8(this.position + 2);
|
|
51
|
+
this.position += 3;
|
|
52
|
+
return b1 | b2 << 8 | b3 << 16;
|
|
53
|
+
}
|
|
54
|
+
readBytes(count) {
|
|
55
|
+
const bytes = this.buffer.subarray(this.position, this.position + count);
|
|
56
|
+
this.position += count;
|
|
57
|
+
return bytes;
|
|
58
|
+
}
|
|
59
|
+
readRawString(length) {
|
|
60
|
+
const bytes = this.buffer.subarray(this.position, this.position + length);
|
|
61
|
+
this.position += length;
|
|
62
|
+
return String.fromCharCode(...bytes);
|
|
63
|
+
}
|
|
64
|
+
readFloat() {
|
|
65
|
+
const value = this.view.getFloat32(this.position, true);
|
|
66
|
+
this.position += 4;
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
69
|
+
readBoolean() {
|
|
70
|
+
return this.readByte() !== 0;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Read a null-terminated C-style string
|
|
74
|
+
*/
|
|
75
|
+
readCString() {
|
|
76
|
+
const start = this.position;
|
|
77
|
+
let end = start;
|
|
78
|
+
while (end < this.buffer.length && this.buffer[end] !== 0) {
|
|
79
|
+
end++;
|
|
80
|
+
}
|
|
81
|
+
const bytes = this.buffer.subarray(start, end);
|
|
82
|
+
this.position = end + 1;
|
|
83
|
+
const decoder = new TextDecoder("utf-8");
|
|
84
|
+
return decoder.decode(bytes);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Alias for readRawString for compatibility
|
|
88
|
+
*/
|
|
89
|
+
readString(length) {
|
|
90
|
+
return this.readRawString(length);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// src/Lz4.ts
|
|
95
|
+
function decompressLz4Block(reader, declaredSize) {
|
|
96
|
+
const startPos = reader.pos;
|
|
97
|
+
const targetSize = reader.readUInt32();
|
|
98
|
+
const target = new Uint8Array(targetSize);
|
|
99
|
+
let targetIdx = 0;
|
|
100
|
+
const LzBlockSize = 65536;
|
|
101
|
+
const dict = new Uint8Array(LzBlockSize);
|
|
102
|
+
let dictSize = 0;
|
|
103
|
+
while (true) {
|
|
104
|
+
const compressedSize = reader.readInt24();
|
|
105
|
+
const flags = reader.readByte();
|
|
106
|
+
if ((flags & ~128) !== 0) {
|
|
107
|
+
throw new Error(`Unknown LZ4 flags 0x${flags.toString(16)}`);
|
|
108
|
+
}
|
|
109
|
+
const compressed = reader.readBytes(compressedSize);
|
|
110
|
+
const decoded = decompressLz4BlockWithDict(compressed, dict, dictSize);
|
|
111
|
+
if (targetIdx + decoded.length > target.length) {
|
|
112
|
+
throw new Error("Decoded LZ4 data overruns target buffer");
|
|
113
|
+
}
|
|
114
|
+
target.set(decoded, targetIdx);
|
|
115
|
+
targetIdx += decoded.length;
|
|
116
|
+
if (decoded.length >= LzBlockSize) {
|
|
117
|
+
dict.set(decoded.subarray(decoded.length - LzBlockSize));
|
|
118
|
+
dictSize = LzBlockSize;
|
|
119
|
+
} else {
|
|
120
|
+
const available = LzBlockSize - dictSize;
|
|
121
|
+
if (decoded.length <= available) {
|
|
122
|
+
dict.set(decoded, dictSize);
|
|
123
|
+
dictSize += decoded.length;
|
|
124
|
+
} else {
|
|
125
|
+
const shift = decoded.length - available;
|
|
126
|
+
dict.copyWithin(0, shift);
|
|
127
|
+
dict.set(decoded, LzBlockSize - decoded.length);
|
|
128
|
+
dictSize = LzBlockSize;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if ((flags & 128) !== 0) {
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (startPos + declaredSize !== reader.pos) {
|
|
136
|
+
throw new Error("LZ4 block length mismatch");
|
|
137
|
+
}
|
|
138
|
+
if (targetIdx !== targetSize) {
|
|
139
|
+
throw new Error(`LZ4 decoded size mismatch (expected ${targetSize}, got ${targetIdx})`);
|
|
140
|
+
}
|
|
141
|
+
return target;
|
|
142
|
+
}
|
|
143
|
+
function decompressLz4BlockWithDict(compressed, dict, dictSize) {
|
|
144
|
+
const output = [];
|
|
145
|
+
let src = 0;
|
|
146
|
+
while (src < compressed.length) {
|
|
147
|
+
const token = compressed[src++];
|
|
148
|
+
let literalLength = token >> 4;
|
|
149
|
+
if (literalLength === 15) {
|
|
150
|
+
let len = 0;
|
|
151
|
+
do {
|
|
152
|
+
len = compressed[src++];
|
|
153
|
+
literalLength += len;
|
|
154
|
+
} while (len === 255 && src < compressed.length);
|
|
155
|
+
}
|
|
156
|
+
for (let i = 0; i < literalLength; i++) {
|
|
157
|
+
output.push(compressed[src++]);
|
|
158
|
+
}
|
|
159
|
+
if (src >= compressed.length) {
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
const offset = compressed[src] | compressed[src + 1] << 8;
|
|
163
|
+
src += 2;
|
|
164
|
+
let matchLength = token & 15;
|
|
165
|
+
if (matchLength === 15) {
|
|
166
|
+
let len = 0;
|
|
167
|
+
do {
|
|
168
|
+
len = compressed[src++];
|
|
169
|
+
matchLength += len;
|
|
170
|
+
} while (len === 255 && src < compressed.length);
|
|
171
|
+
}
|
|
172
|
+
matchLength += 4;
|
|
173
|
+
if (offset === 0) {
|
|
174
|
+
throw new Error("Invalid LZ4 offset");
|
|
175
|
+
}
|
|
176
|
+
const totalAvailable = dictSize + output.length;
|
|
177
|
+
if (offset > totalAvailable) {
|
|
178
|
+
throw new Error("Invalid LZ4 offset");
|
|
179
|
+
}
|
|
180
|
+
for (let i = 0; i < matchLength; i++) {
|
|
181
|
+
const backPos = output.length - offset;
|
|
182
|
+
if (backPos >= 0) {
|
|
183
|
+
output.push(output[backPos]);
|
|
184
|
+
} else {
|
|
185
|
+
const dictPos = dictSize + backPos;
|
|
186
|
+
output.push(dict[dictPos]);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return Uint8Array.from(output);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/Lzo.ts
|
|
194
|
+
var LZO = class _LZO {
|
|
195
|
+
constructor() {
|
|
196
|
+
this._blockSize = 128 * 1024;
|
|
197
|
+
this._minNewSize = this.blockSize;
|
|
198
|
+
this._out = new Uint8Array(256 * 1024);
|
|
199
|
+
this._cbl = 0;
|
|
200
|
+
this._t = 0;
|
|
201
|
+
this._inputPointer = 0;
|
|
202
|
+
this._outputPointer = 0;
|
|
203
|
+
this._matchPosition = 0;
|
|
204
|
+
this._skipToFirstLiteralFunc = false;
|
|
205
|
+
}
|
|
206
|
+
get blockSize() {
|
|
207
|
+
return this._blockSize;
|
|
208
|
+
}
|
|
209
|
+
set blockSize(value) {
|
|
210
|
+
if (value <= 0) throw new Error("Block size must be a positive integer");
|
|
211
|
+
this._blockSize = value;
|
|
212
|
+
}
|
|
213
|
+
_extendBuffer() {
|
|
214
|
+
const newBuffer = new Uint8Array(
|
|
215
|
+
this._minNewSize + (this.blockSize - this._minNewSize % this.blockSize)
|
|
216
|
+
);
|
|
217
|
+
newBuffer.set(this._out);
|
|
218
|
+
this._out = newBuffer;
|
|
219
|
+
this._cbl = this._out.length;
|
|
220
|
+
}
|
|
221
|
+
_matchNext() {
|
|
222
|
+
this._minNewSize = this._outputPointer + 3;
|
|
223
|
+
if (this._minNewSize > this._cbl) this._extendBuffer();
|
|
224
|
+
this._out[this._outputPointer++] = this._buffer[this._inputPointer++];
|
|
225
|
+
if (this._t > 1) {
|
|
226
|
+
this._out[this._outputPointer++] = this._buffer[this._inputPointer++];
|
|
227
|
+
if (this._t > 2) {
|
|
228
|
+
this._out[this._outputPointer++] = this._buffer[this._inputPointer++];
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
this._t = this._buffer[this._inputPointer++];
|
|
232
|
+
}
|
|
233
|
+
_matchDone() {
|
|
234
|
+
this._t = this._buffer[this._inputPointer - 2] & 3;
|
|
235
|
+
return this._t;
|
|
236
|
+
}
|
|
237
|
+
_copyMatch() {
|
|
238
|
+
this._t += 2;
|
|
239
|
+
this._minNewSize = this._outputPointer + this._t;
|
|
240
|
+
if (this._minNewSize > this._cbl) {
|
|
241
|
+
this._extendBuffer();
|
|
242
|
+
}
|
|
243
|
+
do {
|
|
244
|
+
this._out[this._outputPointer++] = this._out[this._matchPosition++];
|
|
245
|
+
} while (--this._t > 0);
|
|
246
|
+
}
|
|
247
|
+
_copyFromBuffer() {
|
|
248
|
+
this._minNewSize = this._outputPointer + this._t;
|
|
249
|
+
if (this._minNewSize > this._cbl) {
|
|
250
|
+
this._extendBuffer();
|
|
251
|
+
}
|
|
252
|
+
do {
|
|
253
|
+
this._out[this._outputPointer++] = this._buffer[this._inputPointer++];
|
|
254
|
+
} while (--this._t > 0);
|
|
255
|
+
}
|
|
256
|
+
_match() {
|
|
257
|
+
while (true) {
|
|
258
|
+
if (this._t >= 64) {
|
|
259
|
+
this._matchPosition = this._outputPointer - 1 - (this._t >> 2 & 7) - (this._buffer[this._inputPointer++] << 3);
|
|
260
|
+
this._t = (this._t >> 5) - 1;
|
|
261
|
+
this._copyMatch();
|
|
262
|
+
} else if (this._t >= 32) {
|
|
263
|
+
this._t &= 31;
|
|
264
|
+
if (this._t === 0) {
|
|
265
|
+
while (this._buffer[this._inputPointer] === 0) {
|
|
266
|
+
this._t += 255;
|
|
267
|
+
this._inputPointer++;
|
|
268
|
+
}
|
|
269
|
+
this._t += 31 + this._buffer[this._inputPointer++];
|
|
270
|
+
}
|
|
271
|
+
this._matchPosition = this._outputPointer - 1 - (this._buffer[this._inputPointer] >> 2) - (this._buffer[this._inputPointer + 1] << 6);
|
|
272
|
+
this._inputPointer += 2;
|
|
273
|
+
this._copyMatch();
|
|
274
|
+
} else if (this._t >= 16) {
|
|
275
|
+
this._matchPosition = this._outputPointer - ((this._t & 8) << 11);
|
|
276
|
+
this._t &= 7;
|
|
277
|
+
if (this._t === 0) {
|
|
278
|
+
while (this._buffer[this._inputPointer] === 0) {
|
|
279
|
+
this._t += 255;
|
|
280
|
+
this._inputPointer++;
|
|
281
|
+
}
|
|
282
|
+
this._t += 7 + this._buffer[this._inputPointer++];
|
|
283
|
+
}
|
|
284
|
+
this._matchPosition -= (this._buffer[this._inputPointer] >> 2) + (this._buffer[this._inputPointer + 1] << 6);
|
|
285
|
+
this._inputPointer += 2;
|
|
286
|
+
if (this._matchPosition === this._outputPointer) {
|
|
287
|
+
return this._out.subarray(0, this._outputPointer);
|
|
288
|
+
} else {
|
|
289
|
+
this._matchPosition -= 16384;
|
|
290
|
+
this._copyMatch();
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
this._matchPosition = this._outputPointer - 1 - (this._t >> 2) - (this._buffer[this._inputPointer++] << 2);
|
|
294
|
+
this._minNewSize = this._outputPointer + 2;
|
|
295
|
+
if (this._minNewSize > this._cbl) {
|
|
296
|
+
this._extendBuffer();
|
|
297
|
+
}
|
|
298
|
+
this._out[this._outputPointer++] = this._out[this._matchPosition++];
|
|
299
|
+
this._out[this._outputPointer++] = this._out[this._matchPosition];
|
|
300
|
+
}
|
|
301
|
+
if (this._matchDone() === 0) {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
this._matchNext();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
_decompressBuffer(buffer) {
|
|
308
|
+
this._buffer = buffer;
|
|
309
|
+
this._cbl = this._out.length;
|
|
310
|
+
this._t = 0;
|
|
311
|
+
this._inputPointer = 0;
|
|
312
|
+
this._outputPointer = 0;
|
|
313
|
+
this._matchPosition = 0;
|
|
314
|
+
this._skipToFirstLiteralFunc = false;
|
|
315
|
+
if (this._buffer[this._inputPointer] > 17) {
|
|
316
|
+
this._t = this._buffer[this._inputPointer++] - 17;
|
|
317
|
+
if (this._t < 4) {
|
|
318
|
+
this._matchNext();
|
|
319
|
+
const matched = this._match();
|
|
320
|
+
if (matched !== true) return matched;
|
|
321
|
+
} else {
|
|
322
|
+
this._copyFromBuffer();
|
|
323
|
+
this._skipToFirstLiteralFunc = true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
while (true) {
|
|
327
|
+
if (!this._skipToFirstLiteralFunc) {
|
|
328
|
+
this._t = this._buffer[this._inputPointer++];
|
|
329
|
+
if (this._t >= 16) {
|
|
330
|
+
const matched2 = this._match();
|
|
331
|
+
if (matched2 !== true) return matched2;
|
|
332
|
+
continue;
|
|
333
|
+
} else if (this._t === 0) {
|
|
334
|
+
while (this._buffer[this._inputPointer] === 0) {
|
|
335
|
+
this._t += 255;
|
|
336
|
+
this._inputPointer++;
|
|
337
|
+
}
|
|
338
|
+
this._t += 15 + this._buffer[this._inputPointer++];
|
|
339
|
+
}
|
|
340
|
+
this._t += 3;
|
|
341
|
+
this._copyFromBuffer();
|
|
342
|
+
} else this._skipToFirstLiteralFunc = false;
|
|
343
|
+
this._t = this._buffer[this._inputPointer++];
|
|
344
|
+
if (this._t < 16) {
|
|
345
|
+
this._matchPosition = this._outputPointer - (1 + 2048);
|
|
346
|
+
this._matchPosition -= this._t >> 2;
|
|
347
|
+
this._matchPosition -= this._buffer[this._inputPointer++] << 2;
|
|
348
|
+
this._minNewSize = this._outputPointer + 3;
|
|
349
|
+
if (this._minNewSize > this._cbl) {
|
|
350
|
+
this._extendBuffer();
|
|
351
|
+
}
|
|
352
|
+
this._out[this._outputPointer++] = this._out[this._matchPosition++];
|
|
353
|
+
this._out[this._outputPointer++] = this._out[this._matchPosition++];
|
|
354
|
+
this._out[this._outputPointer++] = this._out[this._matchPosition];
|
|
355
|
+
if (this._matchDone() === 0) continue;
|
|
356
|
+
else this._matchNext();
|
|
357
|
+
}
|
|
358
|
+
const matched = this._match();
|
|
359
|
+
if (matched !== true) return matched;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Decompresses the given buffer using the LZO1X-1 algorithm.
|
|
364
|
+
* @param buffer The buffer to decompress.
|
|
365
|
+
* @returns The decompressed buffer.
|
|
366
|
+
*/
|
|
367
|
+
static decompress(buffer) {
|
|
368
|
+
return new _LZO()._decompressBuffer(buffer);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Decompresses the given buffer and returns both the decompressed data and bytes read.
|
|
372
|
+
* @param buffer The buffer to decompress.
|
|
373
|
+
* @returns Object containing decompressed data and number of bytes consumed from input.
|
|
374
|
+
*/
|
|
375
|
+
static decompressWithSize(buffer) {
|
|
376
|
+
const lzo = new _LZO();
|
|
377
|
+
const decompressed = lzo._decompressBuffer(buffer);
|
|
378
|
+
return {
|
|
379
|
+
data: decompressed,
|
|
380
|
+
bytesRead: lzo._inputPointer
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
function lzoDecompress(src, expectedSize) {
|
|
385
|
+
const input = src instanceof Uint8Array ? src : new Uint8Array(src);
|
|
386
|
+
const decompressed = LZO.decompress(input);
|
|
387
|
+
if (decompressed.length !== expectedSize) {
|
|
388
|
+
throw new Error(`LZO decompression size mismatch: expected ${expectedSize}, got ${decompressed.length}`);
|
|
389
|
+
}
|
|
390
|
+
return decompressed;
|
|
391
|
+
}
|
|
392
|
+
function lzoDecompressWithSize(src, expectedSize) {
|
|
393
|
+
const input = src instanceof Uint8Array ? src : new Uint8Array(src);
|
|
394
|
+
const result = LZO.decompressWithSize(input);
|
|
395
|
+
if (result.data.length !== expectedSize) {
|
|
396
|
+
throw new Error(`LZO decompression size mismatch: expected ${expectedSize}, got ${result.data.length}`);
|
|
397
|
+
}
|
|
398
|
+
return result;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// src/Lzss.ts
|
|
402
|
+
var N = 4096;
|
|
403
|
+
var F = 18;
|
|
404
|
+
var THRESHOLD = 2;
|
|
405
|
+
function lzssDecompress(input, inputOffset, expectedSize, useSignedChecksum = false) {
|
|
406
|
+
const buffer = new Array(N + F - 1);
|
|
407
|
+
const dst = new Uint8Array(expectedSize);
|
|
408
|
+
if (expectedSize <= 0) {
|
|
409
|
+
return { data: new Uint8Array(0), bytesRead: 0 };
|
|
410
|
+
}
|
|
411
|
+
const startPos = inputOffset;
|
|
412
|
+
let inPos = inputOffset;
|
|
413
|
+
let iDst = 0;
|
|
414
|
+
let calculatedChecksum = 0;
|
|
415
|
+
let r = N - F;
|
|
416
|
+
for (let i = 0; i < r; i++) {
|
|
417
|
+
buffer[i] = 32;
|
|
418
|
+
}
|
|
419
|
+
let flags = 0;
|
|
420
|
+
while (expectedSize > 0) {
|
|
421
|
+
if (((flags >>>= 1) & 256) === 0) {
|
|
422
|
+
const c = input[inPos++];
|
|
423
|
+
flags = c | 65280;
|
|
424
|
+
}
|
|
425
|
+
if ((flags & 1) !== 0) {
|
|
426
|
+
const c = input[inPos++];
|
|
427
|
+
calculatedChecksum = calculatedChecksum + (useSignedChecksum ? c << 24 >> 24 : c) | 0;
|
|
428
|
+
dst[iDst++] = c;
|
|
429
|
+
expectedSize--;
|
|
430
|
+
buffer[r] = c;
|
|
431
|
+
r = r + 1 & N - 1;
|
|
432
|
+
} else {
|
|
433
|
+
const i = input[inPos++];
|
|
434
|
+
const j = input[inPos++];
|
|
435
|
+
const offset = i | (j & 240) << 4;
|
|
436
|
+
const length = (j & 15) + THRESHOLD;
|
|
437
|
+
if (length + 1 > expectedSize + length - THRESHOLD) {
|
|
438
|
+
throw new Error("LZSS overflow");
|
|
439
|
+
}
|
|
440
|
+
let ii = r - offset;
|
|
441
|
+
const jj = length + ii;
|
|
442
|
+
for (; ii <= jj; ii++) {
|
|
443
|
+
const c = buffer[ii & N - 1];
|
|
444
|
+
calculatedChecksum = calculatedChecksum + (useSignedChecksum ? c << 24 >> 24 : c) | 0;
|
|
445
|
+
dst[iDst++] = c;
|
|
446
|
+
expectedSize--;
|
|
447
|
+
buffer[r] = c;
|
|
448
|
+
r = r + 1 & N - 1;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const view = new DataView(input.buffer, input.byteOffset, input.byteLength);
|
|
453
|
+
const checksum = view.getInt32(inPos, true);
|
|
454
|
+
inPos += 4;
|
|
455
|
+
if (checksum !== calculatedChecksum) {
|
|
456
|
+
throw new Error(`Checksum mismatch: expected ${checksum}, got ${calculatedChecksum}`);
|
|
457
|
+
}
|
|
458
|
+
return {
|
|
459
|
+
data: dst,
|
|
460
|
+
bytesRead: inPos - startPos
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function calculateChecksum(data, signed = false) {
|
|
464
|
+
let checksum = 0;
|
|
465
|
+
for (const byte of data) {
|
|
466
|
+
checksum = checksum + (signed ? byte << 24 >> 24 : byte) | 0;
|
|
467
|
+
}
|
|
468
|
+
return checksum;
|
|
469
|
+
}
|
|
470
|
+
export {
|
|
471
|
+
BinaryReader,
|
|
472
|
+
LZO,
|
|
473
|
+
calculateChecksum,
|
|
474
|
+
decompressLz4Block,
|
|
475
|
+
lzoDecompress,
|
|
476
|
+
lzoDecompressWithSize,
|
|
477
|
+
lzssDecompress
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* LZO1X compression and decompression
|
|
481
|
+
* Based on https://github.com/thaumictom/lzo-ts
|
|
482
|
+
* @license GPL-3.0
|
|
483
|
+
*/
|
|
484
|
+
//# sourceMappingURL=index.js.map
|