use std::ffi::OsStr;
use std::fs::File;
use std::path::Path;
use memmap2::Mmap;
use crate::types::{ArchiveFormat, OpenPackError};
pub(crate) fn detect_format(path: &Path, bytes: &[u8]) -> Result<ArchiveFormat, OpenPackError> {
let ext = path
.extension()
.and_then(OsStr::to_str)
.map(|value| value.to_ascii_lowercase());
if let Some(ext_str) = ext.as_deref() {
match ext_str {
"jar" => return Ok(ArchiveFormat::Jar),
"apk" => return Ok(ArchiveFormat::Apk),
"ipa" => return Ok(ArchiveFormat::Ipa),
"zip" => return Ok(ArchiveFormat::Zip),
"crx" => {
if bytes.starts_with(b"PK\x03\x04") {
return Ok(ArchiveFormat::Zip);
}
#[cfg(feature = "crx")]
{
return Ok(ArchiveFormat::Crx);
}
#[cfg(not(feature = "crx"))]
{
return Err(OpenPackError::Unsupported);
}
}
_ => {}
}
}
if bytes.starts_with(b"Cr24") {
#[cfg(feature = "crx")]
{
return Ok(ArchiveFormat::Crx);
}
#[cfg(not(feature = "crx"))]
{
return Err(OpenPackError::Unsupported);
}
}
if bytes.starts_with(b"PK") {
return Ok(ArchiveFormat::Zip);
}
if bytes.len() >= 2 && &bytes[0..2] == b"\x1F\x8B" {
return Err(OpenPackError::Unsupported);
}
Err(OpenPackError::Unsupported)
}
pub(crate) fn read_archive_bytes(file: File, file_len: u64) -> Result<Mmap, OpenPackError> {
let _capacity = usize::try_from(file_len)
.map_err(|_| OpenPackError::LimitExceeded("archive too large for platform".into()))?;
let mmap = unsafe {
memmap2::MmapOptions::new()
.map(&file)
.map_err(OpenPackError::Io)?
};
Ok(mmap)
}