use std::fs::File;
use std::io::BufReader;
use std::path::{Path, PathBuf};
use crate::format::parser::read_archive_header;
use crate::format::streams::ResourceLimits;
use crate::volume::{MultiVolumeReader, VolumeReader};
use crate::{Error, Result};
use super::entries;
use super::{Archive, VolumeInfo};
pub(crate) fn detect_multivolume_base(path: &Path) -> Option<PathBuf> {
let path_str = path.to_string_lossy();
if let Some(pos) = path_str.rfind(".7z.") {
let suffix = &path_str[pos + 4..];
if !suffix.is_empty() && suffix.chars().all(|c| c.is_ascii_digit()) {
return Some(PathBuf::from(&path_str[..pos + 3]));
}
}
if path_str.ends_with(".7z") {
let first_volume = PathBuf::from(format!("{}.001", path_str));
if first_volume.exists() {
return Some(path.to_path_buf());
}
}
None
}
impl Archive<MultiVolumeReader> {
pub fn open_multivolume(path: impl AsRef<Path>) -> Result<Self> {
let path = path.as_ref();
let reader = MultiVolumeReader::open(path)?;
let volume_count = reader.volume_count();
let volume_paths: Vec<PathBuf> = (1..=volume_count)
.map(|n| reader.get_volume_path(n))
.collect();
let limits = ResourceLimits::default();
let (_start_header, header) = read_archive_header(&mut { reader }, Some(limits))?;
let entries = entries::build_entries(&header);
let info = entries::build_info(&header, &entries);
let reader = MultiVolumeReader::open(path)?;
Ok(Self {
reader,
header,
entries,
info,
#[cfg(feature = "aes")]
password: None,
volume_info: Some(VolumeInfo {
count: volume_count,
paths: volume_paths,
}),
sfx_offset: 0, })
}
}
pub(crate) fn open_multivolume_as_single(base_path: &Path) -> Result<Archive<BufReader<File>>> {
let reader = MultiVolumeReader::open(base_path)?;
let volume_count = reader.volume_count();
let volume_paths: Vec<PathBuf> = (1..=volume_count)
.map(|n| reader.get_volume_path(n))
.collect();
let limits = ResourceLimits::default();
let (_start_header, header) = read_archive_header(&mut { reader }, Some(limits))?;
let entries = entries::build_entries(&header);
let info = entries::build_info(&header, &entries);
let first_volume_path = format!("{}.001", base_path.display());
let file = File::open(&first_volume_path).map_err(Error::Io)?;
Ok(Archive {
reader: BufReader::new(file),
header,
entries,
info,
#[cfg(feature = "aes")]
password: None,
volume_info: Some(VolumeInfo {
count: volume_count,
paths: volume_paths,
}),
sfx_offset: 0, })
}