Probe 7z listings and ZIP starts
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>
This commit is contained in:
1 parent
3b61215f6b
commit
d446bb57df
25 files changed
+4840
-11
No files matched your search
+40
-1
@@ -915,12 +915,17 @@ fn candidates_of(key: &str, files: &[Vec<Seg>], upload: usize) -> Vec<Candidate>
|
||||
let c = |kind, s: &Seg| Candidate { release_key: key.to_string(), upload, kind, message_id: s.message_id.clone(), file: s.file.name.clone() };
|
||||
for f in files {
|
||||
let name = &f[0].file.name;
|
||||
if let Some(volume) = names::seven_zip_volume(name).filter(|&v| v > 1) {
|
||||
let volume = names::seven_zip_volume(name);
|
||||
if let Some(volume) = volume.filter(|&v| v > 1) {
|
||||
if tail.is_none_or(|(v, _)| volume > v) {
|
||||
tail = Some((volume, f));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// An unsplit 7z of more than one segment: its listing is in its last one.
|
||||
if volume == Some(0) && f.len() > 1 && tail.is_none() {
|
||||
tail = Some((0, f));
|
||||
}
|
||||
if names::is_archive_start(name) {
|
||||
out.push(c("archive", &f[0]));
|
||||
} else if names::is_par2(name) && !names::is_later_volume(name) {
|
||||
@@ -965,6 +970,40 @@ mod tests {
|
||||
assert_eq!(batch.releases[0].key, batch.releases[1].key);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn archive_candidates_as_in_the_typescript() {
|
||||
let mut priorities = FxHashMap::default();
|
||||
priorities.insert(GROUP.to_string(), 1);
|
||||
let mut ix = RangeIndexer::new(GROUP, 1, 10_000, 1, Rules::defaults(priorities), 5);
|
||||
let file = |at: i64, release: &str, name: &str, n: usize, parts: i64| -> Vec<String> {
|
||||
(0..parts).map(|i| line(at + i, &format!(r#"{release} [{n}/3] - "{name}" yEnc ({}/{parts})"#, i + 1), 0)).collect()
|
||||
};
|
||||
let mut lines = Vec::new();
|
||||
// A split 7z: its start, and the end of its highest volume.
|
||||
lines.extend(file(100, "Split.Seven", "Split.Seven.7z.001", 1, 2));
|
||||
lines.extend(file(110, "Split.Seven", "Split.Seven.7z.003", 3, 2));
|
||||
lines.extend(file(120, "Split.Seven", "Split.Seven.7z.002", 2, 2));
|
||||
// An unsplit 7z of 3 segments: its start and its end.
|
||||
lines.extend(file(200, "Whole.Seven", "Whole.Seven.7z", 1, 3));
|
||||
// A ZIP: its start.
|
||||
lines.extend(file(300, "Some.Zip", "Some.Zip.zip", 1, 2));
|
||||
ix.add_text(&lines.join("\r\n"), 10_001);
|
||||
ix.finish();
|
||||
let batch = ix.take();
|
||||
let mut got: Vec<(&str, &str, &str)> = batch.candidates.iter().map(|c| (c.kind, c.file.as_str(), c.message_id.as_str())).collect();
|
||||
got.sort();
|
||||
assert_eq!(
|
||||
got,
|
||||
vec![
|
||||
("7z-tail", "Split.Seven.7z.003", "u111@test"),
|
||||
("7z-tail", "Whole.Seven.7z", "u202@test"),
|
||||
("archive", "Some.Zip.zip", "u300@test"),
|
||||
("archive", "Split.Seven.7z.001", "u100@test"),
|
||||
("archive", "Whole.Seven.7z", "u200@test"),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copies_and_fills_as_in_the_typescript() {
|
||||
let hour = 3_600_000i64;
|
||||
|
||||
+1
-1
@@ -1030,7 +1030,7 @@ static SEVEN: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.7z$"));
|
||||
static PART1: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.part0*1\.rar$"));
|
||||
static RAR: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.rar$"));
|
||||
static PART: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.part([0-9]+)\.rar$"));
|
||||
static BIN: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.bin$"));
|
||||
static BIN: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.(bin|zip)$"));
|
||||
static OLD_RAR: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.r[0-9]{2,3}$"));
|
||||
static PAR2_VOL: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.vol[0-9]+[+-][0-9]+\.par2$"));
|
||||
pub static PAR2: LazyLock<Regex> = LazyLock::new(|| re(r"(?i)\.par2$"));
|
||||
|
||||
Reference in new issue
Block a user