use crate::archive::{BcfArchive, Limits};
use crate::error::BcfError;
use std::io::{Read, Seek};
use std::path::Path;
pub fn read_path(path: impl AsRef<Path>) -> Result<BcfArchive, BcfError> {
read_path_with(path, Limits::default())
}
pub fn read_path_with(path: impl AsRef<Path>, limits: Limits) -> Result<BcfArchive, BcfError> {
let path = path.as_ref();
let file = std::fs::File::open(path).map_err(|source| BcfError::Io {
path: Some(path.to_path_buf()),
source,
})?;
read_reader_with(file, limits).map_err(|e| match e {
BcfError::Io { path: None, source } => BcfError::Io {
path: Some(path.to_path_buf()),
source,
},
other => other,
})
}
pub fn read_slice(bytes: &[u8]) -> Result<BcfArchive, BcfError> {
read_reader(std::io::Cursor::new(bytes))
}
pub fn read_slice_with(bytes: &[u8], limits: Limits) -> Result<BcfArchive, BcfError> {
read_reader_with(std::io::Cursor::new(bytes), limits)
}
pub fn read_reader<R: Read + Seek>(reader: R) -> Result<BcfArchive, BcfError> {
read_reader_with(reader, Limits::default())
}
pub fn read_reader_with<R: Read + Seek>(reader: R, limits: Limits) -> Result<BcfArchive, BcfError> {
let zip = zip::ZipArchive::new(reader).map_err(|e| match e {
zip::result::ZipError::Io(source) => BcfError::Io { path: None, source },
other => BcfError::NotAnArchive {
detail: other.to_string(),
},
})?;
BcfArchive::from_zip(zip, limits)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn non_zip_bytes_are_reported_as_not_an_archive() {
let err = read_slice(b"this is plainly not a zip").unwrap_err();
assert!(matches!(err, BcfError::NotAnArchive { .. }), "{err:?}");
}
#[test]
fn a_missing_file_keeps_its_path_in_the_error() {
let err = read_path("/nonexistent/definitely-not-here.bcfzip").unwrap_err();
match err {
BcfError::Io { path: Some(p), .. } => {
assert!(p.to_string_lossy().contains("definitely-not-here"));
}
other => panic!("expected Io with path, got {other:?}"),
}
}
}