feat(windows): add resource reference string parsers
Add IconRc and StrRc structs for parsing Windows resource reference strings. Implement FromStr and Display traits for both types along with error handling. Rename BadExpandStrError to ParseExpandStrError for consistency.
This commit is contained in:
@ -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<Icon, FetchIconError> {
|
||||
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<Self, Self::Err> {
|
||||
static RE: LazyLock<Regex> =
|
||||
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::<u32>()
|
||||
.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<String, FetchStrError> {
|
||||
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<Self, Self::Err> {
|
||||
static RE: LazyLock<Regex> = 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::<u32>()
|
||||
.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<Self, BadExpandStrError> {
|
||||
pub fn new(s: &str) -> Result<Self, ParseExpandStrError> {
|
||||
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<Self, Self::Err> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user