2022-01-06 10:47:27 +13:00
|
|
|
use directories_next::ProjectDirs;
|
2022-01-01 10:34:24 +13:00
|
|
|
use image::{DynamicImage, ImageBuffer, Rgb};
|
|
|
|
use imagepipe::{ImageSource, Pipeline};
|
2020-10-15 05:41:37 +13:00
|
|
|
use std::ffi::OsString;
|
2020-09-12 23:25:23 +12:00
|
|
|
use std::fs;
|
2022-01-06 10:47:27 +13:00
|
|
|
use std::fs::{File, OpenOptions};
|
2022-01-01 10:34:24 +13:00
|
|
|
use std::io::BufReader;
|
2020-10-15 05:41:37 +13:00
|
|
|
use std::path::{Path, PathBuf};
|
2020-09-01 05:37:30 +12:00
|
|
|
use std::time::SystemTime;
|
|
|
|
|
2020-09-02 05:34:39 +12:00
|
|
|
/// Class for common functions used across other class/functions
|
|
|
|
|
2020-09-01 05:37:30 +12:00
|
|
|
pub struct Common();
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2022-01-06 10:47:27 +13:00
|
|
|
pub fn open_cache_folder(cache_file_name: &str, save_to_cache: bool, use_json: bool, warnings: &mut Vec<String>) -> Option<((Option<File>, PathBuf), (Option<File>, PathBuf))> {
|
|
|
|
if let Some(proj_dirs) = ProjectDirs::from("pl", "Qarmin", "Czkawka") {
|
|
|
|
let cache_dir = PathBuf::from(proj_dirs.cache_dir());
|
|
|
|
let cache_file = cache_dir.join(cache_file_name);
|
|
|
|
let cache_file_json = cache_dir.join(cache_file_name.replace(".bin", ".json"));
|
|
|
|
|
|
|
|
let mut file_handler_default = None;
|
|
|
|
let mut file_handler_json = None;
|
|
|
|
|
|
|
|
if save_to_cache {
|
|
|
|
if cache_dir.exists() {
|
|
|
|
if !cache_dir.is_dir() {
|
|
|
|
warnings.push(format!("Config dir {} is a file!", cache_dir.display()));
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
} else if let Err(e) = fs::create_dir_all(&cache_dir) {
|
|
|
|
warnings.push(format!("Cannot create config dir {}, reason {}", cache_dir.display(), e));
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
file_handler_default = Some(match OpenOptions::new().truncate(true).write(true).create(true).open(&cache_file) {
|
|
|
|
Ok(t) => t,
|
|
|
|
Err(e) => {
|
|
|
|
warnings.push(format!("Cannot create or open cache file {}, reason {}", cache_file.display(), e));
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if use_json {
|
|
|
|
file_handler_json = Some(match OpenOptions::new().truncate(true).write(true).create(true).open(&cache_file_json) {
|
|
|
|
Ok(t) => t,
|
|
|
|
Err(e) => {
|
|
|
|
warnings.push(format!("Cannot create or open cache file {}, reason {}", cache_file_json.display(), e));
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if let Ok(t) = OpenOptions::new().read(true).open(&cache_file) {
|
|
|
|
file_handler_default = Some(t);
|
|
|
|
} else {
|
|
|
|
if use_json {
|
|
|
|
file_handler_json = Some(match OpenOptions::new().read(true).open(&cache_file_json) {
|
|
|
|
Ok(t) => t,
|
|
|
|
Err(_) => return None,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// messages.push(format!("Cannot find or open cache file {}", cache_file.display())); // No error or warning
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return Some(((file_handler_default, cache_file), (file_handler_json, cache_file_json)));
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2022-01-01 10:34:24 +13:00
|
|
|
pub fn get_dynamic_image_from_raw_image(path: impl AsRef<Path> + std::fmt::Debug) -> Option<DynamicImage> {
|
|
|
|
let file_handler = match OpenOptions::new().read(true).open(&path) {
|
|
|
|
Ok(t) => t,
|
|
|
|
Err(_e) => {
|
|
|
|
// println!("Failed to open image {:?}, reason {}", path, e);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut reader = BufReader::new(file_handler);
|
|
|
|
let raw = match rawloader::decode(&mut reader) {
|
|
|
|
Ok(raw) => raw,
|
|
|
|
Err(_e) => {
|
|
|
|
// println!("Failed to decode raw image {:?}, reason {}", path, e);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let width = raw.width;
|
|
|
|
let height = raw.height;
|
|
|
|
let source = ImageSource::Raw(raw);
|
|
|
|
|
|
|
|
let mut pipeline = match Pipeline::new_from_source(source, width, height, true) {
|
|
|
|
Ok(pipeline) => pipeline,
|
|
|
|
Err(_e) => {
|
|
|
|
// println!("Failed to create pipeline {:?}, reason {}", path, e);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
pipeline.run(None);
|
|
|
|
let image = match pipeline.output_8bit(None) {
|
|
|
|
Ok(image) => image,
|
|
|
|
Err(_e) => {
|
|
|
|
// println!("Failed to process image {:?}, reason {}", path, e);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let image = match ImageBuffer::<Rgb<u8>, Vec<u8>>::from_raw(image.width as u32, image.height as u32, image.data) {
|
|
|
|
Some(image) => image,
|
|
|
|
None => {
|
|
|
|
// println!("Failed to get image {:?}", path);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// println!("Properly hashed {:?}", path);
|
|
|
|
Some(image::DynamicImage::ImageRgb8(image))
|
|
|
|
}
|
|
|
|
|
2020-09-01 05:37:30 +12:00
|
|
|
impl Common {
|
2020-09-12 23:25:23 +12:00
|
|
|
/// Printing time which took between start and stop point and prints also function name
|
2020-10-10 09:32:08 +13:00
|
|
|
#[allow(unused_variables)]
|
|
|
|
pub fn print_time(start_time: SystemTime, end_time: SystemTime, function_name: String) {
|
2020-09-17 22:07:58 +12:00
|
|
|
#[cfg(debug_assertions)]
|
2021-12-22 06:44:20 +13:00
|
|
|
println!(
|
|
|
|
"Execution of function \"{}\" took {:?}",
|
|
|
|
function_name,
|
|
|
|
end_time.duration_since(start_time).expect("Time cannot go reverse.")
|
|
|
|
);
|
2020-09-01 05:37:30 +12:00
|
|
|
}
|
2020-09-12 08:32:17 +12:00
|
|
|
|
2020-09-12 23:25:23 +12:00
|
|
|
pub fn delete_multiple_entries(entries: &[String]) -> Vec<String> {
|
|
|
|
let mut path: &Path;
|
|
|
|
let mut warnings: Vec<String> = Vec::new();
|
|
|
|
for entry in entries {
|
|
|
|
path = Path::new(entry);
|
|
|
|
if path.is_dir() {
|
2021-11-15 03:53:55 +13:00
|
|
|
if let Err(e) = fs::remove_dir_all(&entry) {
|
|
|
|
warnings.push(format!("Failed to remove folder {}, reason {}", entry, e));
|
2020-09-12 23:25:23 +12:00
|
|
|
}
|
2021-11-15 03:53:55 +13:00
|
|
|
} else if let Err(e) = fs::remove_file(&entry) {
|
|
|
|
warnings.push(format!("Failed to remove file {}, reason {}", entry, e));
|
2020-09-12 23:25:23 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
warnings
|
|
|
|
}
|
|
|
|
pub fn delete_one_entry(entry: &str) -> String {
|
|
|
|
let path: &Path = Path::new(entry);
|
|
|
|
let mut warning: String = String::from("");
|
2020-09-16 05:17:13 +12:00
|
|
|
if path.is_dir() {
|
2021-11-15 03:53:55 +13:00
|
|
|
if let Err(e) = fs::remove_dir_all(&entry) {
|
|
|
|
warning = format!("Failed to remove folder {}, reason {}", entry, e)
|
2020-09-16 05:17:13 +12:00
|
|
|
}
|
2021-11-15 03:53:55 +13:00
|
|
|
} else if let Err(e) = fs::remove_file(&entry) {
|
|
|
|
warning = format!("Failed to remove file {}, reason {}", entry, e)
|
2020-09-12 23:25:23 +12:00
|
|
|
}
|
|
|
|
warning
|
|
|
|
}
|
|
|
|
|
2020-09-12 08:32:17 +12:00
|
|
|
/// Function to check if directory match expression
|
2020-10-15 05:41:37 +13:00
|
|
|
pub fn regex_check(expression: &str, directory: impl AsRef<Path>) -> bool {
|
2021-12-03 01:31:10 +13:00
|
|
|
if expression == "*" {
|
|
|
|
return true;
|
|
|
|
}
|
2020-09-12 08:32:17 +12:00
|
|
|
|
|
|
|
let temp_splits: Vec<&str> = expression.split('*').collect();
|
|
|
|
let mut splits: Vec<&str> = Vec::new();
|
|
|
|
for i in temp_splits {
|
2021-01-01 07:53:49 +13:00
|
|
|
if !i.is_empty() {
|
2020-09-12 08:32:17 +12:00
|
|
|
splits.push(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if splits.is_empty() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-10-15 05:41:37 +13:00
|
|
|
// Get rid of non unicode characters
|
|
|
|
let directory = directory.as_ref().to_string_lossy();
|
|
|
|
|
2020-09-12 08:32:17 +12:00
|
|
|
// Early checking if directory contains all parts needed by expression
|
|
|
|
for split in &splits {
|
|
|
|
if !directory.contains(split) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut position_of_splits: Vec<usize> = Vec::new();
|
|
|
|
|
|
|
|
// `git*` shouldn't be true for `/gitsfafasfs`
|
|
|
|
if !expression.starts_with('*') && directory.find(&splits[0]).unwrap() > 0 {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// `*home` shouldn't be true for `/homeowner`
|
|
|
|
if !expression.ends_with('*') && !directory.ends_with(splits.last().unwrap()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// At the end we check if parts between * are correctly positioned
|
|
|
|
position_of_splits.push(directory.find(&splits[0]).unwrap());
|
|
|
|
let mut current_index: usize;
|
|
|
|
let mut found_index: usize;
|
|
|
|
for i in splits[1..].iter().enumerate() {
|
|
|
|
current_index = *position_of_splits.get(i.0).unwrap() + i.1.len();
|
|
|
|
found_index = match directory[current_index..].find(i.1) {
|
|
|
|
Some(t) => t,
|
|
|
|
None => return false,
|
|
|
|
};
|
|
|
|
position_of_splits.push(found_index + current_index);
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
2020-10-15 05:41:37 +13:00
|
|
|
|
|
|
|
pub fn normalize_windows_path(path_to_change: impl AsRef<Path>) -> PathBuf {
|
|
|
|
let path = path_to_change.as_ref();
|
2020-12-31 01:41:18 +13:00
|
|
|
|
|
|
|
// Don't do anything, because network path may be case intensive
|
|
|
|
if path.to_string_lossy().starts_with('\\') {
|
|
|
|
return path.to_path_buf();
|
|
|
|
}
|
|
|
|
|
2020-10-15 05:41:37 +13:00
|
|
|
match path.to_str() {
|
|
|
|
Some(path) if path.is_char_boundary(1) => {
|
2021-12-19 11:45:37 +13:00
|
|
|
let replaced = path.replace('/', "\\");
|
2020-10-15 05:41:37 +13:00
|
|
|
let mut new_path = OsString::new();
|
|
|
|
if replaced[1..].starts_with(':') {
|
|
|
|
new_path.push(replaced[..1].to_ascii_uppercase());
|
|
|
|
new_path.push(replaced[1..].to_ascii_lowercase());
|
|
|
|
} else {
|
|
|
|
new_path.push(replaced.to_ascii_lowercase());
|
|
|
|
}
|
|
|
|
PathBuf::from(new_path)
|
|
|
|
}
|
|
|
|
_ => path.to_path_buf(),
|
|
|
|
}
|
2020-10-11 02:18:04 +13:00
|
|
|
}
|
2020-09-12 08:32:17 +12:00
|
|
|
}
|
2020-09-18 17:32:37 +12:00
|
|
|
|
2020-09-12 08:32:17 +12:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2020-10-15 05:41:37 +13:00
|
|
|
use std::path::PathBuf;
|
2020-09-12 08:32:17 +12:00
|
|
|
|
2021-11-28 08:49:20 +13:00
|
|
|
use crate::common::Common;
|
|
|
|
|
2020-09-12 08:32:17 +12:00
|
|
|
#[test]
|
|
|
|
fn test_regex() {
|
|
|
|
assert!(Common::regex_check("*home*", "/home/rafal"));
|
|
|
|
assert!(Common::regex_check("*home", "/home"));
|
|
|
|
assert!(Common::regex_check("*home/", "/home/"));
|
|
|
|
assert!(Common::regex_check("*home/*", "/home/"));
|
|
|
|
assert!(Common::regex_check("*.git*", "/home/.git"));
|
|
|
|
assert!(Common::regex_check("*/home/rafal*rafal*rafal*rafal*", "/home/rafal/rafalrafalrafal"));
|
2020-12-15 01:07:35 +13:00
|
|
|
assert!(Common::regex_check("AAA", "AAA"));
|
|
|
|
assert!(Common::regex_check("AAA*", "AAABDGG/QQPW*"));
|
2020-09-12 08:32:17 +12:00
|
|
|
assert!(!Common::regex_check("*home", "/home/"));
|
|
|
|
assert!(!Common::regex_check("*home", "/homefasfasfasfasf/"));
|
|
|
|
assert!(!Common::regex_check("*home", "/homefasfasfasfasf"));
|
|
|
|
assert!(!Common::regex_check("rafal*afal*fal", "rafal"));
|
2020-09-17 23:35:11 +12:00
|
|
|
assert!(!Common::regex_check("rafal*a", "rafal"));
|
2020-09-12 08:32:17 +12:00
|
|
|
assert!(!Common::regex_check("AAAAAAAA****", "/AAAAAAAAAAAAAAAAA"));
|
|
|
|
assert!(!Common::regex_check("*.git/*", "/home/.git"));
|
|
|
|
assert!(!Common::regex_check("*home/*koc", "/koc/home/"));
|
|
|
|
assert!(!Common::regex_check("*home/", "/home"));
|
|
|
|
assert!(!Common::regex_check("*TTT", "/GGG"));
|
2021-05-09 07:54:01 +12:00
|
|
|
|
|
|
|
#[cfg(target_family = "windows")]
|
|
|
|
{
|
|
|
|
assert!(Common::regex_check("*\\home", "C:\\home"));
|
|
|
|
assert!(Common::regex_check("*/home", "C:\\home"));
|
|
|
|
}
|
2020-09-12 08:32:17 +12:00
|
|
|
}
|
2021-11-28 08:57:10 +13:00
|
|
|
|
2020-10-11 02:18:04 +13:00
|
|
|
#[test]
|
|
|
|
fn test_windows_path() {
|
2020-12-22 06:22:59 +13:00
|
|
|
assert_eq!(PathBuf::from("C:\\path.txt"), Common::normalize_windows_path("c:/PATH.tXt"));
|
|
|
|
assert_eq!(PathBuf::from("H:\\reka\\weza\\roman.txt"), Common::normalize_windows_path("h:/RekA/Weza\\roMan.Txt"));
|
|
|
|
assert_eq!(PathBuf::from("T:\\a"), Common::normalize_windows_path("T:\\A"));
|
2020-12-31 01:41:18 +13:00
|
|
|
assert_eq!(PathBuf::from("\\\\aBBa"), Common::normalize_windows_path("\\\\aBBa"));
|
|
|
|
assert_eq!(PathBuf::from("a"), Common::normalize_windows_path("a"));
|
|
|
|
assert_eq!(PathBuf::from(""), Common::normalize_windows_path(""));
|
2020-10-11 02:18:04 +13:00
|
|
|
}
|
2020-09-01 05:37:30 +12:00
|
|
|
}
|