use std::ffi::{c_char, CString};
use std::fmt;
use std::path::{Path, PathBuf};
use url::Url;
use crate::error::OfficeError;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DocUrl(CString);
impl DocUrl {
pub(crate) fn as_ptr(&self) -> *const c_char {
self.0.as_ptr()
}
pub fn from_relative_path<S: AsRef<str>>(path: S) -> Result<DocUrl, OfficeError> {
let path: &str = path.as_ref();
let abs_path = std::fs::canonicalize(path).map_err(|err| {
OfficeError::OfficeError(format!("Does the file exist at {}? {}", path, err))
})?;
Self::from_absolute_path(abs_path.display().to_string())
}
pub fn from_absolute_path<S: AsRef<str>>(path: S) -> Result<DocUrl, OfficeError> {
let value = path.as_ref();
let path = Path::new(value);
if !path.is_absolute() {
return Err(OfficeError::OfficeError(format!(
"The file path {} must be absolute!",
&value
)));
}
let url_value = Url::from_file_path(value)
.map_err(|_| OfficeError::OfficeError(format!("failed to parse url {}", value)))?;
let value_str = CString::new(url_value.as_str())?;
Ok(DocUrl(value_str))
}
pub fn from_path<P: Into<PathBuf>>(path: P) -> Result<DocUrl, OfficeError> {
let path: PathBuf = path.into();
let abs_path = match path.is_absolute() {
false => std::path::absolute(&path)
.map_err(|err| OfficeError::OfficeError(err.to_string()))?,
true => path,
};
Self::from_absolute_path(abs_path.display().to_string())
}
pub fn from_remote_uri<S: AsRef<str>>(uri: S) -> Result<DocUrl, OfficeError> {
let uri: &str = uri.as_ref();
_ = Url::parse(uri)
.map_err(|_| OfficeError::OfficeError(format!("failed to parse uri {}", uri)))?;
let value_str = CString::new(uri)?;
Ok(DocUrl(value_str))
}
}
impl fmt::Display for DocUrl {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0.to_string_lossy())
}
}
#[cfg(test)]
mod test {
use super::DocUrl;
#[test]
fn test_relative() {
let path = "./src";
let _url = DocUrl::from_relative_path(path).unwrap();
}
#[test]
fn test_invalid_relative() {
let path = "/__ABSOLUTE_PATH_THAT_DOES_NOT_EXIST__";
let _url = DocUrl::from_relative_path(path).unwrap_err();
}
#[test]
fn test_absolute() {
#[cfg(target_os = "windows")]
let path = "C://";
#[cfg(not(target_os = "windows"))]
let path = "/src";
let _url = DocUrl::from_absolute_path(path).unwrap();
}
#[test]
fn test_invalid_absolute() {
let path = "./src";
let _url = DocUrl::from_absolute_path(path).unwrap_err();
}
#[test]
fn test_remote_path() {
let path = "http://localhost:5555/file.docx";
let _url = DocUrl::from_remote_uri(path).unwrap();
let path = "file://file.docx";
let _url = DocUrl::from_remote_uri(path).unwrap();
}
#[test]
fn test_invalid_remote_path() {
let path = "h/malformed";
let _url = DocUrl::from_remote_uri(path).unwrap_err();
let path = "h";
let _url = DocUrl::from_remote_uri(path).unwrap_err();
}
}