diff --git a/wfassoc/src/highlevel.rs b/wfassoc/src/highlevel.rs index eee0f43..cba00a1 100644 --- a/wfassoc/src/highlevel.rs +++ b/wfassoc/src/highlevel.rs @@ -1,5 +1,8 @@ -use crate::lowlevel; +use crate::{lowlevel, utilities, win32}; use std::collections::HashMap; +use std::ffi::OsStr; +use std::rc::Rc; +use std::path::Path; use thiserror::Error as TeError; pub use lowlevel::{Scope, View}; @@ -15,7 +18,16 @@ pub enum SchemaError { /// Error occurs when trying converting `Schema` into `Program`. #[derive(Debug, TeError)] -pub enum ParseProgramError {} +pub enum ParseProgramError { + #[error("{0}")] + BadFileName(#[from] win32::concept::BadFileNameError), + #[error("{0}")] + CastOsStr(#[from] utilities::CastOsStrError), + #[error("given path doesn't has legal file name part")] + NoFileNamePart, + #[error("given path doesn't has legal directory part")] + NoDirNamePart, +} /// Error occurs when operating with `Program`. #[derive(Debug, TeError)] @@ -161,7 +173,20 @@ impl SchemaExt { /// Program is a complete and immutable program representer pub struct Program { + app_paths_key: lowlevel::AppPathsKey, + applications_key: lowlevel::ApplicationsKey, + file_name: String, + dir_name: String, + name: Rc, + icon: Rc, + behavior: Rc, + strs: Vec>, + icons: Vec>, + behaviors: Vec>, + + progid_keys: Vec>, + ext_keys: Vec, } impl TryFrom for Program { @@ -173,15 +198,49 @@ impl TryFrom for Program { } impl Program { + /// Extract the file name part from full path to application, + /// which was used in Registry path component. + fn extract_file_name(full_path: &Path) -> Result<&OsStr, ParseProgramError> { + full_path + .file_name() + .ok_or(ParseProgramError::NoFileNamePart) + } + + /// Extract the start in path from full path to application, + /// which basically is the stem of full path. + fn extract_dir_name(full_path: &Path) -> Result<&OsStr, ParseProgramError> { + full_path + .parent() + .map(|p| p.as_os_str()) + .ok_or(ParseProgramError::NoDirNamePart) + } + /// Try creating Program from Schema. pub fn new(schema: Schema) -> Result { - todo!() + // Extract file name part and directory name part respectively. + let schema_path = Path::new(&schema.path); + let file_name = Self::extract_file_name(schema_path)?; + let file_name = String::from(utilities::osstr_to_str(file_name)?); + let dir_name = Self::extract_dir_name(schema_path)?; + let dir_name = String::from(utilities::osstr_to_str(dir_name)?); + // Build app paths key and applications key respectively + let key = win32::concept::FileName::new(&file_name)?; + let app_paths_key = lowlevel::AppPathsKey::new(key.clone()); + let applications_key = lowlevel::ApplicationsKey::new(key.clone()); + + todo!(); + // Ok(Self { + // app_paths_key, + // applications_key, + // file_name, + // dir_name, + // }) } } impl Program { /// Register this application. - /// + /// /// If there is registration of this application, /// this function will return error. pub fn register(&mut self, scope: Scope) -> Result<(), ProgramError> { @@ -189,7 +248,7 @@ impl Program { } /// Unregister this application. - /// + /// /// If there is no registration of this application, /// this function will return error. pub fn unregister(&mut self, scope: Scope) -> Result<(), ProgramError> { @@ -199,6 +258,8 @@ impl Program { /// Check whether this application has been registered in given view. /// /// Please note that this is a rough check and do not validate any data. + /// + /// The return value only ensures the pre-requirement of `register` and `unregister`. pub fn is_registered(&self, view: View) -> Result { todo!() } @@ -208,6 +269,41 @@ impl Program { // region: Program Internals +/// Internal used enum presenting a Program string resource. +#[derive(Debug)] +enum ProgramStr { + Plain(String), + RefStr(win32::concept::StrRefStr) +} + +/// Internal used enum presenting a Program icon resource. +#[derive(Debug)] +enum ProgramIcon { + Plain(String), + RefStr(win32::concept::IconRefStr) +} + +/// Internal used enum presenting a Program behavior (command line setups). +#[derive(Debug)] +struct ProgramBehavior { + inner: String, +} + +/// Internal used struct presenting a Program ProgId. +#[derive(Debug)] +struct ProgramProgIdKey { + key: lowlevel::ProgIdKey, + name: Rc, + icon: Rc, + behavior: Rc, +} + +/// Internal used struct presenting a Program file extension. +#[derive(Debug)] +struct ProgramExtKey { + key: lowlevel::ExtKey, + assoc: Rc +} // endregion diff --git a/wfassoc/src/lowlevel.rs b/wfassoc/src/lowlevel.rs index c6d5915..6df3987 100644 --- a/wfassoc/src/lowlevel.rs +++ b/wfassoc/src/lowlevel.rs @@ -88,16 +88,44 @@ impl Scope { // endregion +// region: App Paths Key + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AppPathsKey { key: win32::concept::FileName, } +impl AppPathsKey { + pub fn new(inner: win32::concept::FileName) -> Self { + Self { key: inner } + } + + pub fn inner(&self) -> &win32::concept::FileName { + &self.key + } +} + +// endregion + +// region: Applications Key + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ApplicationsKey { key: win32::concept::FileName, } +impl ApplicationsKey { + pub fn new(inner: win32::concept::FileName) -> Self { + Self { key: inner } + } + + pub fn inner(&self) -> &win32::concept::FileName { + &self.key + } +} + +// endregion + // region: File Extension Key #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -156,6 +184,16 @@ impl ExtKey { } +impl ExtKey { + pub fn new(inner: win32::concept::Ext) -> Self { + Self { ext: inner } + } + + pub fn inner(&self) -> &win32::concept::Ext { + &self.ext + } +} + // endregion // region: ProgId Key @@ -164,11 +202,11 @@ impl ExtKey { /// The enum representing a losse Programmatic Identifiers (ProgId). /// -/// In real world, not all software developers are willing to following Microsoft suggestions to use ProgId, +/// In real world, not all software developers are willing to following Microsoft suggestions to use ProgId. /// They use string which do not have any regulation as ProgId. /// This enum is designed for handling this scenario. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum LosseProgId { +pub enum LosseProgId { Plain(String), Strict(win32::concept::ProgId), } @@ -203,6 +241,16 @@ pub struct ProgIdKey { progid: LosseProgId, } +impl ProgIdKey { + pub fn new(inner: LosseProgId) -> Self { + Self { progid: inner } + } + + pub fn inner(&self) -> &LosseProgId { + &self.progid + } +} + // endregion // endregion diff --git a/wfassoc/src/win32/concept.rs b/wfassoc/src/win32/concept.rs index 62d48b5..8878b54 100644 --- a/wfassoc/src/win32/concept.rs +++ b/wfassoc/src/win32/concept.rs @@ -321,6 +321,7 @@ impl ParseIconRefStrError { /// /// As far as I know, the minus token `-` does nothing in this string. /// The following number is just the index. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct IconRefStr { /// The path part of this reference string. /// And it can be expandable. @@ -414,6 +415,7 @@ impl ParseStrRefStrError { /// /// As far as I know, the minus token `-` does nothing in this string. /// The following number is just the index. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct StrRefStr { /// The path part of this reference string. /// And it can be expandable. @@ -503,6 +505,7 @@ pub enum IconSizeKind { } /// The struct representing a loaded icon resource. +#[derive(Debug)] pub struct IconRc { icon: HICON, } @@ -593,6 +596,7 @@ pub enum LoadStrRcError { } /// The struct representing a loaded string resource. +#[derive(Debug)] pub struct StrRc { inner: String, } @@ -686,6 +690,7 @@ pub enum ExpandEnvVarError { /// The struct representing an Expand String, /// which contain environment variable in string, /// like `%LOCALAPPDATA%\SomeApp.exe`. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ExpandString { inner: String, } @@ -800,6 +805,8 @@ pub enum ParseFileNameError { EmbeddedNul(#[from] widestring::error::ContainsNul), /// Given string has illegal char as Windows file name. InvalidChar, + /// Given string is empty. + EmptyStr, } impl Display for FileName { @@ -814,7 +821,12 @@ impl FromStr for FileName { fn from_str(s: &str) -> Result { use windows_sys::Win32::UI::Shell::PathCleanupSpec; - // Make buffer and call function. + // If given string is empty, it must be illegal. + if s.is_empty() { + return Err(ParseFileNameError::EmptyStr); + } + + // Make buffer and call Win32 function for checking. let mut spec = WideCString::from_str(s)?; let rv = unsafe { PathCleanupSpec(std::ptr::null(), spec.as_mut_ptr()) }; if rv != 0 { diff --git a/wfassoc/tests/concept.rs b/wfassoc/tests/concept.rs index 526f0c4..8c76014 100644 --- a/wfassoc/tests/concept.rs +++ b/wfassoc/tests/concept.rs @@ -35,6 +35,7 @@ fn test_ext_parse() { } ok_tester(".jpg", "jpg"); + err_tester("."); err_tester(".jar.disabled"); err_tester("jar"); } @@ -247,6 +248,7 @@ fn test_file_name() { } ok_tester("GoodExecutable.exe"); + err_tester(""); err_tester("*.?xaml"); err_tester(r#"\\\lol///"#); }