7z keeps its file list at the end of the archive, so the 7z-tail candidates (the last segment of the highest volume) were queued but never probed, and the .7z.001 start only gave the type. The prober now claims 7z-tail candidates after the archives; lib/sevenzip finds the end header in the article, decodes the LZMA-packed header (a TypeScript port of the LZMA SDK's reference decoder) and lists the files with their sizes. An AES-encrypted header means passworded without names. Names feed the inner name and the judge's fake rule. An unsplit .7z of several segments now also gets a tail candidate, and .zip files an archive candidate: their first segment's local headers give the first entries and whether they are encrypted. Both in the Rust edge and the TypeScript indexer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 lines
2.0 KiB
TypeScript
46 lines
2.0 KiB
TypeScript
import { test } from '@japa/runner'
|
|
import { readFileSync } from 'node:fs'
|
|
import { parseSevenZipTail } from '#lib/sevenzip/index'
|
|
|
|
const fixture = (name: string) => readFileSync(new URL(`../../fixtures/sevenzip/${name}`, import.meta.url))
|
|
const DIR = 'Some.Movie.2020.1080p.BluRay.x264-GRP'
|
|
|
|
test.group('probe / 7z listing from the archive end', () => {
|
|
test('an LZMA-packed header (7z default): files with sizes, directories left out', ({ assert }) => {
|
|
const listing = parseSevenZipTail(fixture('plain.tail'))
|
|
assert.deepEqual(listing, {
|
|
files: [
|
|
{ name: `${DIR}/empty.txt`, size: 0 },
|
|
{ name: `${DIR}/Sample/sample.mkv`, size: 20000 },
|
|
{ name: `${DIR}/grp.nfo`, size: 4 },
|
|
{ name: `${DIR}/some.movie.2020.1080p.bluray.x264-grp.mkv`, size: 300000 },
|
|
],
|
|
encrypted: false,
|
|
headerEncrypted: false,
|
|
})
|
|
})
|
|
|
|
test('an uncompressed header (7z -mhc=off) and the last volume of a split archive', ({ assert }) => {
|
|
for (const name of ['uncompressed-header.tail', 'split-last-volume.tail']) {
|
|
const listing = parseSevenZipTail(fixture(name))!
|
|
assert.lengthOf(listing.files, 4, name)
|
|
assert.isFalse(listing.encrypted, name)
|
|
}
|
|
})
|
|
|
|
test('encrypted entries: names listed, encrypted; an encrypted header (7z -mhe): no names, encrypted', ({ assert }) => {
|
|
const files = parseSevenZipTail(fixture('files-encrypted.tail'))!
|
|
assert.lengthOf(files.files, 4)
|
|
assert.isTrue(files.encrypted)
|
|
assert.isFalse(files.headerEncrypted)
|
|
assert.deepEqual(parseSevenZipTail(fixture('header-encrypted.tail')), { files: [], encrypted: true, headerEncrypted: true })
|
|
})
|
|
|
|
test('a whole small archive; not the end of an archive: null', ({ assert }) => {
|
|
assert.deepEqual(parseSevenZipTail(fixture('tiny.7z'))?.files.map((f) => f.name), ['a.txt', 'b.nfo'])
|
|
// The end cut off, or data that isn't 7z at all.
|
|
assert.isNull(parseSevenZipTail(fixture('plain.tail').subarray(0, 30000)))
|
|
assert.isNull(parseSevenZipTail(fixture('sample.bin')))
|
|
})
|
|
})
|