7z-iterator 0.2.9 → 0.2.10
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/cjs/FileEntry.js.map +1 -1
- package/dist/cjs/SevenZipIterator.js.map +1 -1
- package/dist/cjs/compat.js.map +1 -1
- package/dist/cjs/lib/streamToSource.js.map +1 -1
- package/dist/cjs/nextEntry.js.map +1 -1
- package/dist/cjs/sevenz/NumberCodec.js.map +1 -1
- package/dist/cjs/sevenz/SevenZipParser.js.map +1 -1
- package/dist/cjs/sevenz/codecs/Aes.js.map +1 -1
- package/dist/cjs/sevenz/codecs/Bcj.js +1 -1
- package/dist/cjs/sevenz/codecs/Bcj.js.map +1 -1
- package/dist/cjs/sevenz/codecs/Bcj2.js.map +1 -1
- package/dist/cjs/sevenz/codecs/BcjArm.js.map +1 -1
- package/dist/cjs/sevenz/codecs/BcjArm64.js.map +1 -1
- package/dist/cjs/sevenz/codecs/BcjArmt.js.map +1 -1
- package/dist/cjs/sevenz/codecs/BcjIa64.js.map +1 -1
- package/dist/cjs/sevenz/codecs/BcjPpc.js.map +1 -1
- package/dist/cjs/sevenz/codecs/BcjSparc.js.map +1 -1
- package/dist/cjs/sevenz/codecs/Delta.js.map +1 -1
- package/dist/cjs/sevenz/codecs/Lzma.js.map +1 -1
- package/dist/cjs/sevenz/codecs/Lzma2.js.map +1 -1
- package/dist/cjs/sevenz/codecs/createBufferingDecoder.js.map +1 -1
- package/dist/cjs/sevenz/codecs/index.js.map +1 -1
- package/dist/cjs/sevenz/codecs/lzmaCompat.d.cts +1 -1
- package/dist/cjs/sevenz/codecs/lzmaCompat.d.ts +1 -1
- package/dist/cjs/sevenz/codecs/lzmaCompat.js.map +1 -1
- package/dist/cjs/sevenz/codecs/streams.js.map +1 -1
- package/dist/cjs/sevenz/constants.d.cts +8 -8
- package/dist/cjs/sevenz/constants.d.ts +8 -8
- package/dist/cjs/sevenz/constants.js.map +1 -1
- package/dist/cjs/sevenz/headers.js +1 -1
- package/dist/cjs/sevenz/headers.js.map +1 -1
- package/dist/esm/FileEntry.js +1 -1
- package/dist/esm/FileEntry.js.map +1 -1
- package/dist/esm/SevenZipIterator.js +6 -6
- package/dist/esm/SevenZipIterator.js.map +1 -1
- package/dist/esm/compat.js +2 -2
- package/dist/esm/compat.js.map +1 -1
- package/dist/esm/lib/streamToSource.js +12 -12
- package/dist/esm/lib/streamToSource.js.map +1 -1
- package/dist/esm/nextEntry.js +11 -11
- package/dist/esm/nextEntry.js.map +1 -1
- package/dist/esm/sevenz/NumberCodec.js +19 -19
- package/dist/esm/sevenz/NumberCodec.js.map +1 -1
- package/dist/esm/sevenz/SevenZipParser.js +191 -191
- package/dist/esm/sevenz/SevenZipParser.js.map +1 -1
- package/dist/esm/sevenz/codecs/Aes.js +29 -29
- package/dist/esm/sevenz/codecs/Aes.js.map +1 -1
- package/dist/esm/sevenz/codecs/Bcj.js +8 -8
- package/dist/esm/sevenz/codecs/Bcj.js.map +1 -1
- package/dist/esm/sevenz/codecs/Bcj2.js +35 -35
- package/dist/esm/sevenz/codecs/Bcj2.js.map +1 -1
- package/dist/esm/sevenz/codecs/BcjArm.js +4 -4
- package/dist/esm/sevenz/codecs/BcjArm.js.map +1 -1
- package/dist/esm/sevenz/codecs/BcjArm64.js +5 -5
- package/dist/esm/sevenz/codecs/BcjArm64.js.map +1 -1
- package/dist/esm/sevenz/codecs/BcjArmt.js +10 -10
- package/dist/esm/sevenz/codecs/BcjArmt.js.map +1 -1
- package/dist/esm/sevenz/codecs/BcjIa64.js +24 -24
- package/dist/esm/sevenz/codecs/BcjIa64.js.map +1 -1
- package/dist/esm/sevenz/codecs/BcjPpc.js +5 -5
- package/dist/esm/sevenz/codecs/BcjPpc.js.map +1 -1
- package/dist/esm/sevenz/codecs/BcjSparc.js +8 -8
- package/dist/esm/sevenz/codecs/BcjSparc.js.map +1 -1
- package/dist/esm/sevenz/codecs/Delta.js +6 -6
- package/dist/esm/sevenz/codecs/Delta.js.map +1 -1
- package/dist/esm/sevenz/codecs/Lzma.js +16 -16
- package/dist/esm/sevenz/codecs/Lzma.js.map +1 -1
- package/dist/esm/sevenz/codecs/Lzma2.js +35 -35
- package/dist/esm/sevenz/codecs/Lzma2.js.map +1 -1
- package/dist/esm/sevenz/codecs/createBufferingDecoder.js +3 -3
- package/dist/esm/sevenz/codecs/createBufferingDecoder.js.map +1 -1
- package/dist/esm/sevenz/codecs/index.js +6 -6
- package/dist/esm/sevenz/codecs/index.js.map +1 -1
- package/dist/esm/sevenz/codecs/lzmaCompat.d.ts +1 -1
- package/dist/esm/sevenz/codecs/lzmaCompat.js +5 -5
- package/dist/esm/sevenz/codecs/lzmaCompat.js.map +1 -1
- package/dist/esm/sevenz/codecs/streams.js +13 -13
- package/dist/esm/sevenz/codecs/streams.js.map +1 -1
- package/dist/esm/sevenz/constants.d.ts +8 -8
- package/dist/esm/sevenz/constants.js +9 -9
- package/dist/esm/sevenz/constants.js.map +1 -1
- package/dist/esm/sevenz/headers.js +134 -134
- package/dist/esm/sevenz/headers.js.map +1 -1
- package/package.json +20 -20
|
@@ -36,8 +36,8 @@ import { readNumber } from './NumberCodec.js';
|
|
|
36
36
|
* File descriptor based archive source
|
|
37
37
|
*/ export class FileSource {
|
|
38
38
|
read(position, length) {
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
const buf = allocBuffer(length);
|
|
40
|
+
const bytesRead = fs.readSync(this.fd, buf, 0, length, position);
|
|
41
41
|
if (bytesRead < length) {
|
|
42
42
|
return buf.slice(0, bytesRead);
|
|
43
43
|
}
|
|
@@ -67,24 +67,24 @@ import { readNumber } from './NumberCodec.js';
|
|
|
67
67
|
*/ parse() {
|
|
68
68
|
if (this.parsed) return;
|
|
69
69
|
// Read signature header
|
|
70
|
-
|
|
70
|
+
const sigBuf = this.source.read(0, SIGNATURE_HEADER_SIZE);
|
|
71
71
|
if (sigBuf.length < SIGNATURE_HEADER_SIZE) {
|
|
72
72
|
throw createCodedError('Archive too small', ErrorCode.TRUNCATED_ARCHIVE);
|
|
73
73
|
}
|
|
74
74
|
this.signature = parseSignatureHeader(sigBuf);
|
|
75
75
|
// Read encoded header
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
const headerOffset = SIGNATURE_HEADER_SIZE + this.signature.nextHeaderOffset;
|
|
77
|
+
const headerBuf = this.source.read(headerOffset, this.signature.nextHeaderSize);
|
|
78
78
|
if (headerBuf.length < this.signature.nextHeaderSize) {
|
|
79
79
|
throw createCodedError('Truncated header', ErrorCode.TRUNCATED_ARCHIVE);
|
|
80
80
|
}
|
|
81
81
|
// Parse encoded header (may need decompression)
|
|
82
82
|
try {
|
|
83
|
-
|
|
83
|
+
const headerResult = parseEncodedHeader(headerBuf, this.signature.nextHeaderCRC);
|
|
84
84
|
this.streamsInfo = headerResult.streamsInfo || null;
|
|
85
85
|
this.filesInfo = headerResult.filesInfo;
|
|
86
86
|
} catch (err) {
|
|
87
|
-
|
|
87
|
+
const codedErr = err;
|
|
88
88
|
if (codedErr && codedErr.code === ErrorCode.COMPRESSED_HEADER) {
|
|
89
89
|
// Header is compressed - need to decompress first
|
|
90
90
|
this.handleCompressedHeader(headerBuf);
|
|
@@ -100,31 +100,31 @@ import { readNumber } from './NumberCodec.js';
|
|
|
100
100
|
* Handle compressed header (kEncodedHeader)
|
|
101
101
|
*/ handleCompressedHeader(headerBuf) {
|
|
102
102
|
// Parse the encoded header info to get decompression parameters
|
|
103
|
-
|
|
103
|
+
let offset = 1; // Skip kEncodedHeader byte
|
|
104
104
|
// Should have StreamsInfo for the header itself
|
|
105
|
-
|
|
105
|
+
const propertyId = headerBuf[offset++];
|
|
106
106
|
if (propertyId !== PropertyId.kMainStreamsInfo && propertyId !== PropertyId.kPackInfo) {
|
|
107
107
|
throw createCodedError('Expected StreamsInfo in encoded header', ErrorCode.CORRUPT_HEADER);
|
|
108
108
|
}
|
|
109
109
|
// For now, we parse the streams info from the encoded header block
|
|
110
110
|
// This tells us how to decompress the actual header
|
|
111
111
|
// Read pack info from the encoded header structure
|
|
112
|
-
|
|
112
|
+
const packInfoResult = this.parseEncodedHeaderStreams(headerBuf, 1);
|
|
113
113
|
// Calculate compressed header position
|
|
114
114
|
// For simple archives: header is at SIGNATURE_HEADER_SIZE + packPos
|
|
115
115
|
// For BCJ2/complex archives: header may be at the END of pack data area
|
|
116
116
|
// The pack data area ends at nextHeaderOffset (where encoded header starts)
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
const compressedStart = SIGNATURE_HEADER_SIZE + packInfoResult.packPos;
|
|
118
|
+
const compressedData = this.source.read(compressedStart, packInfoResult.packSize);
|
|
119
119
|
// Decompress using the specified codec
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
const codec = getCodec(packInfoResult.codecId);
|
|
121
|
+
let decompressedHeader = null;
|
|
122
122
|
// Try decompressing from the calculated position first
|
|
123
123
|
try {
|
|
124
124
|
decompressedHeader = codec.decode(compressedData, packInfoResult.properties, packInfoResult.unpackSize);
|
|
125
125
|
// Verify CRC if present
|
|
126
126
|
if (packInfoResult.unpackCRC !== undefined) {
|
|
127
|
-
|
|
127
|
+
const actualCRC = crc32(decompressedHeader);
|
|
128
128
|
if (actualCRC !== packInfoResult.unpackCRC) {
|
|
129
129
|
decompressedHeader = null; // CRC mismatch, need to search
|
|
130
130
|
}
|
|
@@ -135,22 +135,22 @@ import { readNumber } from './NumberCodec.js';
|
|
|
135
135
|
// If initial decompression failed, search for the correct position as a fallback
|
|
136
136
|
// This handles edge cases where packPos doesn't point directly to header pack data
|
|
137
137
|
if (decompressedHeader === null && this.signature) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
const packAreaEnd = SIGNATURE_HEADER_SIZE + this.signature.nextHeaderOffset;
|
|
139
|
+
const searchStart = packAreaEnd - packInfoResult.packSize;
|
|
140
|
+
const searchEnd = Math.max(SIGNATURE_HEADER_SIZE, compressedStart - 100000);
|
|
141
141
|
// Scan for LZMA data starting with 0x00 (range coder init)
|
|
142
142
|
// Try each candidate and validate with CRC
|
|
143
|
-
|
|
144
|
-
searchLoop: for(
|
|
145
|
-
|
|
146
|
-
for(
|
|
143
|
+
const scanChunkSize = 4096;
|
|
144
|
+
searchLoop: for(let chunkStart = searchStart; chunkStart >= searchEnd; chunkStart -= scanChunkSize){
|
|
145
|
+
const chunk = this.source.read(chunkStart, scanChunkSize + packInfoResult.packSize);
|
|
146
|
+
for(let i = 0; i < Math.min(chunk.length, scanChunkSize); i++){
|
|
147
147
|
if (chunk[i] === 0x00) {
|
|
148
|
-
|
|
148
|
+
const candidateData = chunk.subarray(i, i + packInfoResult.packSize);
|
|
149
149
|
if (candidateData.length === packInfoResult.packSize) {
|
|
150
150
|
try {
|
|
151
|
-
|
|
151
|
+
const candidateDecompressed = codec.decode(candidateData, packInfoResult.properties, packInfoResult.unpackSize);
|
|
152
152
|
if (packInfoResult.unpackCRC !== undefined) {
|
|
153
|
-
|
|
153
|
+
const candCRC = crc32(candidateDecompressed);
|
|
154
154
|
if (candCRC === packInfoResult.unpackCRC) {
|
|
155
155
|
decompressedHeader = candidateDecompressed;
|
|
156
156
|
break searchLoop;
|
|
@@ -172,13 +172,13 @@ import { readNumber } from './NumberCodec.js';
|
|
|
172
172
|
}
|
|
173
173
|
// Now parse the decompressed header
|
|
174
174
|
// It should start with kHeader
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
let decompOffset = 0;
|
|
176
|
+
const headerId = decompressedHeader[decompOffset++];
|
|
177
177
|
if (headerId !== PropertyId.kHeader) {
|
|
178
178
|
throw createCodedError('Expected kHeader in decompressed header', ErrorCode.CORRUPT_HEADER);
|
|
179
179
|
}
|
|
180
180
|
// Parse the decompressed header using shared function from headers.ts
|
|
181
|
-
|
|
181
|
+
const result = parseHeaderContent(decompressedHeader, decompOffset);
|
|
182
182
|
this.streamsInfo = result.streamsInfo || null;
|
|
183
183
|
this.filesInfo = result.filesInfo;
|
|
184
184
|
}
|
|
@@ -187,30 +187,30 @@ import { readNumber } from './NumberCodec.js';
|
|
|
187
187
|
* This is a simplified parser for the header's own compression info
|
|
188
188
|
*/ parseEncodedHeaderStreams(buf, offset) {
|
|
189
189
|
// This is a simplified parser for the encoded header's own streams info
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
190
|
+
let packPos = 0;
|
|
191
|
+
let packSize = 0;
|
|
192
|
+
let unpackSize = 0;
|
|
193
|
+
let codecId = [];
|
|
194
|
+
let properties;
|
|
195
|
+
let unpackCRC;
|
|
196
196
|
while(offset < buf.length){
|
|
197
|
-
|
|
197
|
+
const propertyId = buf[offset++];
|
|
198
198
|
if (propertyId === PropertyId.kEnd) {
|
|
199
199
|
break;
|
|
200
200
|
}
|
|
201
201
|
switch(propertyId){
|
|
202
202
|
case PropertyId.kPackInfo:
|
|
203
203
|
{
|
|
204
|
-
|
|
204
|
+
const packPosResult = readNumber(buf, offset);
|
|
205
205
|
packPos = packPosResult.value;
|
|
206
206
|
offset += packPosResult.bytesRead;
|
|
207
|
-
|
|
207
|
+
const numPackResult = readNumber(buf, offset);
|
|
208
208
|
offset += numPackResult.bytesRead;
|
|
209
209
|
// Read until kEnd
|
|
210
210
|
while(buf[offset] !== PropertyId.kEnd){
|
|
211
211
|
if (buf[offset] === PropertyId.kSize) {
|
|
212
212
|
offset++;
|
|
213
|
-
|
|
213
|
+
const sizeResult = readNumber(buf, offset);
|
|
214
214
|
packSize = sizeResult.value;
|
|
215
215
|
offset += sizeResult.bytesRead;
|
|
216
216
|
} else {
|
|
@@ -225,21 +225,21 @@ import { readNumber } from './NumberCodec.js';
|
|
|
225
225
|
while(offset < buf.length && buf[offset] !== PropertyId.kEnd){
|
|
226
226
|
if (buf[offset] === PropertyId.kFolder) {
|
|
227
227
|
offset++;
|
|
228
|
-
|
|
228
|
+
const numFoldersResult = readNumber(buf, offset);
|
|
229
229
|
offset += numFoldersResult.bytesRead;
|
|
230
230
|
offset++; // external flag
|
|
231
231
|
// Parse coder
|
|
232
|
-
|
|
232
|
+
const numCodersResult = readNumber(buf, offset);
|
|
233
233
|
offset += numCodersResult.bytesRead;
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
234
|
+
const flags = buf[offset++];
|
|
235
|
+
const idSize = flags & 0x0f;
|
|
236
|
+
const hasAttributes = (flags & 0x20) !== 0;
|
|
237
237
|
codecId = [];
|
|
238
|
-
for(
|
|
238
|
+
for(let i = 0; i < idSize; i++){
|
|
239
239
|
codecId.push(buf[offset++]);
|
|
240
240
|
}
|
|
241
241
|
if (hasAttributes) {
|
|
242
|
-
|
|
242
|
+
const propsLenResult = readNumber(buf, offset);
|
|
243
243
|
offset += propsLenResult.bytesRead;
|
|
244
244
|
properties = buf.slice(offset, offset + propsLenResult.value);
|
|
245
245
|
offset += propsLenResult.value;
|
|
@@ -247,12 +247,12 @@ import { readNumber } from './NumberCodec.js';
|
|
|
247
247
|
} else if (buf[offset] === PropertyId.kCodersUnpackSize) {
|
|
248
248
|
offset++;
|
|
249
249
|
// Read unpack size - needed for LZMA decoder
|
|
250
|
-
|
|
250
|
+
const unpackSizeResult = readNumber(buf, offset);
|
|
251
251
|
unpackSize = unpackSizeResult.value;
|
|
252
252
|
offset += unpackSizeResult.bytesRead;
|
|
253
253
|
} else if (buf[offset] === PropertyId.kCRC) {
|
|
254
254
|
offset++;
|
|
255
|
-
|
|
255
|
+
const allDefined = buf[offset++];
|
|
256
256
|
if (allDefined) {
|
|
257
257
|
unpackCRC = buf.readUInt32LE(offset);
|
|
258
258
|
offset += 4;
|
|
@@ -280,32 +280,32 @@ import { readNumber } from './NumberCodec.js';
|
|
|
280
280
|
this.entries = [];
|
|
281
281
|
if (!this.streamsInfo) {
|
|
282
282
|
// No streams info - just create entries from file info
|
|
283
|
-
for(
|
|
284
|
-
|
|
283
|
+
for(let i = 0; i < this.filesInfo.length; i++){
|
|
284
|
+
const file = this.filesInfo[i];
|
|
285
285
|
this.entries.push(this.createEntry(file, 0, 0, 0));
|
|
286
286
|
}
|
|
287
287
|
return;
|
|
288
288
|
}
|
|
289
289
|
// Use the properly parsed numUnpackStreamsPerFolder from the archive header
|
|
290
|
-
|
|
290
|
+
const streamsPerFolder = this.streamsInfo.numUnpackStreamsPerFolder;
|
|
291
291
|
// Initialize files per folder count (for smart caching)
|
|
292
|
-
for(
|
|
292
|
+
for(let f = 0; f < streamsPerFolder.length; f++){
|
|
293
293
|
this.filesPerFolder[f] = streamsPerFolder[f];
|
|
294
294
|
this.extractedPerFolder[f] = 0;
|
|
295
295
|
}
|
|
296
296
|
// Now build entries with proper folder/stream tracking
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
for(
|
|
302
|
-
|
|
297
|
+
let streamIndex = 0;
|
|
298
|
+
let folderIndex = 0;
|
|
299
|
+
let streamInFolder = 0;
|
|
300
|
+
let folderStreamCount = streamsPerFolder[0] || 0;
|
|
301
|
+
for(let j = 0; j < this.filesInfo.length; j++){
|
|
302
|
+
const fileInfo = this.filesInfo[j];
|
|
303
303
|
// Get size from unpackSizes for files with streams
|
|
304
|
-
|
|
304
|
+
let size = 0;
|
|
305
305
|
if (fileInfo.hasStream && streamIndex < this.streamsInfo.unpackSizes.length) {
|
|
306
306
|
size = this.streamsInfo.unpackSizes[streamIndex];
|
|
307
307
|
}
|
|
308
|
-
|
|
308
|
+
const entry = this.createEntry(fileInfo, size, folderIndex, streamInFolder);
|
|
309
309
|
entry._streamIndex = streamIndex;
|
|
310
310
|
// Set CRC if available
|
|
311
311
|
if (fileInfo.hasStream && this.streamsInfo.unpackCRCs && this.streamsInfo.unpackCRCs[streamIndex] !== undefined) {
|
|
@@ -331,12 +331,12 @@ import { readNumber } from './NumberCodec.js';
|
|
|
331
331
|
// Determine entry type
|
|
332
332
|
// Note: 7z format doesn't natively support symlinks. p7zip with -snl stores
|
|
333
333
|
// symlinks as regular files with the target path as content.
|
|
334
|
-
|
|
334
|
+
let type = 'file';
|
|
335
335
|
if (file.isDirectory) {
|
|
336
336
|
type = 'directory';
|
|
337
337
|
}
|
|
338
338
|
// Calculate mode from Windows attributes
|
|
339
|
-
|
|
339
|
+
let mode;
|
|
340
340
|
if (file.attributes !== undefined) {
|
|
341
341
|
// Check for Unix extension bit
|
|
342
342
|
if ((file.attributes & FileAttribute.UNIX_EXTENSION) !== 0) {
|
|
@@ -381,7 +381,7 @@ import { readNumber } from './NumberCodec.js';
|
|
|
381
381
|
*/ getEntryStream(entry) {
|
|
382
382
|
if (!entry._hasStream || entry.type === 'directory') {
|
|
383
383
|
// Return empty stream for directories and empty files
|
|
384
|
-
|
|
384
|
+
const emptyStream = new PassThrough();
|
|
385
385
|
emptyStream.end();
|
|
386
386
|
return emptyStream;
|
|
387
387
|
}
|
|
@@ -389,40 +389,40 @@ import { readNumber } from './NumberCodec.js';
|
|
|
389
389
|
throw createCodedError('No streams info available', ErrorCode.CORRUPT_HEADER);
|
|
390
390
|
}
|
|
391
391
|
// Get folder info
|
|
392
|
-
|
|
392
|
+
const folder = this.streamsInfo.folders[entry._folderIndex];
|
|
393
393
|
if (!folder) {
|
|
394
394
|
throw createCodedError('Invalid folder index', ErrorCode.CORRUPT_HEADER);
|
|
395
395
|
}
|
|
396
396
|
// Check codec support
|
|
397
|
-
for(
|
|
398
|
-
|
|
397
|
+
for(let i = 0; i < folder.coders.length; i++){
|
|
398
|
+
const coder = folder.coders[i];
|
|
399
399
|
if (!isCodecSupported(coder.id)) {
|
|
400
|
-
|
|
400
|
+
const codecName = getCodecName(coder.id);
|
|
401
401
|
throw createCodedError(`Unsupported codec: ${codecName}`, ErrorCode.UNSUPPORTED_CODEC);
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
404
|
// Get decompressed data for this folder (with smart caching)
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
const folderIdx = entry._folderIndex;
|
|
406
|
+
const data = this.getDecompressedFolder(folderIdx);
|
|
407
407
|
// Calculate file offset within the decompressed block
|
|
408
408
|
// For solid archives, multiple files are concatenated in the block
|
|
409
|
-
|
|
410
|
-
for(
|
|
409
|
+
let fileStart = 0;
|
|
410
|
+
for(let m = 0; m < entry._streamIndexInFolder; m++){
|
|
411
411
|
// Sum sizes of all streams before this one in the folder
|
|
412
|
-
|
|
412
|
+
const prevStreamGlobalIndex = entry._streamIndex - entry._streamIndexInFolder + m;
|
|
413
413
|
fileStart += this.streamsInfo.unpackSizes[prevStreamGlobalIndex];
|
|
414
414
|
}
|
|
415
|
-
|
|
415
|
+
const fileSize = entry.size;
|
|
416
416
|
// Create a PassThrough stream with the file data
|
|
417
|
-
|
|
417
|
+
const outputStream = new PassThrough();
|
|
418
418
|
// Bounds check to prevent "oob" error on older Node versions
|
|
419
419
|
if (fileStart + fileSize > data.length) {
|
|
420
420
|
throw createCodedError(`File data out of bounds: offset ${fileStart} + size ${fileSize} > decompressed length ${data.length}`, ErrorCode.DECOMPRESSION_FAILED);
|
|
421
421
|
}
|
|
422
|
-
|
|
422
|
+
const fileData = data.slice(fileStart, fileStart + fileSize);
|
|
423
423
|
// Verify CRC if present
|
|
424
424
|
if (entry._crc !== undefined) {
|
|
425
|
-
|
|
425
|
+
const actualCRC = crc32(fileData);
|
|
426
426
|
if (actualCRC !== entry._crc) {
|
|
427
427
|
throw createCodedError(`CRC mismatch for ${entry.path}: expected ${entry._crc.toString(16)}, got ${actualCRC.toString(16)}`, ErrorCode.CRC_MISMATCH);
|
|
428
428
|
}
|
|
@@ -442,7 +442,7 @@ import { readNumber } from './NumberCodec.js';
|
|
|
442
442
|
*/ getEntryStreamAsync(entry, callback) {
|
|
443
443
|
if (!entry._hasStream || entry.type === 'directory') {
|
|
444
444
|
// Return empty stream for directories and empty files
|
|
445
|
-
|
|
445
|
+
const emptyStream = new PassThrough();
|
|
446
446
|
emptyStream.end();
|
|
447
447
|
callback(null, emptyStream);
|
|
448
448
|
return;
|
|
@@ -452,43 +452,43 @@ import { readNumber } from './NumberCodec.js';
|
|
|
452
452
|
return;
|
|
453
453
|
}
|
|
454
454
|
// Get folder info
|
|
455
|
-
|
|
455
|
+
const folder = this.streamsInfo.folders[entry._folderIndex];
|
|
456
456
|
if (!folder) {
|
|
457
457
|
callback(createCodedError('Invalid folder index', ErrorCode.CORRUPT_HEADER));
|
|
458
458
|
return;
|
|
459
459
|
}
|
|
460
460
|
// Check codec support
|
|
461
|
-
for(
|
|
462
|
-
|
|
461
|
+
for(let i = 0; i < folder.coders.length; i++){
|
|
462
|
+
const coder = folder.coders[i];
|
|
463
463
|
if (!isCodecSupported(coder.id)) {
|
|
464
|
-
|
|
464
|
+
const codecName = getCodecName(coder.id);
|
|
465
465
|
callback(createCodedError(`Unsupported codec: ${codecName}`, ErrorCode.UNSUPPORTED_CODEC));
|
|
466
466
|
return;
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
469
|
// Get decompressed data for this folder using async method
|
|
470
|
-
|
|
471
|
-
|
|
470
|
+
const folderIdx = entry._folderIndex;
|
|
471
|
+
const streamsInfo = this.streamsInfo;
|
|
472
472
|
this.getDecompressedFolderAsync(folderIdx, (err, data)=>{
|
|
473
473
|
if (err) return callback(err);
|
|
474
474
|
if (!data) return callback(new Error('No data returned from decompression'));
|
|
475
475
|
// Calculate file offset within the decompressed block
|
|
476
|
-
|
|
477
|
-
for(
|
|
478
|
-
|
|
476
|
+
let fileStart = 0;
|
|
477
|
+
for(let m = 0; m < entry._streamIndexInFolder; m++){
|
|
478
|
+
const prevStreamGlobalIndex = entry._streamIndex - entry._streamIndexInFolder + m;
|
|
479
479
|
fileStart += streamsInfo.unpackSizes[prevStreamGlobalIndex];
|
|
480
480
|
}
|
|
481
|
-
|
|
481
|
+
const fileSize = entry.size;
|
|
482
482
|
// Bounds check
|
|
483
483
|
if (fileStart + fileSize > data.length) {
|
|
484
484
|
return callback(createCodedError(`File data out of bounds: offset ${fileStart} + size ${fileSize} > decompressed length ${data.length}`, ErrorCode.DECOMPRESSION_FAILED));
|
|
485
485
|
}
|
|
486
486
|
// Create a PassThrough stream with the file data
|
|
487
|
-
|
|
488
|
-
|
|
487
|
+
const outputStream = new PassThrough();
|
|
488
|
+
const fileData = data.slice(fileStart, fileStart + fileSize);
|
|
489
489
|
// Verify CRC if present
|
|
490
490
|
if (entry._crc !== undefined) {
|
|
491
|
-
|
|
491
|
+
const actualCRC = crc32(fileData);
|
|
492
492
|
if (actualCRC !== entry._crc) {
|
|
493
493
|
return callback(createCodedError(`CRC mismatch for ${entry.path}: expected ${entry._crc.toString(16)}, got ${actualCRC.toString(16)}`, ErrorCode.CRC_MISMATCH));
|
|
494
494
|
}
|
|
@@ -505,7 +505,7 @@ import { readNumber } from './NumberCodec.js';
|
|
|
505
505
|
/**
|
|
506
506
|
* Check if a folder uses BCJ2 codec
|
|
507
507
|
*/ folderHasBcj2(folder) {
|
|
508
|
-
for(
|
|
508
|
+
for(let i = 0; i < folder.coders.length; i++){
|
|
509
509
|
if (isBcj2Codec(folder.coders[i].id)) {
|
|
510
510
|
return true;
|
|
511
511
|
}
|
|
@@ -523,42 +523,42 @@ import { readNumber } from './NumberCodec.js';
|
|
|
523
523
|
if (!this.streamsInfo) {
|
|
524
524
|
throw createCodedError('No streams info available', ErrorCode.CORRUPT_HEADER);
|
|
525
525
|
}
|
|
526
|
-
|
|
526
|
+
const folder = this.streamsInfo.folders[folderIndex];
|
|
527
527
|
// Check how many files remain in this folder
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
528
|
+
const filesInFolder = this.filesPerFolder[folderIndex] || 1;
|
|
529
|
+
const extractedFromFolder = this.extractedPerFolder[folderIndex] || 0;
|
|
530
|
+
const remainingFiles = filesInFolder - extractedFromFolder;
|
|
531
531
|
// Only cache if more than 1 file remains (including the current one being extracted)
|
|
532
|
-
|
|
532
|
+
const shouldCache = remainingFiles > 1;
|
|
533
533
|
// Check if this folder uses BCJ2 (requires special multi-stream handling)
|
|
534
534
|
if (this.folderHasBcj2(folder)) {
|
|
535
|
-
|
|
535
|
+
const data = this.decompressBcj2Folder(folderIndex);
|
|
536
536
|
if (shouldCache) {
|
|
537
537
|
this.decompressedCache[folderIndex] = data;
|
|
538
538
|
}
|
|
539
539
|
return data;
|
|
540
540
|
}
|
|
541
541
|
// Calculate packed data position
|
|
542
|
-
|
|
542
|
+
let packPos = SIGNATURE_HEADER_SIZE + this.streamsInfo.packPos;
|
|
543
543
|
// Find which pack stream this folder uses
|
|
544
|
-
|
|
545
|
-
for(
|
|
544
|
+
let packStreamIndex = 0;
|
|
545
|
+
for(let j = 0; j < folderIndex; j++){
|
|
546
546
|
packStreamIndex += this.streamsInfo.folders[j].packedStreams.length;
|
|
547
547
|
}
|
|
548
548
|
// Calculate position of this pack stream
|
|
549
|
-
for(
|
|
549
|
+
for(let k = 0; k < packStreamIndex; k++){
|
|
550
550
|
packPos += this.streamsInfo.packSizes[k];
|
|
551
551
|
}
|
|
552
|
-
|
|
552
|
+
const packSize = this.streamsInfo.packSizes[packStreamIndex];
|
|
553
553
|
// Read packed data
|
|
554
|
-
|
|
554
|
+
const packedData = this.source.read(packPos, packSize);
|
|
555
555
|
// Decompress through codec chain
|
|
556
|
-
|
|
557
|
-
for(
|
|
558
|
-
|
|
559
|
-
|
|
556
|
+
let data2 = packedData;
|
|
557
|
+
for(let l = 0; l < folder.coders.length; l++){
|
|
558
|
+
const coderInfo = folder.coders[l];
|
|
559
|
+
const codec = getCodec(coderInfo.id);
|
|
560
560
|
// Get unpack size for this coder (needed by LZMA)
|
|
561
|
-
|
|
561
|
+
const unpackSize = folder.unpackSizes[l];
|
|
562
562
|
data2 = codec.decode(data2, coderInfo.properties, unpackSize);
|
|
563
563
|
}
|
|
564
564
|
// Cache only if more files remain in this folder
|
|
@@ -571,7 +571,7 @@ import { readNumber } from './NumberCodec.js';
|
|
|
571
571
|
* Get decompressed data for a folder using streaming (callback-based async)
|
|
572
572
|
* Uses createDecoder() streams for non-blocking decompression
|
|
573
573
|
*/ getDecompressedFolderAsync(folderIndex, callback) {
|
|
574
|
-
|
|
574
|
+
const self = this;
|
|
575
575
|
// Check cache first
|
|
576
576
|
if (this.decompressedCache[folderIndex]) {
|
|
577
577
|
callback(null, this.decompressedCache[folderIndex]);
|
|
@@ -581,17 +581,17 @@ import { readNumber } from './NumberCodec.js';
|
|
|
581
581
|
callback(createCodedError('No streams info available', ErrorCode.CORRUPT_HEADER));
|
|
582
582
|
return;
|
|
583
583
|
}
|
|
584
|
-
|
|
584
|
+
const folder = this.streamsInfo.folders[folderIndex];
|
|
585
585
|
// Check how many files remain in this folder
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
586
|
+
const filesInFolder = this.filesPerFolder[folderIndex] || 1;
|
|
587
|
+
const extractedFromFolder = this.extractedPerFolder[folderIndex] || 0;
|
|
588
|
+
const remainingFiles = filesInFolder - extractedFromFolder;
|
|
589
|
+
const shouldCache = remainingFiles > 1;
|
|
590
590
|
// BCJ2 requires special handling - use sync version for now
|
|
591
591
|
// TODO: Add async BCJ2 support
|
|
592
592
|
if (this.folderHasBcj2(folder)) {
|
|
593
593
|
try {
|
|
594
|
-
|
|
594
|
+
const data = this.decompressBcj2Folder(folderIndex);
|
|
595
595
|
if (shouldCache) {
|
|
596
596
|
this.decompressedCache[folderIndex] = data;
|
|
597
597
|
}
|
|
@@ -602,29 +602,29 @@ import { readNumber } from './NumberCodec.js';
|
|
|
602
602
|
return;
|
|
603
603
|
}
|
|
604
604
|
// Calculate packed data position
|
|
605
|
-
|
|
605
|
+
let packPos = SIGNATURE_HEADER_SIZE + this.streamsInfo.packPos;
|
|
606
606
|
// Find which pack stream this folder uses
|
|
607
|
-
|
|
608
|
-
for(
|
|
607
|
+
let packStreamIndex = 0;
|
|
608
|
+
for(let j = 0; j < folderIndex; j++){
|
|
609
609
|
packStreamIndex += this.streamsInfo.folders[j].packedStreams.length;
|
|
610
610
|
}
|
|
611
611
|
// Calculate position of this pack stream
|
|
612
|
-
for(
|
|
612
|
+
for(let k = 0; k < packStreamIndex; k++){
|
|
613
613
|
packPos += this.streamsInfo.packSizes[k];
|
|
614
614
|
}
|
|
615
|
-
|
|
615
|
+
const packSize = this.streamsInfo.packSizes[packStreamIndex];
|
|
616
616
|
// Read packed data
|
|
617
|
-
|
|
617
|
+
const packedData = this.source.read(packPos, packSize);
|
|
618
618
|
// Create decoder stream chain and decompress
|
|
619
|
-
|
|
620
|
-
|
|
619
|
+
const coders = folder.coders;
|
|
620
|
+
const unpackSizes = folder.unpackSizes;
|
|
621
621
|
// Helper to decompress through a single codec stream
|
|
622
622
|
function decompressWithStream(input, coderIdx, cb) {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
623
|
+
const coderInfo = coders[coderIdx];
|
|
624
|
+
const codec = getCodec(coderInfo.id);
|
|
625
|
+
const decoder = codec.createDecoder(coderInfo.properties, unpackSizes[coderIdx]);
|
|
626
|
+
const chunks = [];
|
|
627
|
+
let errorOccurred = false;
|
|
628
628
|
decoder.on('data', (chunk)=>{
|
|
629
629
|
chunks.push(chunk);
|
|
630
630
|
});
|
|
@@ -672,24 +672,24 @@ import { readNumber } from './NumberCodec.js';
|
|
|
672
672
|
if (!this.streamsInfo) {
|
|
673
673
|
throw createCodedError('No streams info available', ErrorCode.CORRUPT_HEADER);
|
|
674
674
|
}
|
|
675
|
-
|
|
675
|
+
const folder = this.streamsInfo.folders[folderIndex];
|
|
676
676
|
// Calculate starting pack position
|
|
677
|
-
|
|
677
|
+
let packPos = SIGNATURE_HEADER_SIZE + this.streamsInfo.packPos;
|
|
678
678
|
// Find which pack stream index this folder starts at
|
|
679
|
-
|
|
680
|
-
for(
|
|
679
|
+
let packStreamIndex = 0;
|
|
680
|
+
for(let j = 0; j < folderIndex; j++){
|
|
681
681
|
packStreamIndex += this.streamsInfo.folders[j].packedStreams.length;
|
|
682
682
|
}
|
|
683
683
|
// Calculate position
|
|
684
|
-
for(
|
|
684
|
+
for(let k = 0; k < packStreamIndex; k++){
|
|
685
685
|
packPos += this.streamsInfo.packSizes[k];
|
|
686
686
|
}
|
|
687
687
|
// Read all pack streams for this folder
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
for(
|
|
692
|
-
|
|
688
|
+
const numPackStreams = folder.packedStreams.length;
|
|
689
|
+
const packStreams = [];
|
|
690
|
+
let currentPos = packPos;
|
|
691
|
+
for(let p = 0; p < numPackStreams; p++){
|
|
692
|
+
const size = this.streamsInfo.packSizes[packStreamIndex + p];
|
|
693
693
|
packStreams.push(this.source.read(currentPos, size));
|
|
694
694
|
currentPos += size;
|
|
695
695
|
}
|
|
@@ -701,10 +701,10 @@ import { readNumber } from './NumberCodec.js';
|
|
|
701
701
|
// Coder 3: BCJ2 - 4 in, 1 out
|
|
702
702
|
// Pack streams map to: coder inputs not bound to other coder outputs
|
|
703
703
|
// First, decompress each non-BCJ2 coder
|
|
704
|
-
|
|
704
|
+
const coderOutputs = {};
|
|
705
705
|
// Find the BCJ2 coder
|
|
706
|
-
|
|
707
|
-
for(
|
|
706
|
+
let bcj2CoderIndex = -1;
|
|
707
|
+
for(let c = 0; c < folder.coders.length; c++){
|
|
708
708
|
if (isBcj2Codec(folder.coders[c].id)) {
|
|
709
709
|
bcj2CoderIndex = c;
|
|
710
710
|
break;
|
|
@@ -715,44 +715,44 @@ import { readNumber } from './NumberCodec.js';
|
|
|
715
715
|
}
|
|
716
716
|
// Build input stream index -> pack stream mapping
|
|
717
717
|
// folder.packedStreams tells us which input indices are unbound and their order
|
|
718
|
-
|
|
719
|
-
for(
|
|
718
|
+
const inputToPackStream = {};
|
|
719
|
+
for(let pi = 0; pi < folder.packedStreams.length; pi++){
|
|
720
720
|
inputToPackStream[folder.packedStreams[pi]] = pi;
|
|
721
721
|
}
|
|
722
722
|
// Build output stream index -> coder mapping
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
for(
|
|
726
|
-
|
|
727
|
-
for(
|
|
723
|
+
const outputToCoder = {};
|
|
724
|
+
let totalOutputs = 0;
|
|
725
|
+
for(let co = 0; co < folder.coders.length; co++){
|
|
726
|
+
const numOut = folder.coders[co].numOutStreams;
|
|
727
|
+
for(let outp = 0; outp < numOut; outp++){
|
|
728
728
|
outputToCoder[totalOutputs + outp] = co;
|
|
729
729
|
}
|
|
730
730
|
totalOutputs += numOut;
|
|
731
731
|
}
|
|
732
732
|
// Decompress non-BCJ2 coders (LZMA, LZMA2)
|
|
733
733
|
// We need to process in dependency order
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
for(
|
|
737
|
-
|
|
734
|
+
const processed = {};
|
|
735
|
+
const processOrder = this.getCoderProcessOrder(folder, bcj2CoderIndex);
|
|
736
|
+
for(let po = 0; po < processOrder.length; po++){
|
|
737
|
+
const coderIdx = processOrder[po];
|
|
738
738
|
if (coderIdx === bcj2CoderIndex) continue;
|
|
739
|
-
|
|
740
|
-
|
|
739
|
+
const coder = folder.coders[coderIdx];
|
|
740
|
+
const codec = getCodec(coder.id);
|
|
741
741
|
// Find input for this coder
|
|
742
|
-
|
|
743
|
-
for(
|
|
742
|
+
let coderInputStart = 0;
|
|
743
|
+
for(let ci2 = 0; ci2 < coderIdx; ci2++){
|
|
744
744
|
coderInputStart += folder.coders[ci2].numInStreams;
|
|
745
745
|
}
|
|
746
746
|
// Get input data (from pack stream)
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
747
|
+
const inputIdx = coderInputStart;
|
|
748
|
+
const packStreamIdx = inputToPackStream[inputIdx];
|
|
749
|
+
const inputData = packStreams[packStreamIdx];
|
|
750
750
|
// Decompress
|
|
751
|
-
|
|
752
|
-
|
|
751
|
+
const unpackSize = folder.unpackSizes[coderIdx];
|
|
752
|
+
const outputData = codec.decode(inputData, coder.properties, unpackSize);
|
|
753
753
|
// Store in coder outputs
|
|
754
|
-
|
|
755
|
-
for(
|
|
754
|
+
let coderOutputStart = 0;
|
|
755
|
+
for(let co2 = 0; co2 < coderIdx; co2++){
|
|
756
756
|
coderOutputStart += folder.coders[co2].numOutStreams;
|
|
757
757
|
}
|
|
758
758
|
coderOutputs[coderOutputStart] = outputData;
|
|
@@ -761,16 +761,16 @@ import { readNumber } from './NumberCodec.js';
|
|
|
761
761
|
// Now process BCJ2
|
|
762
762
|
// BCJ2 has 4 inputs, need to map them correctly
|
|
763
763
|
// Standard order: main(LZMA2 output), call(LZMA output), jump(LZMA output), range(raw pack)
|
|
764
|
-
|
|
765
|
-
for(
|
|
764
|
+
let bcj2InputStart = 0;
|
|
765
|
+
for(let ci3 = 0; ci3 < bcj2CoderIndex; ci3++){
|
|
766
766
|
bcj2InputStart += folder.coders[ci3].numInStreams;
|
|
767
767
|
}
|
|
768
|
-
|
|
769
|
-
for(
|
|
770
|
-
|
|
768
|
+
const bcj2Inputs = [];
|
|
769
|
+
for(let bi = 0; bi < 4; bi++){
|
|
770
|
+
const globalIdx = bcj2InputStart + bi;
|
|
771
771
|
// Check if this input is bound to a coder output
|
|
772
|
-
|
|
773
|
-
for(
|
|
772
|
+
let boundOutput = -1;
|
|
773
|
+
for(let bp2 = 0; bp2 < folder.bindPairs.length; bp2++){
|
|
774
774
|
if (folder.bindPairs[bp2].inIndex === globalIdx) {
|
|
775
775
|
boundOutput = folder.bindPairs[bp2].outIndex;
|
|
776
776
|
break;
|
|
@@ -781,19 +781,19 @@ import { readNumber } from './NumberCodec.js';
|
|
|
781
781
|
bcj2Inputs.push(coderOutputs[boundOutput]);
|
|
782
782
|
} else {
|
|
783
783
|
// Get from pack streams
|
|
784
|
-
|
|
784
|
+
const psIdx = inputToPackStream[globalIdx];
|
|
785
785
|
bcj2Inputs.push(packStreams[psIdx]);
|
|
786
786
|
}
|
|
787
787
|
}
|
|
788
788
|
// Get BCJ2 unpack size
|
|
789
|
-
|
|
790
|
-
for(
|
|
789
|
+
let bcj2OutputStart = 0;
|
|
790
|
+
for(let co3 = 0; co3 < bcj2CoderIndex; co3++){
|
|
791
791
|
bcj2OutputStart += folder.coders[co3].numOutStreams;
|
|
792
792
|
}
|
|
793
|
-
|
|
793
|
+
const bcj2UnpackSize = folder.unpackSizes[bcj2OutputStart];
|
|
794
794
|
// Memory optimization: Clear intermediate buffers to help GC
|
|
795
795
|
// These are no longer needed after bcj2Inputs is built
|
|
796
|
-
for(
|
|
796
|
+
for(const key in coderOutputs){
|
|
797
797
|
delete coderOutputs[key];
|
|
798
798
|
}
|
|
799
799
|
// Clear packStreams array (allows GC to free compressed data)
|
|
@@ -804,30 +804,30 @@ import { readNumber } from './NumberCodec.js';
|
|
|
804
804
|
/**
|
|
805
805
|
* Get processing order for coders (dependency order)
|
|
806
806
|
*/ getCoderProcessOrder(folder, excludeIdx) {
|
|
807
|
-
|
|
808
|
-
|
|
807
|
+
const order = [];
|
|
808
|
+
const processed = {};
|
|
809
809
|
// Simple approach: process coders that don't depend on unprocessed outputs
|
|
810
|
-
|
|
810
|
+
let changed = true;
|
|
811
811
|
while(changed){
|
|
812
812
|
changed = false;
|
|
813
|
-
for(
|
|
813
|
+
for(let c = 0; c < folder.coders.length; c++){
|
|
814
814
|
if (processed[c] || c === excludeIdx) continue;
|
|
815
815
|
// Check if all inputs are satisfied
|
|
816
|
-
|
|
817
|
-
for(
|
|
816
|
+
let inputStart = 0;
|
|
817
|
+
for(let i = 0; i < c; i++){
|
|
818
818
|
inputStart += folder.coders[i].numInStreams;
|
|
819
819
|
}
|
|
820
|
-
|
|
821
|
-
for(
|
|
822
|
-
|
|
820
|
+
let canProcess = true;
|
|
821
|
+
for(let inp = 0; inp < folder.coders[c].numInStreams; inp++){
|
|
822
|
+
const globalIdx = inputStart + inp;
|
|
823
823
|
// Check if bound to an unprocessed coder
|
|
824
|
-
for(
|
|
824
|
+
for(let bp = 0; bp < folder.bindPairs.length; bp++){
|
|
825
825
|
if (folder.bindPairs[bp].inIndex === globalIdx) {
|
|
826
826
|
// Find which coder produces this output
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
for(
|
|
830
|
-
|
|
827
|
+
const outIdx = folder.bindPairs[bp].outIndex;
|
|
828
|
+
let outStart = 0;
|
|
829
|
+
for(let oc = 0; oc < folder.coders.length; oc++){
|
|
830
|
+
const numOut = folder.coders[oc].numOutStreams;
|
|
831
831
|
if (outIdx < outStart + numOut) {
|
|
832
832
|
if (!processed[oc] && oc !== excludeIdx) {
|
|
833
833
|
canProcess = false;
|
|
@@ -873,8 +873,8 @@ import { readNumber } from './NumberCodec.js';
|
|
|
873
873
|
/**
|
|
874
874
|
* Get base name from a path
|
|
875
875
|
*/ function getBaseName(path) {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
876
|
+
const lastSlash = path.lastIndexOf('/');
|
|
877
|
+
const lastBackslash = path.lastIndexOf('\\');
|
|
878
|
+
const lastSep = Math.max(lastSlash, lastBackslash);
|
|
879
879
|
return lastSep >= 0 ? path.slice(lastSep + 1) : path;
|
|
880
880
|
}
|