diff --git a/wfassoc/src/highlevel.rs b/wfassoc/src/highlevel.rs index f185c0e..3d94a97 100644 --- a/wfassoc/src/highlevel.rs +++ b/wfassoc/src/highlevel.rs @@ -1,8 +1,10 @@ use crate::{lowlevel, utilities, win32::concept}; +use regex::Regex; use std::collections::HashMap; use std::ffi::OsStr; use std::path::Path; use std::rc::Rc; +use std::sync::LazyLock; use thiserror::Error as TeError; pub use lowlevel::{Scope, View}; @@ -19,6 +21,10 @@ pub enum SchemaError { /// Error occurs when trying converting `Schema` into `Program`. #[derive(Debug, TeError)] pub enum ParseProgramError { + #[error("{0}")] + BadExtBody(#[from] concept::BadExtBodyError), + #[error("{0}")] + BadProgIdPart(#[from] concept::BadProgIdPartError), #[error("{0}")] BadFileName(#[from] concept::BadFileNameError), #[error("{0}")] @@ -31,6 +37,10 @@ pub enum ParseProgramError { NoDirNamePart, #[error("given identifier is not presented in dict")] NoSuchIdentifier, + #[error("extension name should not be empty")] + EmptyExtension, + #[error("given program identifier is not allowed")] + BadIdentifier, } /// Error occurs when operating with `Program`. @@ -124,6 +134,9 @@ impl Schema { } } + /// + /// + /// The passed `ext` string should be without leading dot `.`. pub fn add_ext( &mut self, ext: &str, @@ -241,14 +254,39 @@ impl Program { index_map: &HashMap, ) -> Result, ParseProgramError> { match index_map.get(key) { - Some(index) => match vector.get(*index) { - Some(value) => Ok(value.clone()), - None => Err(ParseProgramError::NoSuchIdentifier), - }, + Some(index) => Ok(vector + .get(*index) + .expect("unexpected invalid index") + .clone()), None => Err(ParseProgramError::NoSuchIdentifier), } } + /// Build ProgId from identifier and given file extension. + fn build_progid( + identifier: &str, + ext: &str, + ) -> Result { + // Use Regex to check identifier + static RE: LazyLock = LazyLock::new(|| { + Regex::new(r"^[a-zA-Z][a-zA-Z0-9_-]*$").expect("unexpected bad regex pattern string") + }); + let identifier = match RE.captures(identifier) { + Some(_) => identifier, + None => return Err(ParseProgramError::BadIdentifier), + }; + + // Capitalize first ASCII of ext + let ext = utilities::capitalize_first_ascii(ext); + + // Build strict ProgId + let progid = concept::ProgId::new(identifier, &ext, None)?; + // Then build losse ProgId + let losse_progid: lowlevel::LosseProgId = progid.into(); + // Return built result + Ok(losse_progid) + } + /// Try creating Program from Schema. pub fn new(schema: Schema) -> Result { // Extract file name part and directory name part respectively. @@ -301,16 +339,60 @@ impl Program { .map(|behavior| Self::resolve_index(&behavior, &behaviors, &behaviors_index_map)) .transpose()?; - // Process file extensions. - // We need create ProgIds list and Exts list at the same time. + // We build ProgIdKey and ExtKey list at the same time + let mut progid_keys: Vec> = Vec::with_capacity(schema.exts.len()); + let mut ext_keys: Vec = Vec::with_capacity(schema.exts.len()); + for (key, value) in &schema.exts { + // Build ProgId first. + let progid = Self::build_progid(&schema.identifier, key.as_str())?; + // Then build ProgId key. + let progid_key = lowlevel::ProgIdKey::new(progid); - todo!(); - // Ok(Self { - // app_paths_key, - // applications_key, - // file_name, - // dir_name, - // }) + // Build essential fields for program ProgId key struct. + let name = Self::resolve_index(&value.name, &strs, &strs_index_map)?; + let icon = Self::resolve_index(&value.icon, &icons, &icons_index_map)?; + let behavior = Self::resolve_index(&value.behavior, &behaviors, &behaviors_index_map)?; + + // Create program ProgId key struct + let progid_key = ProgramProgIdKey { + key: progid_key, + name, + icon, + behavior, + }; + // Create Rc style + let progid_key = Rc::new(progid_key); + + // Build Ext. + let ext = concept::Ext::new(key.as_str())?; + let ext_key = lowlevel::ExtKey::new(ext); + + // Create program Ext key struct + let ext_key = ProgramExtKey { + key: ext_key, + assoc: progid_key.clone(), + }; + + // Add them into list + progid_keys.push(progid_key); + ext_keys.push(ext_key); + } + + // Everything is okey + Ok(Self { + app_paths_key, + applications_key, + file_name, + dir_name, + name, + icon, + behavior, + strs, + icons, + behaviors, + progid_keys, + ext_keys, + }) } }