use crate::matcher::RelativePosition;
use crate::types::FileType;
pub trait FileTypeDescription {
fn smallest_block_size(&self, relative_position: &RelativePosition) -> Option<usize>;
fn ideal_block_size(relative_position: &RelativePosition) -> Option<(usize, Vec<FileType>)>;
fn ideal_block_size_of_variants(
relative_position: &RelativePosition,
variants: &[FileType],
) -> Option<(usize, Vec<FileType>)>;
fn maximum_block_size(relative_position: &RelativePosition) -> Option<(usize, Vec<FileType>)>;
fn maximum_block_size_of_variants(
relative_position: &RelativePosition,
variants: &[FileType],
) -> Option<(usize, Vec<FileType>)>;
fn largest_block_size(&self, relative_position: &RelativePosition) -> Option<usize>;
}
const MEGABYTE: usize = 1024 * 1024;
impl FileTypeDescription for FileType {
fn smallest_block_size(&self, relative_position: &RelativePosition) -> Option<usize> {
if (*relative_position) == RelativePosition::Start {
match self {
FileType::Zip => Some(4),
FileType::Rar => Some(7),
FileType::Rar5 => Some(8),
FileType::Tar => Some(257 + 8),
FileType::Lzma => Some(1),
FileType::Xz => Some(5),
FileType::Zst => Some(4),
FileType::Png => Some(8),
FileType::Jpg => Some(2),
FileType::_7z => Some(6),
FileType::Opus => Some(36),
FileType::Vorbis => Some(35),
FileType::Mp3 => Some(2),
FileType::Webp => Some(12),
FileType::Flac => Some(4),
FileType::Matroska => Some(4),
FileType::Wasm => Some(4),
FileType::Class => Some(4),
FileType::Tasty => Some(4),
FileType::Mach => Some(4),
FileType::Elf => Some(4),
FileType::Wav => Some(12),
FileType::Avi => Some(12),
FileType::Aiff => Some(12),
FileType::Tiff => Some(4),
FileType::Sqlite3 => Some(16),
FileType::Ico => Some(4),
FileType::Dalvik => Some(8),
FileType::Pdf => Some(5),
FileType::DosMzExecutable | FileType::DosZmExecutable => Some(2),
FileType::Xcf => Some(10),
FileType::Gif => Some(4),
FileType::Bmp => Some(2),
FileType::Gpg => Some(4),
FileType::ArmoredGpg => Some(29),
FileType::Iso => None,
FileType::Swf | FileType::Swc => Some(3),
}
} else {
match self {
FileType::Zip => Some(22),
_ => None,
}
}
}
fn ideal_block_size(relative_position: &RelativePosition) -> Option<(usize, Vec<FileType>)> {
coerce_file_types_at_least(
|variant| variant.smallest_block_size(relative_position),
&FileType::variants(),
)
}
fn ideal_block_size_of_variants(
relative_position: &RelativePosition,
variants: &[FileType],
) -> Option<(usize, Vec<FileType>)> {
coerce_file_types_at_least(
|variant| variant.smallest_block_size(relative_position),
variants,
)
}
fn maximum_block_size(relative_position: &RelativePosition) -> Option<(usize, Vec<FileType>)> {
coerce_file_types_at_least(
|variant| variant.largest_block_size(relative_position),
&FileType::variants(),
)
}
fn maximum_block_size_of_variants(
relative_position: &RelativePosition,
variants: &[FileType],
) -> Option<(usize, Vec<FileType>)> {
coerce_file_types_at_least(
|variant| variant.largest_block_size(relative_position),
variants,
)
}
fn largest_block_size(&self, relative_position: &RelativePosition) -> Option<usize> {
if *relative_position == RelativePosition::Start {
match self {
FileType::Rar => Some(MEGABYTE),
FileType::Rar5 => Some(MEGABYTE),
FileType::Iso => Some(32769 + 5),
_ => None,
}
} else {
None
}
}
}
fn coerce_file_types_at_least<F>(f: F, variants: &[FileType]) -> Option<(usize, Vec<FileType>)>
where
F: Fn(&FileType) -> Option<usize>,
{
let matches: Vec<(FileType, usize)> = variants
.iter()
.filter_map(|variant| f(variant).map(|block_size| (*variant, block_size)))
.collect();
let size = matches.iter().max_by(|l, r| l.1.cmp(&r.1));
let types: Vec<FileType> = matches.iter().map(|f| f.0).collect();
size.map(|size_type_pair| (size_type_pair.1, types))
}