mirror of
https://github.com/loot/loot-condition-interpreter.git
synced 2026-07-27 14:16:09 -07:00
203 lines
6.1 KiB
Rust
203 lines
6.1 KiB
Rust
use std::panic::catch_unwind;
|
|
use std::path::PathBuf;
|
|
use std::sync::RwLock;
|
|
|
|
use libc::{c_char, c_int, size_t};
|
|
use loot_condition_interpreter::State;
|
|
|
|
use crate::constants::*;
|
|
use crate::helpers::{
|
|
error, map_game_type, map_plugin_crcs, map_plugin_versions, to_str, to_str_vec,
|
|
};
|
|
|
|
#[allow(non_camel_case_types)]
|
|
pub struct lci_state(pub RwLock<State>);
|
|
|
|
#[allow(non_camel_case_types)]
|
|
#[repr(C)]
|
|
pub struct plugin_version {
|
|
pub plugin_name: *const c_char,
|
|
pub version: *const c_char,
|
|
}
|
|
|
|
#[allow(non_camel_case_types)]
|
|
#[repr(C)]
|
|
pub struct plugin_crc {
|
|
pub plugin_name: *const c_char,
|
|
pub crc: u32,
|
|
}
|
|
|
|
#[no_mangle]
|
|
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() {
|
|
error(LCI_ERROR_INVALID_ARGS, "Null pointer passed")
|
|
} else {
|
|
let game_type = match map_game_type(game_type) {
|
|
Ok(x) => x,
|
|
Err(x) => return error(x, "Invalid game specified"),
|
|
};
|
|
|
|
let data_path = match to_str(data_path) {
|
|
Ok(x) => PathBuf::from(x),
|
|
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,
|
|
)))));
|
|
|
|
LCI_OK
|
|
}
|
|
})
|
|
.unwrap_or(LCI_ERROR_PANICKED)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn lci_state_destroy(state: *mut lci_state) {
|
|
if !state.is_null() {
|
|
drop(Box::from_raw(state));
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn lci_state_set_active_plugins(
|
|
state: *mut lci_state,
|
|
plugin_names: *const *const c_char,
|
|
num_plugins: size_t,
|
|
) -> c_int {
|
|
catch_unwind(|| {
|
|
if state.is_null() {
|
|
error(LCI_ERROR_INVALID_ARGS, "Null state pointer passed")
|
|
} else if plugin_names.is_null() && num_plugins != 0 {
|
|
error(
|
|
LCI_ERROR_INVALID_ARGS,
|
|
"Null plugin_names pointer passed but num_plugins is non-zero",
|
|
)
|
|
} else if !plugin_names.is_null() && num_plugins == 0 {
|
|
error(
|
|
LCI_ERROR_INVALID_ARGS,
|
|
"Non-null plugin_names pointer passed but num_plugins is zero",
|
|
)
|
|
} else {
|
|
let plugins: Vec<&str> = match to_str_vec(plugin_names, num_plugins) {
|
|
Ok(x) => x,
|
|
Err(e) => return e,
|
|
};
|
|
|
|
let mut state = match (*state).0.write() {
|
|
Err(e) => return error(LCI_ERROR_POISONED_THREAD_LOCK, &e.to_string()),
|
|
Ok(h) => h,
|
|
};
|
|
|
|
state.set_active_plugins(&plugins);
|
|
|
|
LCI_OK
|
|
}
|
|
})
|
|
.unwrap_or(LCI_ERROR_PANICKED)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn lci_state_set_plugin_versions(
|
|
state: *mut lci_state,
|
|
plugin_versions: *const plugin_version,
|
|
num_plugins: size_t,
|
|
) -> c_int {
|
|
catch_unwind(|| {
|
|
if state.is_null() {
|
|
error(LCI_ERROR_INVALID_ARGS, "Null state pointer passed")
|
|
} else if plugin_versions.is_null() && num_plugins != 0 {
|
|
error(
|
|
LCI_ERROR_INVALID_ARGS,
|
|
"Null plugin_versions pointer passed but num_plugins is non-zero",
|
|
)
|
|
} else if !plugin_versions.is_null() && num_plugins == 0 {
|
|
error(
|
|
LCI_ERROR_INVALID_ARGS,
|
|
"Non-null plugin_versions pointer passed but num_plugins is zero",
|
|
)
|
|
} else {
|
|
let plugin_versions = match map_plugin_versions(plugin_versions, num_plugins) {
|
|
Ok(x) => x,
|
|
Err(e) => return e,
|
|
};
|
|
|
|
let mut state = match (*state).0.write() {
|
|
Err(e) => return error(LCI_ERROR_POISONED_THREAD_LOCK, &e.to_string()),
|
|
Ok(h) => h,
|
|
};
|
|
|
|
state.set_plugin_versions(&plugin_versions);
|
|
|
|
LCI_OK
|
|
}
|
|
})
|
|
.unwrap_or(LCI_ERROR_PANICKED)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn lci_state_set_crc_cache(
|
|
state: *mut lci_state,
|
|
entries: *const plugin_crc,
|
|
num_entries: size_t,
|
|
) -> c_int {
|
|
catch_unwind(|| {
|
|
if state.is_null() {
|
|
error(LCI_ERROR_INVALID_ARGS, "Null state pointer passed")
|
|
} else if entries.is_null() && num_entries != 0 {
|
|
error(
|
|
LCI_ERROR_INVALID_ARGS,
|
|
"Null entries pointer passed but num_entries is non-zero",
|
|
)
|
|
} else if !entries.is_null() && num_entries == 0 {
|
|
error(
|
|
LCI_ERROR_INVALID_ARGS,
|
|
"Non-null entries pointer passed but num_entries is zero",
|
|
)
|
|
} else {
|
|
let plugin_crcs = match map_plugin_crcs(entries, num_entries) {
|
|
Ok(x) => x,
|
|
Err(e) => return e,
|
|
};
|
|
|
|
match (*state).0.write() {
|
|
Err(e) => error(LCI_ERROR_POISONED_THREAD_LOCK, &e.to_string()),
|
|
Ok(mut s) => match s.set_cached_crcs(&plugin_crcs) {
|
|
Err(e) => error(LCI_ERROR_POISONED_THREAD_LOCK, &e.to_string()),
|
|
Ok(_) => LCI_OK,
|
|
},
|
|
}
|
|
}
|
|
})
|
|
.unwrap_or(LCI_ERROR_PANICKED)
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn lci_state_clear_condition_cache(state: *mut lci_state) -> c_int {
|
|
catch_unwind(|| {
|
|
if state.is_null() {
|
|
error(LCI_ERROR_INVALID_ARGS, "Null state pointer passed")
|
|
} else {
|
|
match (*state).0.write() {
|
|
Err(e) => error(LCI_ERROR_POISONED_THREAD_LOCK, &e.to_string()),
|
|
Ok(mut s) => match s.clear_condition_cache() {
|
|
Err(e) => error(LCI_ERROR_POISONED_THREAD_LOCK, &e.to_string()),
|
|
Ok(_) => LCI_OK,
|
|
},
|
|
}
|
|
}
|
|
})
|
|
.unwrap_or(LCI_ERROR_PANICKED)
|
|
}
|