use crate::signatures::common::{SignatureError, SignatureResult, CONFIDENCE_HIGH};
use crate::structures::zip::{parse_eocd_header, parse_zip_header};
use aho_corasick::AhoCorasick;
pub const DESCRIPTION: &str = "ZIP archive";
pub fn zip_magic() -> Vec<Vec<u8>> {
vec![b"PK\x03\x04".to_vec()]
}
pub fn zip_parser(file_data: &[u8], offset: usize) -> Result<SignatureResult, SignatureError> {
let mut result = SignatureResult {
offset,
description: DESCRIPTION.to_string(),
confidence: CONFIDENCE_HIGH,
..Default::default()
};
if parse_zip_header(&file_data[offset..]).is_ok() {
if let Ok(zip_info) = find_zip_eof(file_data, offset) {
result.size = zip_info.eof - offset;
result.description = format!(
"{}, file count: {}, total size: {} bytes",
result.description, zip_info.file_count, result.size
);
return Ok(result);
}
}
Err(SignatureError)
}
struct ZipEOCDInfo {
eof: usize,
file_count: usize,
}
fn find_zip_eof(file_data: &[u8], offset: usize) -> Result<ZipEOCDInfo, SignatureError> {
const ZIP_EOCD_MAGIC: &[u8; 8] = b"PK\x05\x06\x00\x00\x00\x00";
let grep = AhoCorasick::new(vec![ZIP_EOCD_MAGIC]).unwrap();
for eocd_match in grep.find_overlapping_iter(&file_data[offset..]) {
let eocd_start: usize = eocd_match.start() + offset;
if let Some(eocd_data) = file_data.get(eocd_start..) {
if let Ok(eocd_header) = parse_eocd_header(eocd_data) {
return Ok(ZipEOCDInfo {
eof: eocd_start + eocd_header.size,
file_count: eocd_header.file_count,
});
}
}
}
Err(SignatureError)
}