diff --git a/ffi/src/state.rs b/ffi/src/state.rs index 5ae65ee..479a247 100644 --- a/ffi/src/state.rs +++ b/ffi/src/state.rs @@ -32,10 +32,9 @@ pub unsafe extern "C" fn lci_state_create( state: *mut *mut lci_state, game_type: c_int, data_path: *const c_char, - loot_path: *const c_char, ) -> c_int { catch_unwind(|| { - if state.is_null() || data_path.is_null() || loot_path.is_null() { + if state.is_null() || data_path.is_null() { error(LCI_ERROR_INVALID_ARGS, "Null pointer passed") } else { let game_type = match map_game_type(game_type) { @@ -48,13 +47,8 @@ pub unsafe extern "C" fn lci_state_create( Err(e) => return e, }; - let loot_path = match to_str(loot_path) { - Ok(x) => PathBuf::from(x), - Err(e) => return e, - }; - *state = Box::into_raw(Box::new(lci_state(RwLock::new(State::new( - game_type, data_path, loot_path, + game_type, data_path, ))))); LCI_OK diff --git a/ffi/tests/ffi.cpp b/ffi/tests/ffi.cpp index dcc53d0..81024be 100644 --- a/ffi/tests/ffi.cpp +++ b/ffi/tests/ffi.cpp @@ -54,7 +54,7 @@ void test_lci_state_create() { printf("testing lci_state_create()...\n"); lci_state * state = nullptr; - int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, ".", "."); + int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "."); assert(return_code == LCI_OK); assert(state != nullptr); @@ -66,7 +66,7 @@ void test_lci_condition_eval() { printf("testing lci_condition_eval()...\n"); lci_state * state = nullptr; - int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "../../tests/testing-plugins/Oblivion/Data", "."); + int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "../../tests/testing-plugins/Oblivion/Data"); assert(return_code == LCI_OK); assert(state != nullptr); @@ -86,7 +86,7 @@ void test_lci_state_set_active_plugins() { printf("testing lci_state_set_active_plugins()...\n"); lci_state * state = nullptr; - int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "../../tests/testing-plugins/Oblivion/Data", "."); + int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "../../tests/testing-plugins/Oblivion/Data"); assert(return_code == LCI_OK); assert(state != nullptr); @@ -118,7 +118,7 @@ void test_lci_state_set_plugin_versions() { printf("testing lci_state_set_plugin_versions()...\n"); lci_state * state = nullptr; - int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "../../tests/testing-plugins/Oblivion/Data", "."); + int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "../../tests/testing-plugins/Oblivion/Data"); assert(return_code == LCI_OK); assert(state != nullptr); @@ -153,7 +153,7 @@ void test_lci_state_set_crc_cache() { printf("testing lci_state_set_crc_cache()...\n"); lci_state * state = nullptr; - int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "../../tests/testing-plugins/Oblivion/Data", "."); + int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "../../tests/testing-plugins/Oblivion/Data"); assert(return_code == LCI_OK); assert(state != nullptr); @@ -185,7 +185,7 @@ void test_lci_state_set_additional_data_paths() { printf("testing lci_state_set_additional_data_paths()...\n"); lci_state * state = nullptr; - int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, ".", "."); + int return_code = lci_state_create(&state, LCI_GAME_OBLIVION, "."); assert(return_code == LCI_OK); assert(state != nullptr); diff --git a/src/function/eval.rs b/src/function/eval.rs index c38abaa..7c42700 100644 --- a/src/function/eval.rs +++ b/src/function/eval.rs @@ -329,24 +329,19 @@ mod tests { } fn state_with_active_plugins>(data_path: T, active_plugins: &[&str]) -> State { - state_with_data(data_path, Vec::default(), "", active_plugins, &[]) - } - - fn state_with_loot_path>(data_path: T, loot_path: &str) -> State { - state_with_data(data_path, Vec::default(), loot_path, &[], &[]) + state_with_data(data_path, Vec::default(), active_plugins, &[]) } fn state_with_versions>( data_path: T, plugin_versions: &[(&str, &str)], ) -> State { - state_with_data(data_path, Vec::default(), "", &[], plugin_versions) + state_with_data(data_path, Vec::default(), &[], plugin_versions) } fn state_with_data>( data_path: T, additional_data_paths: Vec, - loot_path: &str, active_plugins: &[&str], plugin_versions: &[(&str, &str)], ) -> State { @@ -370,7 +365,6 @@ mod tests { game_type: GameType::Oblivion, data_path, additional_data_paths, - loot_path: loot_path.into(), active_plugins: active_plugins .into_iter() .map(|s| s.to_lowercase()) @@ -425,24 +419,6 @@ mod tests { assert!(function.eval(&state).unwrap()); } - #[test] - #[allow(non_snake_case)] - fn function_file_path_eval_should_be_true_if_given_LOOT_and_loot_path_exists() { - let function = Function::FilePath(PathBuf::from("LOOT")); - let state = state_with_loot_path(".", "Cargo.toml"); - - assert!(function.eval(&state).unwrap()); - } - - #[test] - #[allow(non_snake_case)] - fn function_file_path_eval_should_be_false_if_given_LOOT_and_loot_path_does_not_exist() { - let function = Function::FilePath(PathBuf::from("LOOT")); - let state = state_with_loot_path(".", "missing"); - - assert!(!function.eval(&state).unwrap()); - } - #[test] fn function_file_path_eval_should_not_check_for_ghosted_non_plugin_file() { let tmp_dir = tempdir().unwrap(); @@ -515,13 +491,7 @@ mod tests { #[test] fn function_file_regex_eval_should_check_all_configured_data_paths() { let function = Function::FileRegex(PathBuf::from("Data"), regex("Blank\\.esp")); - let state = state_with_data( - "./src", - vec!["./tests/testing-plugins/Oblivion"], - ".", - &[], - &[], - ); + let state = state_with_data("./src", vec!["./tests/testing-plugins/Oblivion"], &[], &[]); assert!(function.eval(&state).unwrap()); } @@ -781,7 +751,6 @@ mod tests { let state = state_with_data( "./tests/testing-plugins/Skyrim", vec!["./tests/testing-plugins/Oblivion"], - ".", &[], &[], ); @@ -878,24 +847,6 @@ mod tests { assert!(!function.eval(&state).unwrap()); } - #[test] - #[allow(non_snake_case)] - fn function_checksum_eval_should_be_true_if_given_LOOT_crc_matches() { - let function = Function::Checksum(PathBuf::from("LOOT"), 0x374E2A6F); - let state = state_with_loot_path(".", "tests/testing-plugins/Oblivion/Data/Blank.esm"); - - assert!(function.eval(&state).unwrap()); - } - - #[test] - #[allow(non_snake_case)] - fn function_checksum_eval_should_be_false_if_given_LOOT_crc_does_not_match() { - let function = Function::Checksum(PathBuf::from("LOOT"), 0xDEADBEEF); - let state = state_with_loot_path(".", "tests/testing-plugins/Oblivion/Data/Blank.esm"); - - assert!(!function.eval(&state).unwrap()); - } - #[test] fn function_checksum_eval_should_be_false_if_given_a_directory_path() { // The given CRC is the CRC-32 of the directory as calculated by 7-zip. diff --git a/src/function/path.rs b/src/function/path.rs index 58c82e6..84d6d80 100644 --- a/src/function/path.rs +++ b/src/function/path.rs @@ -56,34 +56,30 @@ pub fn normalise_file_name(game_type: GameType, name: &str) -> &str { } pub fn resolve_path(state: &State, path: &Path) -> PathBuf { - if path == Path::new("LOOT") { - state.loot_path.clone() + // First check external data paths, as files there may override files in the main data path. + for data_path in &state.additional_data_paths { + let mut path = data_path.join(path); + + if path.exists() { + return path; + } + + if has_unghosted_plugin_file_extension(state.game_type, &path) { + path = add_ghost_extension(path); + } + + if path.exists() { + return path; + } + } + + // Now check the main data path. + let path = state.data_path.join(path); + + if !path.exists() && has_unghosted_plugin_file_extension(state.game_type, &path) { + add_ghost_extension(path) } else { - // First check external data paths, as files there may override files in the main data path. - for data_path in &state.additional_data_paths { - let mut path = data_path.join(path); - - if path.exists() { - return path; - } - - if has_unghosted_plugin_file_extension(state.game_type, &path) { - path = add_ghost_extension(path); - } - - if path.exists() { - return path; - } - } - - // Now check the main data path. - let path = state.data_path.join(path); - - if !path.exists() && has_unghosted_plugin_file_extension(state.game_type, &path) { - add_ghost_extension(path) - } else { - path - } + path } } @@ -404,20 +400,10 @@ mod tests { assert_eq!(PathBuf::from("plugin.ghost"), path); } - #[test] - #[allow(non_snake_case)] - fn resolve_path_should_return_loot_path_if_given_LOOT() { - let loot_path = PathBuf::from("loot.exe"); - let state = State::new(GameType::Skyrim, "data".into(), loot_path.clone()); - let path = resolve_path(&state, Path::new("LOOT")); - - assert_eq!(loot_path, path); - } - #[test] fn resolve_path_should_return_the_data_path_prefixed_path_if_it_exists() { let data_path = PathBuf::from("."); - let state = State::new(GameType::Skyrim, data_path.clone(), "loot.exe".into()); + let state = State::new(GameType::Skyrim, data_path.clone()); let input_path = Path::new("README.md"); let resolved_path = resolve_path(&state, input_path); @@ -428,7 +414,7 @@ mod tests { fn resolve_path_should_return_the_data_path_prefixed_path_if_it_does_not_exist_and_is_not_an_unghosted_plugin_filename( ) { let data_path = PathBuf::from("."); - let state = State::new(GameType::Skyrim, data_path.clone(), "loot.exe".into()); + let state = State::new(GameType::Skyrim, data_path.clone()); let input_path = Path::new("plugin.esp.ghost"); let resolved_path = resolve_path(&state, input_path); @@ -444,7 +430,7 @@ mod tests { fn resolve_path_should_return_the_given_data_relative_path_plus_a_ghost_extension_if_the_plugin_path_does_not_exist( ) { let data_path = PathBuf::from("."); - let state = State::new(GameType::Skyrim, data_path.clone(), "loot.exe".into()); + let state = State::new(GameType::Skyrim, data_path.clone()); let input_path = Path::new("plugin.esp"); let resolved_path = resolve_path(&state, input_path); @@ -474,7 +460,7 @@ mod tests { .unwrap(); copy(Path::new("Cargo.toml"), data_path.join("Cargo.toml")).unwrap(); - let mut state = State::new(GameType::Skyrim, data_path, "loot.exe".into()); + let mut state = State::new(GameType::Skyrim, data_path); state.set_additional_data_paths(vec![external_data_path_1, external_data_path_2.clone()]); let input_path = Path::new("Cargo.toml"); diff --git a/src/lib.rs b/src/lib.rs index 4b0d178..d42b7fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,8 +54,6 @@ pub struct State { /// Other directories that may contain plugins and other game files, used before data_path and /// in the order they're listed. additional_data_paths: Vec, - /// Path to the LOOT executable, used to resolve conditions that use the "LOOT" path. - loot_path: PathBuf, /// Lowercased plugin filenames. active_plugins: HashSet, /// Lowercased paths. @@ -67,12 +65,11 @@ pub struct State { } impl State { - pub fn new(game_type: GameType, data_path: PathBuf, loot_path: PathBuf) -> Self { + pub fn new(game_type: GameType, data_path: PathBuf) -> Self { State { game_type, data_path, additional_data_paths: Vec::default(), - loot_path, active_plugins: HashSet::default(), crc_cache: RwLock::default(), plugin_versions: HashMap::default(), @@ -296,7 +293,6 @@ mod tests { game_type: GameType::Oblivion, data_path, additional_data_paths: Vec::default(), - loot_path: PathBuf::new(), active_plugins: HashSet::new(), crc_cache: RwLock::default(), plugin_versions: HashMap::default(),