fix: fix expand string error
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -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",
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user