1
0

fix: fix expand string error

This commit is contained in:
2026-05-18 20:46:31 +08:00
parent 53cc8edcfd
commit 3b0080849d
6 changed files with 82 additions and 20 deletions

7
Cargo.lock generated
View File

@@ -480,6 +480,12 @@ version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "strfmt"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29fdc163db75f7b5ffa3daf0c5a7136fb0d4b2f35523cd1769da05e034159feb"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@@ -683,6 +689,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"regex", "regex",
"strfmt",
"thiserror", "thiserror",
"uuid", "uuid",
"widestring", "widestring",

View File

@@ -22,3 +22,6 @@ widestring = "1.2.1"
indexmap = "2.11.4" indexmap = "2.11.4"
regex = "1.11.3" regex = "1.11.3"
uuid = { version = "1.18.1", features = ["v4"] } uuid = { version = "1.18.1", features = ["v4"] }
[dev-dependencies]
strfmt = "0.2.5"

View File

@@ -622,11 +622,15 @@ impl Program {
// Before setting it, we must make sure this extension is existing // Before setting it, we must make sure this extension is existing
ext_key.ensure(scope)?; ext_key.ensure(scope)?;
ext_key.set_default(scope, Some(progid_key.inner()))?; ext_key.set_default(scope, Some(progid_key.inner()))?;
}
None => return Err(ProgramError::BadIndex),
};
// Everything is okey.
// Notify changes and return
win32::utilities::notify_assoc_changed();
Ok(()) Ok(())
} }
None => Err(ProgramError::BadIndex),
}
}
pub fn unlink_ext(&mut self, scope: Scope, index: usize) -> Result<(), ProgramError> { pub fn unlink_ext(&mut self, scope: Scope, index: usize) -> Result<(), ProgramError> {
match self.ext_keys.get_mut(index) { match self.ext_keys.get_mut(index) {
@@ -640,11 +644,15 @@ impl Program {
// Before setting it, we must make sure this extension is existing // Before setting it, we must make sure this extension is existing
ext_key.ensure(scope)?; ext_key.ensure(scope)?;
ext_key.set_default(scope, None)?; ext_key.set_default(scope, None)?;
}
None => return Err(ProgramError::BadIndex),
}
// Everything is okey.
// Notify changes and return
win32::utilities::notify_assoc_changed();
Ok(()) Ok(())
} }
None => Err(ProgramError::BadIndex),
}
}
pub fn query_ext( pub fn query_ext(
&self, &self,

View File

@@ -20,6 +20,8 @@ pub enum Error {
#[error("{0}")] #[error("{0}")]
UnexpectedBlankKey(#[from] regext::BlankPathError), UnexpectedBlankKey(#[from] regext::BlankPathError),
#[error("{0}")]
ExpandEnvVar(#[from] concept::ExpandEnvVarError),
#[error("{0}")] #[error("{0}")]
LoadIconRc(#[from] concept::LoadIconRcError), LoadIconRc(#[from] concept::LoadIconRcError),
#[error("{0}")] #[error("{0}")]
@@ -159,7 +161,19 @@ impl IconResVariant {
pub fn extract(&self, kind: concept::IconSizeKind) -> Result<concept::IconRc> { pub fn extract(&self, kind: concept::IconSizeKind) -> Result<concept::IconRc> {
let rc = match self { let rc = match self {
IconResVariant::Plain(v) => concept::IconRc::with_ico_file(v.as_str(), kind)?, IconResVariant::Plain(v) => concept::IconRc::with_ico_file(v.as_str(), kind)?,
IconResVariant::RefStr(v) => concept::IconRc::new(v.get_path(), v.get_index(), kind)?, IconResVariant::RefStr(v) => {
// Try expand path part if possible
let path_part = match concept::ExpandString::new(v.get_path()) {
Ok(expand_string) => expand_string.expand()?,
Err(_) => v.get_path().to_string(),
};
eprintln!("{path_part}");
// Get index part.
let index_part = v.get_index();
eprintln!("{index_part}");
// Resolve icon resource
concept::IconRc::new(&path_part, index_part, kind)?
},
}; };
Ok(rc) Ok(rc)
} }
@@ -214,7 +228,17 @@ impl StrResVariant {
StrResVariant::Plain(v) => v.clone(), StrResVariant::Plain(v) => v.clone(),
// For string reference string, we try to resolve it. // For string reference string, we try to resolve it.
StrResVariant::RefStr(v) => { StrResVariant::RefStr(v) => {
let rc = concept::StrRc::new(v.get_path(), v.get_index())?; // Try expand path part if possible
let path_part = match concept::ExpandString::new(v.get_path()) {
Ok(expand_string) => expand_string.expand()?,
Err(_) => v.get_path().to_string(),
};
eprintln!("{path_part}");
// Get index part
let index_part = v.get_index();
eprintln!("{index_part}");
// Resolve string resource
let rc = concept::StrRc::new(&path_part, index_part)?;
rc.into_string() rc.into_string()
} }
}; };

View File

@@ -724,16 +724,16 @@ impl ExpandString {
/// Expand the variables located in this string /// Expand the variables located in this string
/// and produce the final usable string. /// and produce the final usable string.
pub fn expand_string(&self) -> Result<String, ExpandEnvVarError> { pub fn expand(&self) -> Result<String, ExpandEnvVarError> {
use windows_sys::Win32::System::Environment::ExpandEnvironmentStringsW; use windows_sys::Win32::System::Environment::ExpandEnvironmentStringsW;
// Fetch the size of expand result // Fetch the size of expand result
let source = WideCString::from_str(self.inner.as_str())?; let source = WideCString::from_str(self.inner.as_str())?;
// The return size is including null terminal.
let size = unsafe { ExpandEnvironmentStringsW(source.as_ptr(), std::ptr::null_mut(), 0) }; let size = unsafe { ExpandEnvironmentStringsW(source.as_ptr(), std::ptr::null_mut(), 0) };
if size == 0 { if size == 0 {
return Err(ExpandEnvVarError::ExpandFunction); return Err(ExpandEnvVarError::ExpandFunction);
} }
let size_no_nul = size.checked_sub(1).ok_or(ExpandEnvVarError::Underflow)?;
// Allocate buffer for it. // Allocate buffer for it.
let len: usize = size.try_into()?; let len: usize = size.try_into()?;
@@ -741,7 +741,7 @@ impl ExpandString {
let mut buffer = vec![0; len]; let mut buffer = vec![0; len];
// Receive result // Receive result
let size = let size =
unsafe { ExpandEnvironmentStringsW(source.as_ptr(), buffer.as_mut_ptr(), size_no_nul) }; unsafe { ExpandEnvironmentStringsW(source.as_ptr(), buffer.as_mut_ptr(), size) };
if size == 0 { if size == 0 {
return Err(ExpandEnvVarError::ExpandFunction); return Err(ExpandEnvVarError::ExpandFunction);
} }

View File

@@ -1,4 +1,4 @@
use std::str::FromStr; use std::{collections::HashMap, str::FromStr};
use wfassoc::win32::concept::*; use wfassoc::win32::concept::*;
// region: File Extension // region: File Extension
@@ -218,16 +218,36 @@ fn test_str_rc() {
#[test] #[test]
fn test_expand_string() { fn test_expand_string() {
fn tester(s: &str) { fn tester(fmt: &str, var_name: &str) {
let rv = ExpandString::new(s); // We first insert variable name into format string to get the final string
assert!(rv.is_ok()); let mut vars = HashMap::new();
let rv = rv.unwrap(); vars.insert("0".to_string(), var_name.to_string());
let final_string = strfmt::strfmt(fmt, &vars).unwrap();
let rv = rv.expand_string(); // The we try expanding final string first
assert!(rv.is_ok()); let expand_final_string = ExpandString::new(&final_string);
assert!(expand_final_string.is_ok());
let expand_final_string = expand_final_string.unwrap();
let expanded_final_string = expand_final_string.expand();
assert!(expanded_final_string.is_ok());
let expanded_final_string= expanded_final_string.unwrap();
// Then we expand variable name individually
let expand_var_name = ExpandString::new(var_name);
assert!(expand_var_name.is_ok());
let expand_var_name = expand_var_name.unwrap();
let expanded_var_name = expand_var_name.expand();
assert!(expanded_var_name.is_ok());
let expanded_var_name = expanded_var_name.unwrap();
// Finally, we directly insert expanded variable name into format string
// to get the string which can be compared with final string.
vars.insert("0".to_string(), expanded_var_name.clone());
let built_final_string = strfmt::strfmt(fmt, &vars).unwrap();
assert_eq!(expanded_final_string.to_string(), built_final_string);
} }
tester(r#"%SystemRoot%\System32\shell32.dll"#); tester(r#"{0}\System32\shell32.dll"#, "%SystemRoot%");
} }
// endregion // endregion