@push.rocks/smartarchive 4.2.4 → 5.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/bzip2/bititerator.d.ts +6 -1
- package/dist_ts/bzip2/bititerator.js +30 -24
- package/dist_ts/bzip2/bzip2.d.ts +27 -12
- package/dist_ts/bzip2/bzip2.js +325 -263
- package/dist_ts/bzip2/index.d.ts +4 -1
- package/dist_ts/bzip2/index.js +36 -38
- package/dist_ts/classes.archiveanalyzer.d.ts +25 -5
- package/dist_ts/classes.archiveanalyzer.js +19 -8
- package/dist_ts/classes.bzip2tools.d.ts +1 -1
- package/dist_ts/classes.gziptools.d.ts +39 -6
- package/dist_ts/classes.gziptools.js +85 -24
- package/dist_ts/classes.smartarchive.d.ts +101 -16
- package/dist_ts/classes.smartarchive.js +395 -58
- package/dist_ts/classes.tartools.d.ts +31 -4
- package/dist_ts/classes.tartools.js +93 -32
- package/dist_ts/classes.ziptools.d.ts +47 -12
- package/dist_ts/classes.ziptools.js +142 -23
- package/dist_ts/errors.d.ts +44 -0
- package/dist_ts/errors.js +62 -0
- package/dist_ts/index.d.ts +4 -0
- package/dist_ts/index.js +9 -1
- package/dist_ts/interfaces.d.ts +115 -0
- package/dist_ts/interfaces.js +2 -0
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/bzip2/bititerator.ts +43 -27
- package/ts/bzip2/bzip2.ts +289 -171
- package/ts/bzip2/index.ts +52 -50
- package/ts/classes.archiveanalyzer.ts +42 -28
- package/ts/classes.gziptools.ts +96 -33
- package/ts/classes.smartarchive.ts +469 -118
- package/ts/classes.tartools.ts +124 -52
- package/ts/classes.ziptools.ts +160 -34
- package/ts/errors.ts +70 -0
- package/ts/index.ts +11 -0
- package/ts/interfaces.ts +131 -0
package/ts/bzip2/bzip2.ts
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
public message: string;
|
|
4
|
-
public stack = new Error().stack;
|
|
5
|
-
|
|
6
|
-
constructor(messageArg: string) {
|
|
7
|
-
super();
|
|
8
|
-
this.message = messageArg;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
1
|
+
import { Bzip2Error, BZIP2_ERROR_CODES } from '../errors.js';
|
|
2
|
+
import type { IBitReader, IHuffmanGroup } from '../interfaces.js';
|
|
11
3
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
throw new Bzip2Error(message);
|
|
15
|
-
},
|
|
16
|
-
};
|
|
4
|
+
// Re-export Bzip2Error for backward compatibility
|
|
5
|
+
export { Bzip2Error };
|
|
17
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Throw a BZIP2 error with proper error code
|
|
9
|
+
*/
|
|
10
|
+
function throwError(message: string, code: string = BZIP2_ERROR_CODES.INVALID_BLOCK_DATA): never {
|
|
11
|
+
throw new Bzip2Error(message, code);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* BZIP2 decompression implementation
|
|
16
|
+
*/
|
|
18
17
|
export class Bzip2 {
|
|
19
|
-
|
|
20
|
-
public crcTable = [
|
|
18
|
+
// CRC32 lookup table for BZIP2
|
|
19
|
+
public readonly crcTable: readonly number[] = [
|
|
21
20
|
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
|
|
22
21
|
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
|
23
22
|
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
|
|
@@ -63,14 +62,24 @@ export class Bzip2 {
|
|
|
63
62
|
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
|
|
64
63
|
];
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
// State arrays initialized in header()
|
|
66
|
+
private byteCount!: Int32Array;
|
|
67
|
+
private symToByte!: Uint8Array;
|
|
68
|
+
private mtfSymbol!: Int32Array;
|
|
69
|
+
private selectors!: Uint8Array;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create a bit reader from a byte array
|
|
73
|
+
*/
|
|
74
|
+
array(bytes: Uint8Array | Buffer): (n: number) => number {
|
|
75
|
+
let bit = 0;
|
|
76
|
+
let byte = 0;
|
|
77
|
+
const BITMASK = [0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff];
|
|
78
|
+
|
|
79
|
+
return function (n: number): number {
|
|
80
|
+
let result = 0;
|
|
72
81
|
while (n > 0) {
|
|
73
|
-
|
|
82
|
+
const left = 8 - bit;
|
|
74
83
|
if (n >= left) {
|
|
75
84
|
result <<= left;
|
|
76
85
|
result |= BITMASK[left] & bytes[byte++];
|
|
@@ -78,234 +87,341 @@ export class Bzip2 {
|
|
|
78
87
|
n -= left;
|
|
79
88
|
} else {
|
|
80
89
|
result <<= n;
|
|
81
|
-
result |=
|
|
82
|
-
(bytes[byte] & (BITMASK[n] << (8 - n - bit))) >> (8 - n - bit);
|
|
90
|
+
result |= (bytes[byte] & (BITMASK[n] << (8 - n - bit))) >> (8 - n - bit);
|
|
83
91
|
bit += n;
|
|
84
92
|
n = 0;
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
95
|
return result;
|
|
88
96
|
};
|
|
89
|
-
}
|
|
97
|
+
}
|
|
90
98
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Simple decompression from a buffer
|
|
101
|
+
*/
|
|
102
|
+
simple(srcbuffer: Uint8Array | Buffer, stream: (byte: number) => void): void {
|
|
103
|
+
const bits = this.array(srcbuffer);
|
|
104
|
+
const size = this.header(bits as IBitReader);
|
|
105
|
+
let ret: number | null = 0;
|
|
106
|
+
const bufsize = 100000 * size;
|
|
107
|
+
const buf = new Int32Array(bufsize);
|
|
97
108
|
|
|
98
109
|
do {
|
|
99
|
-
ret = this.decompress(bits, stream, buf, bufsize);
|
|
100
|
-
} while (
|
|
101
|
-
}
|
|
110
|
+
ret = this.decompress(bits as IBitReader, stream, buf, bufsize, ret);
|
|
111
|
+
} while (ret !== null);
|
|
112
|
+
}
|
|
102
113
|
|
|
103
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Parse BZIP2 header and return block size
|
|
116
|
+
*/
|
|
117
|
+
header(bits: IBitReader): number {
|
|
104
118
|
this.byteCount = new Int32Array(256);
|
|
105
119
|
this.symToByte = new Uint8Array(256);
|
|
106
120
|
this.mtfSymbol = new Int32Array(256);
|
|
107
121
|
this.selectors = new Uint8Array(0x8000);
|
|
108
122
|
|
|
109
|
-
if (bits(8 * 3)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
if (bits(8 * 3) !== 4348520) {
|
|
124
|
+
throwError('No BZIP2 magic number found at start of stream', BZIP2_ERROR_CODES.NO_MAGIC_NUMBER);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const blockSize = (bits(8) as number) - 48;
|
|
128
|
+
if (blockSize < 1 || blockSize > 9) {
|
|
129
|
+
throwError('Invalid BZIP2 archive: block size must be 1-9', BZIP2_ERROR_CODES.INVALID_ARCHIVE);
|
|
130
|
+
}
|
|
131
|
+
return blockSize;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Decompress a BZIP2 block
|
|
136
|
+
*/
|
|
137
|
+
decompress(
|
|
138
|
+
bits: IBitReader,
|
|
139
|
+
stream: (byte: number) => void,
|
|
140
|
+
buf: Int32Array,
|
|
141
|
+
bufsize: number,
|
|
142
|
+
streamCRC?: number | null
|
|
143
|
+
): number | null {
|
|
144
|
+
const MAX_HUFCODE_BITS = 20;
|
|
145
|
+
const MAX_SYMBOLS = 258;
|
|
146
|
+
const SYMBOL_RUNA = 0;
|
|
147
|
+
const SYMBOL_RUNB = 1;
|
|
148
|
+
const GROUP_SIZE = 50;
|
|
149
|
+
let crc = 0 ^ -1;
|
|
150
|
+
|
|
151
|
+
// Read block header
|
|
152
|
+
let headerHex = '';
|
|
153
|
+
for (let i = 0; i < 6; i++) {
|
|
154
|
+
headerHex += (bits(8) as number).toString(16);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Check for end-of-stream marker
|
|
158
|
+
if (headerHex === '177245385090') {
|
|
159
|
+
const finalCRC = bits(32) as number | 0;
|
|
160
|
+
if (finalCRC !== streamCRC) {
|
|
161
|
+
throwError('CRC32 mismatch: stream checksum verification failed', BZIP2_ERROR_CODES.CRC_MISMATCH);
|
|
162
|
+
}
|
|
163
|
+
// Align stream to byte boundary
|
|
130
164
|
bits(null);
|
|
131
|
-
return null;
|
|
165
|
+
return null;
|
|
132
166
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
167
|
+
|
|
168
|
+
// Verify block signature (pi digits)
|
|
169
|
+
if (headerHex !== '314159265359') {
|
|
170
|
+
throwError('Invalid block header: expected pi signature (0x314159265359)', BZIP2_ERROR_CODES.INVALID_BLOCK_DATA);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const crcblock = bits(32) as number | 0;
|
|
174
|
+
|
|
175
|
+
if (bits(1)) {
|
|
176
|
+
throwError('Unsupported obsolete BZIP2 format version', BZIP2_ERROR_CODES.INVALID_ARCHIVE);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const origPtr = bits(24) as number;
|
|
180
|
+
if (origPtr > bufsize) {
|
|
181
|
+
throwError('Initial position larger than buffer size', BZIP2_ERROR_CODES.BUFFER_OVERFLOW);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Read symbol map
|
|
185
|
+
let symbolMapBits = bits(16) as number;
|
|
186
|
+
let symTotal = 0;
|
|
187
|
+
for (let i = 0; i < 16; i++) {
|
|
188
|
+
if (symbolMapBits & (1 << (15 - i))) {
|
|
189
|
+
const subMap = bits(16) as number;
|
|
190
|
+
for (let j = 0; j < 16; j++) {
|
|
191
|
+
if (subMap & (1 << (15 - j))) {
|
|
146
192
|
this.symToByte[symTotal++] = 16 * i + j;
|
|
147
193
|
}
|
|
148
194
|
}
|
|
149
195
|
}
|
|
150
196
|
}
|
|
151
197
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
198
|
+
// Read Huffman groups
|
|
199
|
+
const groupCount = bits(3) as number;
|
|
200
|
+
if (groupCount < 2 || groupCount > 6) {
|
|
201
|
+
throwError('Invalid group count: must be between 2 and 6', BZIP2_ERROR_CODES.INVALID_HUFFMAN);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const nSelectors = bits(15) as number;
|
|
205
|
+
if (nSelectors === 0) {
|
|
206
|
+
throwError('Invalid selector count: cannot be zero', BZIP2_ERROR_CODES.INVALID_SELECTOR);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Initialize MTF symbol array
|
|
210
|
+
for (let i = 0; i < groupCount; i++) {
|
|
211
|
+
this.mtfSymbol[i] = i;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Read selectors using MTF decoding
|
|
215
|
+
for (let i = 0; i < nSelectors; i++) {
|
|
216
|
+
let j = 0;
|
|
217
|
+
while (bits(1)) {
|
|
218
|
+
j++;
|
|
219
|
+
if (j >= groupCount) {
|
|
220
|
+
throwError('Invalid MTF index: exceeds group count', BZIP2_ERROR_CODES.INVALID_HUFFMAN);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const uc = this.mtfSymbol[j];
|
|
224
|
+
for (let k = j - 1; k >= 0; k--) {
|
|
163
225
|
this.mtfSymbol[k + 1] = this.mtfSymbol[k];
|
|
164
226
|
}
|
|
165
227
|
this.mtfSymbol[0] = uc;
|
|
166
228
|
this.selectors[i] = uc;
|
|
167
229
|
}
|
|
168
230
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
var hufGroup;
|
|
231
|
+
// Build Huffman tables
|
|
232
|
+
const symCount = symTotal + 2;
|
|
233
|
+
const groups: IHuffmanGroup[] = [];
|
|
234
|
+
const length = new Uint8Array(MAX_SYMBOLS);
|
|
235
|
+
const temp = new Uint16Array(MAX_HUFCODE_BITS + 1);
|
|
175
236
|
|
|
176
|
-
for (
|
|
177
|
-
t = bits(5);
|
|
178
|
-
for (
|
|
237
|
+
for (let j = 0; j < groupCount; j++) {
|
|
238
|
+
let t = bits(5) as number;
|
|
239
|
+
for (let i = 0; i < symCount; i++) {
|
|
179
240
|
while (true) {
|
|
180
|
-
if (t < 1 || t > MAX_HUFCODE_BITS)
|
|
181
|
-
|
|
241
|
+
if (t < 1 || t > MAX_HUFCODE_BITS) {
|
|
242
|
+
throwError('Invalid Huffman code length: must be between 1 and 20', BZIP2_ERROR_CODES.INVALID_HUFFMAN);
|
|
243
|
+
}
|
|
182
244
|
if (!bits(1)) break;
|
|
183
245
|
if (!bits(1)) t++;
|
|
184
246
|
else t--;
|
|
185
247
|
}
|
|
186
248
|
length[i] = t;
|
|
187
249
|
}
|
|
188
|
-
|
|
189
|
-
minLen =
|
|
190
|
-
|
|
250
|
+
|
|
251
|
+
let minLen = length[0];
|
|
252
|
+
let maxLen = length[0];
|
|
253
|
+
for (let i = 1; i < symCount; i++) {
|
|
191
254
|
if (length[i] > maxLen) maxLen = length[i];
|
|
192
255
|
else if (length[i] < minLen) minLen = length[i];
|
|
193
256
|
}
|
|
194
|
-
|
|
195
|
-
hufGroup
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
for (i =
|
|
209
|
-
|
|
210
|
-
|
|
257
|
+
|
|
258
|
+
const hufGroup: IHuffmanGroup = {
|
|
259
|
+
permute: new Int32Array(MAX_SYMBOLS),
|
|
260
|
+
limit: new Int32Array(MAX_HUFCODE_BITS + 1),
|
|
261
|
+
base: new Int32Array(MAX_HUFCODE_BITS + 1),
|
|
262
|
+
minLen,
|
|
263
|
+
maxLen,
|
|
264
|
+
};
|
|
265
|
+
groups[j] = hufGroup;
|
|
266
|
+
|
|
267
|
+
const base = hufGroup.base;
|
|
268
|
+
const limit = hufGroup.limit;
|
|
269
|
+
|
|
270
|
+
let pp = 0;
|
|
271
|
+
for (let i = minLen; i <= maxLen; i++) {
|
|
272
|
+
for (let t = 0; t < symCount; t++) {
|
|
273
|
+
if (length[t] === i) hufGroup.permute[pp++] = t;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
for (let i = minLen; i <= maxLen; i++) {
|
|
278
|
+
temp[i] = 0;
|
|
279
|
+
limit[i] = 0;
|
|
280
|
+
}
|
|
281
|
+
for (let i = 0; i < symCount; i++) {
|
|
282
|
+
temp[length[i]]++;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
pp = 0;
|
|
286
|
+
let tt = 0;
|
|
287
|
+
for (let i = minLen; i < maxLen; i++) {
|
|
211
288
|
pp += temp[i];
|
|
212
289
|
limit[i] = pp - 1;
|
|
213
290
|
pp <<= 1;
|
|
214
|
-
base[i + 1] = pp - (
|
|
291
|
+
base[i + 1] = pp - (tt += temp[i]);
|
|
215
292
|
}
|
|
216
293
|
limit[maxLen] = pp + temp[maxLen] - 1;
|
|
217
294
|
base[minLen] = 0;
|
|
218
295
|
}
|
|
219
296
|
|
|
220
|
-
|
|
297
|
+
// Initialize for decoding
|
|
298
|
+
for (let i = 0; i < 256; i++) {
|
|
221
299
|
this.mtfSymbol[i] = i;
|
|
222
300
|
this.byteCount[i] = 0;
|
|
223
301
|
}
|
|
224
|
-
|
|
225
|
-
runPos =
|
|
302
|
+
|
|
303
|
+
let runPos = 0;
|
|
304
|
+
let count = 0;
|
|
305
|
+
let symCountRemaining = 0;
|
|
306
|
+
let selector = 0;
|
|
307
|
+
let hufGroup = groups[0];
|
|
308
|
+
let base = hufGroup.base;
|
|
309
|
+
let limit = hufGroup.limit;
|
|
310
|
+
|
|
311
|
+
// Main decoding loop
|
|
226
312
|
while (true) {
|
|
227
|
-
if (!
|
|
228
|
-
|
|
229
|
-
if (selector >= nSelectors)
|
|
230
|
-
|
|
313
|
+
if (!symCountRemaining--) {
|
|
314
|
+
symCountRemaining = GROUP_SIZE - 1;
|
|
315
|
+
if (selector >= nSelectors) {
|
|
316
|
+
throwError('Invalid selector index: exceeds available groups', BZIP2_ERROR_CODES.INVALID_SELECTOR);
|
|
317
|
+
}
|
|
231
318
|
hufGroup = groups[this.selectors[selector++]];
|
|
232
319
|
base = hufGroup.base;
|
|
233
320
|
limit = hufGroup.limit;
|
|
234
321
|
}
|
|
235
|
-
|
|
236
|
-
|
|
322
|
+
|
|
323
|
+
let i = hufGroup.minLen;
|
|
324
|
+
let j = bits(i) as number;
|
|
325
|
+
|
|
237
326
|
while (true) {
|
|
238
|
-
if (i > hufGroup.maxLen)
|
|
327
|
+
if (i > hufGroup.maxLen) {
|
|
328
|
+
throwError('Huffman decoding error: bit length exceeds maximum allowed', BZIP2_ERROR_CODES.INVALID_HUFFMAN);
|
|
329
|
+
}
|
|
239
330
|
if (j <= limit[i]) break;
|
|
240
331
|
i++;
|
|
241
|
-
j = (j << 1) | bits(1);
|
|
332
|
+
j = (j << 1) | (bits(1) as number);
|
|
242
333
|
}
|
|
334
|
+
|
|
243
335
|
j -= base[i];
|
|
244
|
-
if (j < 0 || j >= MAX_SYMBOLS)
|
|
245
|
-
|
|
246
|
-
|
|
336
|
+
if (j < 0 || j >= MAX_SYMBOLS) {
|
|
337
|
+
throwError('Symbol index out of bounds during Huffman decoding', BZIP2_ERROR_CODES.INVALID_HUFFMAN);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const nextSym = hufGroup.permute[j];
|
|
341
|
+
|
|
342
|
+
if (nextSym === SYMBOL_RUNA || nextSym === SYMBOL_RUNB) {
|
|
247
343
|
if (!runPos) {
|
|
248
344
|
runPos = 1;
|
|
249
|
-
|
|
345
|
+
j = 0;
|
|
250
346
|
}
|
|
251
|
-
if (nextSym
|
|
252
|
-
else
|
|
347
|
+
if (nextSym === SYMBOL_RUNA) j += runPos;
|
|
348
|
+
else j += 2 * runPos;
|
|
253
349
|
runPos <<= 1;
|
|
254
350
|
continue;
|
|
255
351
|
}
|
|
352
|
+
|
|
256
353
|
if (runPos) {
|
|
257
354
|
runPos = 0;
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
355
|
+
const runLength = j;
|
|
356
|
+
if (count + runLength > bufsize) {
|
|
357
|
+
throwError('Run-length overflow: decoded run exceeds buffer capacity', BZIP2_ERROR_CODES.BUFFER_OVERFLOW);
|
|
358
|
+
}
|
|
359
|
+
const uc = this.symToByte[this.mtfSymbol[0]];
|
|
360
|
+
this.byteCount[uc] += runLength;
|
|
361
|
+
for (let t = 0; t < runLength; t++) {
|
|
362
|
+
buf[count++] = uc;
|
|
363
|
+
}
|
|
262
364
|
}
|
|
365
|
+
|
|
263
366
|
if (nextSym > symTotal) break;
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
367
|
+
|
|
368
|
+
if (count >= bufsize) {
|
|
369
|
+
throwError('Buffer overflow: decoded data exceeds buffer capacity', BZIP2_ERROR_CODES.BUFFER_OVERFLOW);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const mtfIndex = nextSym - 1;
|
|
373
|
+
const uc = this.mtfSymbol[mtfIndex];
|
|
374
|
+
for (let k = mtfIndex - 1; k >= 0; k--) {
|
|
269
375
|
this.mtfSymbol[k + 1] = this.mtfSymbol[k];
|
|
270
376
|
}
|
|
271
377
|
this.mtfSymbol[0] = uc;
|
|
272
|
-
|
|
273
|
-
this.byteCount[
|
|
274
|
-
buf[count++] =
|
|
378
|
+
const decodedByte = this.symToByte[uc];
|
|
379
|
+
this.byteCount[decodedByte]++;
|
|
380
|
+
buf[count++] = decodedByte;
|
|
275
381
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
382
|
+
|
|
383
|
+
if (origPtr < 0 || origPtr >= count) {
|
|
384
|
+
throwError('Invalid original pointer: position outside decoded block', BZIP2_ERROR_CODES.INVALID_POSITION);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Inverse BWT transform
|
|
388
|
+
let j = 0;
|
|
389
|
+
for (let i = 0; i < 256; i++) {
|
|
390
|
+
const k = j + this.byteCount[i];
|
|
283
391
|
this.byteCount[i] = j;
|
|
284
392
|
j = k;
|
|
285
393
|
}
|
|
286
|
-
|
|
287
|
-
|
|
394
|
+
|
|
395
|
+
for (let i = 0; i < count; i++) {
|
|
396
|
+
const uc = buf[i] & 0xff;
|
|
288
397
|
buf[this.byteCount[uc]] |= i << 8;
|
|
289
398
|
this.byteCount[uc]++;
|
|
290
399
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
400
|
+
|
|
401
|
+
// Output decoded data
|
|
402
|
+
let pos = 0;
|
|
403
|
+
let current = 0;
|
|
404
|
+
let run = 0;
|
|
405
|
+
|
|
294
406
|
if (count) {
|
|
295
407
|
pos = buf[origPtr];
|
|
296
408
|
current = pos & 0xff;
|
|
297
409
|
pos >>= 8;
|
|
298
410
|
run = -1;
|
|
299
411
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
while (
|
|
303
|
-
|
|
304
|
-
previous = current;
|
|
412
|
+
|
|
413
|
+
let remaining = count;
|
|
414
|
+
while (remaining) {
|
|
415
|
+
remaining--;
|
|
416
|
+
const previous = current;
|
|
305
417
|
pos = buf[pos];
|
|
306
418
|
current = pos & 0xff;
|
|
307
419
|
pos >>= 8;
|
|
308
|
-
|
|
420
|
+
|
|
421
|
+
let copies: number;
|
|
422
|
+
let outbyte: number;
|
|
423
|
+
|
|
424
|
+
if (run++ === 3) {
|
|
309
425
|
copies = current;
|
|
310
426
|
outbyte = previous;
|
|
311
427
|
current = -1;
|
|
@@ -313,19 +429,21 @@ export class Bzip2 {
|
|
|
313
429
|
copies = 1;
|
|
314
430
|
outbyte = current;
|
|
315
431
|
}
|
|
432
|
+
|
|
316
433
|
while (copies--) {
|
|
317
|
-
crc =
|
|
318
|
-
((crc << 8) ^ this.crcTable[((crc >> 24) ^ outbyte) & 0xff]) &
|
|
319
|
-
0xffffffff; // crc32
|
|
434
|
+
crc = ((crc << 8) ^ this.crcTable[((crc >> 24) ^ outbyte) & 0xff]) & 0xffffffff;
|
|
320
435
|
stream(outbyte);
|
|
321
436
|
}
|
|
322
|
-
|
|
437
|
+
|
|
438
|
+
if (current !== previous) run = 0;
|
|
323
439
|
}
|
|
324
440
|
|
|
325
441
|
crc = (crc ^ -1) >>> 0;
|
|
326
|
-
if ((crc | 0)
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
442
|
+
if ((crc | 0) !== (crcblock | 0)) {
|
|
443
|
+
throwError('CRC32 mismatch: block checksum verification failed', BZIP2_ERROR_CODES.CRC_MISMATCH);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const newStreamCRC = (crc ^ (((streamCRC || 0) << 1) | ((streamCRC || 0) >>> 31))) & 0xffffffff;
|
|
447
|
+
return newStreamCRC;
|
|
448
|
+
}
|
|
331
449
|
}
|