diff --git a/wfassoc/src/extra/windows.rs b/wfassoc/src/extra/windows.rs index c02d0e4..d8af7bd 100644 --- a/wfassoc/src/extra/windows.rs +++ b/wfassoc/src/extra/windows.rs @@ -12,14 +12,159 @@ use thiserror::Error as TeError; use widestring::{WideCStr, WideCString, WideChar}; use windows_sys::Win32::UI::WindowsAndMessaging::HICON; +// region: Windows Resource Reference String + +// region: Icon Reference String + +#[derive(Debug, TeError)] +#[error("given string \"{inner}\" is not a valid Icon Reference String")] +pub struct ParseIconRcError { + inner: String, +} + +impl ParseIconRcError { + fn new(s: &str) -> Self { + Self { + inner: s.to_string(), + } + } +} + +#[derive(Debug, TeError)] +#[error("fail to load icon")] +pub struct FetchIconError {} + +pub struct IconRc { + path: String, + index: u32, +} + +impl IconRc { + /// Create a new Icon Reference String. + /// + /// `path` is the path to the icon resource file and it can be Expand String. + /// `index` is the index of the icon in the resource file. + pub fn new(path: &str, index: u32) -> Self { + Self { + path: path.to_string(), + index, + } + } + + pub fn fetch_icon(&self) -> Result { + todo!() + } +} + +impl Display for IconRc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{},-{}", self.path, self.index) + } +} + +impl FromStr for IconRc { + type Err = ParseIconRcError; + + fn from_str(s: &str) -> Result { + static RE: LazyLock = + LazyLock::new(|| Regex::new(r"^([^,@][^,]*),-([0-9]+)$").unwrap()); + let caps = RE.captures(s); + if let Some(caps) = caps { + let path = &caps[1]; + let index = caps.get(2).ok_or(ParseIconRcError::new(s)).and_then(|sv| { + sv.as_str() + .parse::() + .map_err(|_| ParseIconRcError::new(s)) + })?; + Ok(Self::new(path, index)) + } else { + Err(ParseIconRcError::new(s)) + } + } +} + +// endregion + +// region: String Reference String + +#[derive(Debug, TeError)] +#[error("given string \"{inner}\" is not a valid String Reference String")] +pub struct ParseStrRcError { + inner: String, +} + +impl ParseStrRcError { + fn new(s: &str) -> Self { + Self { + inner: s.to_string(), + } + } +} + +#[derive(Debug, TeError)] +#[error("fail to load string")] +pub struct FetchStrError{} + +pub struct StrRc { + path: String, + index: u32, +} + +impl StrRc { + /// Create a new String Reference String. + /// + /// `path` is the path to the string resource file and it can be Expand String. + /// `index` is the index of the string in the resource file. + pub fn new(path: &str, index: u32) -> Self { + Self { + path: path.to_string(), + index, + } + } + + pub fn fetch_string(&self) -> Result { + todo!() + } +} + +impl Display for StrRc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "@{},-{}", self.path, self.index) + } +} + +impl FromStr for StrRc { + type Err = ParseStrRcError; + + fn from_str(s: &str) -> Result { + static RE: LazyLock = LazyLock::new(|| Regex::new(r"^@([^,]+),-([0-9]+)$").unwrap()); + let caps = RE.captures(s); + if let Some(caps) = caps { + let path = &caps[1]; + let index = caps.get(2).ok_or(ParseStrRcError::new(s)).and_then(|sv| { + sv.as_str() + .parse::() + .map_err(|_| ParseStrRcError::new(s)) + })?; + Ok(Self::new(path, index)) + } else { + Err(ParseStrRcError::new(s)) + } + } +} + +// endregion + +// endregion + // region: Expand String /// Error occurs when creating Expand String. #[derive(Debug, TeError)] #[error("given string is not an expand string")] -pub struct BadExpandStrError {} +pub struct ParseExpandStrError {} -impl BadExpandStrError { +impl ParseExpandStrError { fn new() -> Self { Self {} } @@ -58,7 +203,7 @@ impl ExpandString { impl ExpandString { /// Create a new expand string - pub fn new(s: &str) -> Result { + pub fn new(s: &str) -> Result { Self::from_str(s) } @@ -107,7 +252,7 @@ impl Display for ExpandString { } impl FromStr for ExpandString { - type Err = BadExpandStrError; + type Err = ParseExpandStrError; fn from_str(s: &str) -> Result { if Self::VAR_RE.is_match(s) { @@ -115,7 +260,7 @@ impl FromStr for ExpandString { inner: s.to_string(), }) } else { - Err(BadExpandStrError::new()) + Err(ParseExpandStrError::new()) } } } diff --git a/wfassoc/tests/extra_windows.rs b/wfassoc/tests/extra_windows.rs index 27d8af4..f3d7559 100644 --- a/wfassoc/tests/extra_windows.rs +++ b/wfassoc/tests/extra_windows.rs @@ -1,5 +1,32 @@ +use std::path::Path; use wfassoc::extra::windows::*; +#[test] +fn test_icon_rc() { + +} + +#[test] +fn test_str_rc() { + +} + +#[test] +fn test_expand_string() { + +} + +#[test] +fn test_icon() { + fn tester(file: &str, index: i32) { + let icon = Icon::new(Path::new(file), index, IconSizeKind::Small); + assert!(icon.is_ok()) + } + + // We pick it from "jpegfile" ProgId + tester("imageres.dll", 72); +} + #[test] fn test_cmd_args() { // Declare tester