2023-12-08 07:38:41 +13:00
|
|
|
use std::collections::HashSet;
|
|
|
|
use std::fs::DirEntry;
|
2023-10-11 07:54:41 +13:00
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
use crate::common_messages::Messages;
|
|
|
|
|
2023-10-05 19:06:47 +13:00
|
|
|
#[derive(Debug, Clone, Default)]
|
2020-09-27 03:52:13 +13:00
|
|
|
pub struct Extensions {
|
2024-02-15 05:45:25 +13:00
|
|
|
allowed_extensions_hashset: HashSet<String>,
|
|
|
|
excluded_extensions_hashset: HashSet<String>,
|
2020-09-27 03:52:13 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Extensions {
|
2020-10-10 09:32:08 +13:00
|
|
|
pub fn new() -> Self {
|
|
|
|
Default::default()
|
2020-09-27 03:52:13 +13:00
|
|
|
}
|
2024-02-15 05:45:25 +13:00
|
|
|
|
|
|
|
pub fn filter_extensions(mut file_extensions: String) -> (HashSet<String>, Messages) {
|
2023-10-11 07:54:41 +13:00
|
|
|
let mut messages = Messages::new();
|
2024-02-15 05:45:25 +13:00
|
|
|
let mut extensions_hashset = HashSet::new();
|
2023-10-05 19:06:47 +13:00
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
if file_extensions.trim().is_empty() {
|
|
|
|
return (Default::default(), messages);
|
2020-09-27 03:52:13 +13:00
|
|
|
}
|
2024-02-15 05:45:25 +13:00
|
|
|
file_extensions = file_extensions.replace("IMAGE", "jpg,kra,gif,png,bmp,tiff,hdr,svg");
|
|
|
|
file_extensions = file_extensions.replace("VIDEO", "mp4,flv,mkv,webm,vob,ogv,gifv,avi,mov,wmv,mpg,m4v,m4p,mpeg,3gp");
|
|
|
|
file_extensions = file_extensions.replace("MUSIC", "mp3,flac,ogg,tta,wma,webm");
|
|
|
|
file_extensions = file_extensions.replace("TEXT", "txt,doc,docx,odt,rtf");
|
2020-09-27 03:52:13 +13:00
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
let extensions: Vec<String> = file_extensions.split(',').map(str::trim).map(String::from).collect();
|
2020-09-27 03:52:13 +13:00
|
|
|
for mut extension in extensions {
|
2022-11-24 08:23:17 +13:00
|
|
|
if extension.is_empty() || extension.replace(['.', ' '], "").trim().is_empty() {
|
2020-09-27 03:52:13 +13:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-08 07:38:41 +13:00
|
|
|
if extension.starts_with('.') {
|
2024-02-15 05:45:25 +13:00
|
|
|
extension = extension.chars().skip(1).collect::<String>();
|
2020-09-27 03:52:13 +13:00
|
|
|
}
|
|
|
|
|
2023-12-08 07:38:41 +13:00
|
|
|
if extension.contains('.') {
|
2023-10-11 07:54:41 +13:00
|
|
|
messages.warnings.push(format!("{extension} is not valid extension because contains dot inside"));
|
2020-09-27 03:52:13 +13:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-08 07:38:41 +13:00
|
|
|
if extension.contains(' ') {
|
2023-10-11 07:54:41 +13:00
|
|
|
messages.warnings.push(format!("{extension} is not valid extension because contains empty space inside"));
|
2021-12-18 07:29:37 +13:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
extensions_hashset.insert(extension);
|
2020-09-27 03:52:13 +13:00
|
|
|
}
|
2024-02-15 05:45:25 +13:00
|
|
|
(extensions_hashset, messages)
|
|
|
|
}
|
2020-09-27 03:52:13 +13:00
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
/// List of allowed extensions, only files with this extensions will be checking if are duplicates
|
|
|
|
/// After, extensions cannot contain any dot, commas etc.
|
|
|
|
pub fn set_allowed_extensions(&mut self, allowed_extensions: String) -> Messages {
|
|
|
|
let (extensions, messages) = Self::filter_extensions(allowed_extensions);
|
|
|
|
|
|
|
|
self.allowed_extensions_hashset = extensions;
|
2023-10-11 07:54:41 +13:00
|
|
|
messages
|
2020-09-27 03:52:13 +13:00
|
|
|
}
|
2021-12-18 07:29:37 +13:00
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
pub fn set_excluded_extensions(&mut self, excluded_extensions: String) -> Messages {
|
|
|
|
let (extensions, messages) = Self::filter_extensions(excluded_extensions);
|
|
|
|
|
|
|
|
self.excluded_extensions_hashset = extensions;
|
|
|
|
messages
|
2021-12-18 07:29:37 +13:00
|
|
|
}
|
2024-02-15 05:45:25 +13:00
|
|
|
|
|
|
|
pub fn check_if_entry_have_valid_extension(&self, entry_data: &DirEntry) -> bool {
|
|
|
|
if self.allowed_extensions_hashset.is_empty() && self.excluded_extensions_hashset.is_empty() {
|
2023-12-08 07:38:41 +13:00
|
|
|
return true;
|
|
|
|
}
|
2021-12-18 07:29:37 +13:00
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
// Using entry_data.path().extension() is a lot of slower, even 5 times
|
2023-12-08 07:38:41 +13:00
|
|
|
let file_name = entry_data.file_name();
|
|
|
|
let Some(file_name_str) = file_name.to_str() else { return false };
|
|
|
|
let Some(extension_idx) = file_name_str.rfind('.') else { return false };
|
|
|
|
let extension = &file_name_str[extension_idx + 1..];
|
2022-01-01 10:34:24 +13:00
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
if !self.allowed_extensions_hashset.is_empty() {
|
|
|
|
if extension.chars().all(|c| c.is_ascii_lowercase()) {
|
|
|
|
self.allowed_extensions_hashset.contains(extension)
|
|
|
|
} else {
|
|
|
|
self.allowed_extensions_hashset.contains(&extension.to_lowercase())
|
|
|
|
}
|
2023-12-08 07:38:41 +13:00
|
|
|
} else {
|
2024-02-15 05:45:25 +13:00
|
|
|
if extension.chars().all(|c| c.is_ascii_lowercase()) {
|
|
|
|
!self.excluded_extensions_hashset.contains(extension)
|
|
|
|
} else {
|
|
|
|
!self.excluded_extensions_hashset.contains(&extension.to_lowercase())
|
|
|
|
}
|
2021-12-18 07:29:37 +13:00
|
|
|
}
|
|
|
|
}
|
2022-05-24 05:04:28 +12:00
|
|
|
|
2023-12-17 11:21:09 +13:00
|
|
|
pub fn set_any_extensions(&self) -> bool {
|
2024-02-15 05:45:25 +13:00
|
|
|
!self.allowed_extensions_hashset.is_empty()
|
2023-12-08 07:38:41 +13:00
|
|
|
}
|
2022-05-24 05:04:28 +12:00
|
|
|
|
2023-12-17 11:21:09 +13:00
|
|
|
fn extend_allowed_extensions(&mut self, file_extensions: &[&str]) {
|
2022-05-24 05:04:28 +12:00
|
|
|
for extension in file_extensions {
|
2023-12-08 07:38:41 +13:00
|
|
|
let extension_without_dot = extension.trim_start_matches('.');
|
2024-02-15 05:45:25 +13:00
|
|
|
self.allowed_extensions_hashset.insert(extension_without_dot.to_string());
|
2022-05-24 05:04:28 +12:00
|
|
|
}
|
|
|
|
}
|
2023-12-17 11:21:09 +13:00
|
|
|
|
|
|
|
// E.g. when using similar videos, user can provide extensions like "mp4,flv", but if user provide "mp4,jpg" then
|
|
|
|
// it will be only "mp4" because "jpg" is not valid extension for videos
|
|
|
|
fn union_allowed_extensions(&mut self, file_extensions: &[&str]) {
|
|
|
|
let mut new_extensions = HashSet::new();
|
|
|
|
for extension in file_extensions {
|
|
|
|
let extension_without_dot = extension.trim_start_matches('.');
|
|
|
|
new_extensions.insert(extension_without_dot.to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-15 05:45:25 +13:00
|
|
|
pub fn set_and_validate_allowed_extensions(&mut self, file_extensions: &[&str]) {
|
|
|
|
if self.allowed_extensions_hashset.is_empty() {
|
2023-12-17 11:21:09 +13:00
|
|
|
self.extend_allowed_extensions(file_extensions);
|
|
|
|
} else {
|
|
|
|
self.union_allowed_extensions(file_extensions);
|
|
|
|
}
|
|
|
|
}
|
2020-09-27 03:52:13 +13:00
|
|
|
}
|