use fluent_uri::Uri;
use log::error;
use std::path::PathBuf;
use urlencoding::{decode, encode};
use crate::Error;
use regex::Regex;
fn with_encoded_path(uri: &str) -> String {
let re = Regex::new(r"^(?P<scheme>[^:/?#]+://)?(?P<host>[^/?#]+)(?P<path>/?.*)$").unwrap();
if let Some(caps) = re.captures(uri) {
let scheme = caps.name("scheme").map_or("", |m| m.as_str());
let host = caps["host"].to_string();
let path = &caps["path"];
let encoded_path = path
.split('/')
.map(|segment| encode(segment).into_owned()) .collect::<Vec<String>>()
.join("/");
format!("{}{}{}", scheme, host, encoded_path)
} else {
encode(uri).into_owned()
}
}
pub fn parse_uri(uri: &str) -> crate::Result<Uri<String>> {
let encoded_uri = with_encoded_path(&uri.replace("\\", "/"));
match Uri::parse(encoded_uri) {
Ok(uri) => {
let scheme = uri.scheme().to_string();
if scheme.eq_ignore_ascii_case("file") {
Ok(uri.to_owned())
} else {
Err(Error::InvalidUriScheme(scheme.to_string()))
}
}
Err(err) => Err(Error::ParseUriError(format!("uri: {uri} {err:?}"))),
}
}
#[cfg(target_os = "windows")]
fn get_authority_as_string(input: &Uri<&str>) -> String {
match input.authority() {
Some(authority) => authority.to_string(),
None => String::new(),
}
}
fn decode_path(uri: &Uri<&str>) -> String {
match decode(uri.path().as_ref()) {
Ok(decoded_path) => {
#[cfg(target_os = "windows")]
return format!(
"{}{}",
get_authority_as_string(uri),
decoded_path.replace("/", "\\")
);
#[cfg(not(target_os = "windows"))]
return decoded_path.into_owned();
}
Err(_) => uri.to_string(),
}
}
pub fn uri_to_path(uri: &str) -> crate::Result<std::path::PathBuf> {
match parse_uri(uri) {
Ok(uri) => {
let path = decode_path(&uri.borrow());
Ok(PathBuf::from(path))
}
Err(e) => {
error!("err: {}", e);
Err(e)
}
}
}
#[cfg(test)]
mod tests {
use crate::uri::uri_to_path;
#[test]
pub fn test_uri_to_path_for_windows_path() {
let r = uri_to_path("file://C:/Users/Test/My Pictures/my_file.jpg").unwrap();
#[cfg(target_os = "windows")]
assert_eq!(
r.to_str().unwrap(),
"C:\\Users\\Test\\My Pictures\\my_file.jpg"
);
#[cfg(not(target_os = "windows"))]
assert_eq!(r.to_str().unwrap(), "/Users/Test/My Pictures/my_file.jpg");
}
}