1
0
This commit is contained in:
Kozlov Maxim 2023-08-03 09:36:40 +06:00
parent 5c30064d69
commit 04504a9a7e
9 changed files with 198 additions and 120 deletions

View File

@ -7,12 +7,13 @@ edition = "2021"
crate-type = ["cdylib"]
[profile.release]
opt-level = "z" # Optimize for size.
lto = true # Enable Link Time Optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
panic = "abort" # Abort on panic
strip = true # Automatically strip symbols from the binary.
opt-level = "z" # Optimize for size.
lto = true # Enable Link Time Optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
panic = "abort" # Abort on panic
strip = true # Automatically strip symbols from the binary.
[dependencies]
color-eyre = "0.6.2"
ureq = "2.7.1"
utf16_lit="2.0"
utf16_lit = "2.0"

1
rustfmt.toml Normal file
View File

@ -0,0 +1 @@
max_width = 80

View File

@ -1,9 +1,8 @@
use std::default;
use crate::ffi::{
connection::Connection,
types::{ParamValue, ReturnValue},
};
use color_eyre::eyre::{Result};
pub struct ComponentPropDescription {
pub name: &'static [u16],
@ -12,24 +11,31 @@ pub struct ComponentPropDescription {
}
pub struct ComponentFuncDescription {
pub name: &'static [u16],
pub names: Vec<&'static [u16]>,
pub params_count: usize,
pub returns_val: bool,
pub default_values: &'static [Option<ParamValue<'static>>],
pub default_values: &'static [Option<ParamValue>],
}
impl ComponentFuncDescription {
pub fn new<const params_count: usize>(
name: &'static [u16],
pub fn new<const PARAMS_COUNT: usize>(
names: Vec<&'static [u16]>,
returns_val: bool,
default_values: &'static [Option<ParamValue<'static>>; params_count],
default_values: &'static [Option<ParamValue>; PARAMS_COUNT],
) -> Self {
Self {
name,
params_count,
names,
params_count: PARAMS_COUNT,
returns_val,
default_values,
}
}
pub fn str_names(&self ) -> Vec<String> {
self.names.iter().map(|name_utf16| {
let name_string = String::from_utf16_lossy(name_utf16).trim_matches(char::from(0)).to_string();
name_string
}).collect()
}
}
pub trait AddIn {
@ -38,17 +44,17 @@ pub trait AddIn {
fn list_parameters(&self) -> Vec<ComponentPropDescription> {
Vec::new()
}
fn list_functions(&self) -> Vec<ComponentFuncDescription> {
fn list_functions(&self) -> Vec<&ComponentFuncDescription> {
Vec::new()
}
fn get_parameter(&self, name: &str) -> Option<ParamValue> {
fn get_parameter(&self, _name: &str) -> Option<ParamValue> {
None
}
fn set_parameter(&mut self, name: &str, value: &ParamValue) -> bool {
fn set_parameter(&mut self, _name: &str, _value: &ParamValue) -> bool {
false
}
fn call_function(&mut self, name: &str, params: &[ParamValue]) -> Option<ParamValue> {
None
fn call_function(&mut self, _name: &str, _params: &[ParamValue]) -> Result<Option<ParamValue>> {
Ok(None)
}
}
@ -62,8 +68,7 @@ impl<T: AddIn> AddInContainer<T> {
}
}
impl<T: AddIn> AddInWrapper for AddInContainer<T>{
impl<T: AddIn> AddInWrapper for AddInContainer<T> {
fn init(&mut self, interface: &'static Connection) -> bool {
self.add_in.init(interface)
}
@ -95,11 +100,9 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
.list_parameters()
.get(num)
.map(|x| x.name)
.or_else(|| self.add_in.list_parameters().get(alias).map(|x| x.name))
}
fn get_prop_val(&self, num: usize, val: ReturnValue) -> bool {
fn get_prop_val(&self, num: usize, val: ReturnValue) -> bool {
let param_desc_binding = self.add_in.list_parameters();
let Some(param_desc) = param_desc_binding.get(num) else {
return false
@ -115,12 +118,12 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
};
match param_data {
ParamValue::Str(data_unwrapped) => val.set_str(data_unwrapped),
ParamValue::I32(data_unwrapped) => val.set_i32(data_unwrapped),
ParamValue::Bool(data_unwrapped) => val.set_bool(data_unwrapped),
ParamValue::F64(data_unwrapped) => val.set_f64(data_unwrapped),
ParamValue::Date(data_unwrapped) => val.set_date(data_unwrapped),
ParamValue::Blob(data_unwrapped) => val.set_blob(data_unwrapped),
ParamValue::Str(data_unwrapped) => val.set_str(&data_unwrapped),
ParamValue::Blob(data_unwrapped) => val.set_blob(&data_unwrapped),
ParamValue::Empty => val.set_empty(),
}
true
@ -135,7 +138,7 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
if !param_desc.writable {
return false;
};
let name_string = String::from_utf16_lossy(param_desc.name);
let name_utf8 = name_string.as_str().trim_matches(char::from(0));
self.add_in.set_parameter(name_utf8, val)
@ -146,7 +149,7 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
let Some(param_desc) = param_desc_binding.get(num) else {
return false
};
param_desc.readable
param_desc.readable
}
fn is_prop_writable(&self, num: usize) -> bool {
@ -157,23 +160,25 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
param_desc.writable
}
fn get_n_methods(&self) -> usize{
fn get_n_methods(&self) -> usize {
self.add_in.list_functions().len()
}
fn find_method(&self, name: &[u16]) -> Option<usize>{
self.add_in.list_functions().iter().position(|x| x.name == name)
fn find_method(&self, name: &[u16]) -> Option<usize> {
self.add_in
.list_functions()
.iter()
.position(|x| x.names.contains(&name))
}
fn get_method_name(&self, num: usize, alias: usize) -> Option<&'static [u16]>{
fn get_method_name(&self, num: usize, alias: usize) -> Option<&'static [u16]> {
self.add_in
.list_functions()
.get(num)
.map(|x| x.name)
.or_else(|| self.add_in.list_functions().get(alias).map(|x| x.name))
.map(|x| x.names[0])
}
fn get_n_params(&self, num: usize) -> usize{
fn get_n_params(&self, num: usize) -> usize {
let binding = self.add_in.list_functions();
let Some(func_desc) = binding.get(num) else {
return 0
@ -186,23 +191,23 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
method_num: usize,
param_num: usize,
value: ReturnValue,
) -> bool{
) -> bool {
let func_desc_binding = self.add_in.list_functions();
let Some(func_desc) = func_desc_binding.get(method_num) else {
return false
};
let Some(default_value_option) = func_desc.default_values.get(param_num) else {
return false
};
};
let Some(default_value) = default_value_option else {
return false
};
match default_value {
ParamValue::Bool(data) => value.set_bool(data.clone()),
ParamValue::I32(data) => value.set_i32(data.clone()),
ParamValue::F64(data) => value.set_f64(data.clone()),
ParamValue::Date(data) => value.set_date(data.clone()),
ParamValue::Bool(data) => value.set_bool(*data),
ParamValue::I32(data) => value.set_i32(*data),
ParamValue::F64(data) => value.set_f64(*data),
ParamValue::Date(data) => value.set_date(*data),
ParamValue::Str(data) => value.set_str(data),
ParamValue::Blob(data) => value.set_blob(data),
ParamValue::Empty => value.set_empty(),
@ -210,7 +215,7 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
true
}
fn has_ret_val(&self, method_num: usize) -> bool{
fn has_ret_val(&self, method_num: usize) -> bool {
let func_desc_binding = self.add_in.list_functions();
let Some(func_desc) = func_desc_binding.get(method_num) else {
return false
@ -218,15 +223,18 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
func_desc.returns_val
}
fn call_as_proc(&mut self, method_num: usize, params: &[ParamValue]) -> bool{
fn call_as_proc(&mut self, method_num: usize, params: &[ParamValue]) -> bool {
let func_desc_binding = self.add_in.list_functions();
let Some(func_desc) = func_desc_binding.get(method_num) else {
return false
};
let name_string = String::from_utf16_lossy(func_desc.name);
let name_string = String::from_utf16_lossy(func_desc.names[0]);
let name_utf8 = name_string.as_str().trim_matches(char::from(0));
let _result = self.add_in.call_function(name_utf8, params);
let call_result = match self.add_in.call_function(name_utf8, params) {
Ok(r) => r,
Err(err) => return false,
};
true
}
@ -234,33 +242,36 @@ impl<T: AddIn> AddInWrapper for AddInContainer<T>{
&mut self,
method_num: usize,
params: &[ParamValue],
val: ReturnValue
) -> bool{
val: ReturnValue,
) -> bool {
let func_desc_binding = self.add_in.list_functions();
let Some(func_desc) = func_desc_binding.get(method_num) else {
return false
};
if !func_desc.returns_val {
return false
return false;
}
let name_string = String::from_utf16_lossy(func_desc.name);
let name_string = String::from_utf16_lossy(func_desc.names[0]);
let name_utf8 = name_string.as_str().trim_matches(char::from(0));
let Some(result) = self.add_in.call_function(name_utf8, params) else {return false};
match result {
let call_result = match self.add_in.call_function(name_utf8, params) {
Ok(r) => r,
Err(err) => return false,
};
let Some(return_value) = call_result else {return false};
match return_value {
ParamValue::Bool(data) => val.set_bool(data),
ParamValue::I32(data) => val.set_i32(data),
ParamValue::F64(data) => val.set_f64(data),
ParamValue::Date(data) => val.set_date(data),
ParamValue::Str(data) => val.set_str(data),
ParamValue::Blob(data) => val.set_blob(data),
ParamValue::Str(data) => val.set_str(&data),
ParamValue::Blob(data) => val.set_blob(&data),
ParamValue::Empty => val.set_empty(),
}
}
true
}
fn set_locale(&mut self, loc: &[u16]){
}
fn set_user_interface_language_code(&mut self, lang: &[u16]){}
fn set_locale(&mut self, _loc: &[u16]) {}
fn set_user_interface_language_code(&mut self, _lang: &[u16]) {}
}
pub trait AddInWrapper {
@ -291,7 +302,12 @@ pub trait AddInWrapper {
) -> bool;
fn has_ret_val(&self, method_num: usize) -> bool;
fn call_as_proc(&mut self, method_num: usize, params: &[ParamValue]) -> bool;
fn call_as_func(&mut self, method_num: usize, params: &[ParamValue], val: ReturnValue) -> bool;
fn call_as_func(
&mut self,
method_num: usize,
params: &[ParamValue],
val: ReturnValue,
) -> bool;
fn set_locale(&mut self, loc: &[u16]);
fn set_user_interface_language_code(&mut self, lang: &[u16]);
}

View File

@ -1,15 +1,19 @@
use std::ffi::{c_long, c_ushort};
use utf16_lit::utf16_null;
use super::types::TVariant;
use super::{types::TVariant, utils::os_string};
#[repr(C)]
struct ConnectionVTable {
dtor: usize,
#[cfg(target_family = "unix")]
dtor2: usize,
add_error:
unsafe extern "system" fn(&Connection, c_ushort, *const u16, *const u16, c_long) -> bool,
add_error: unsafe extern "system" fn(
&Connection,
c_ushort,
*const u16,
*const u16,
c_long,
) -> bool,
read: unsafe extern "system" fn(
&Connection,
*mut u16,
@ -21,7 +25,8 @@ struct ConnectionVTable {
register_profile_as: unsafe extern "system" fn(&Connection, *mut u16) -> bool,
set_event_buffer_depth: unsafe extern "system" fn(&Connection, c_long) -> bool,
get_event_buffer_depth: unsafe extern "system" fn(&Connection) -> c_long,
external_event: unsafe extern "system" fn(&Connection, *mut u16, *mut u16, *mut u16) -> bool,
external_event:
unsafe extern "system" fn(&Connection, *mut u16, *mut u16, *mut u16) -> bool,
clean_event_buffer: unsafe extern "system" fn(&Connection),
set_status_line: unsafe extern "system" fn(&Connection, *mut u16) -> bool,
reset_status_line: unsafe extern "system" fn(&Connection),
@ -46,9 +51,9 @@ impl Connection {
pub fn external_event(&self, caller: &str, name: &str, data: &str) -> bool {
unsafe {
let caller_ptr = caller.encode_utf16().collect::<Vec<u16>>().as_mut_ptr();
let name_ptr = name.encode_utf16().collect::<Vec<u16>>().as_mut_ptr();
let data_ptr = data.encode_utf16().collect::<Vec<u16>>().as_mut_ptr();
let caller_ptr = os_string(caller).as_mut_ptr();
let name_ptr = os_string(name).as_mut_ptr();
let data_ptr = os_string(data).as_mut_ptr();
(self.vptr1.external_event)(self, caller_ptr, name_ptr, data_ptr)
}
}

View File

@ -1,7 +1,7 @@
use std::ffi::c_long;
use super::{connection::Connection, memory_manager::MemoryManager, This};
use crate::add_in::{AddIn, AddInWrapper};
use crate::add_in::AddInWrapper;
#[repr(C)]
pub struct InitDoneBaseVTable<T: AddInWrapper> {

View File

@ -232,7 +232,7 @@ unsafe extern "system" fn call_as_proc<T: AddInWrapper>(
let component = this.get_component();
let param_values = from_raw_parts(params, size_array as usize)
.iter()
.map(|x| ParamValue::from(x))
.map(ParamValue::from)
.collect::<Vec<ParamValue>>();
component
@ -261,7 +261,7 @@ unsafe extern "system" fn call_as_func<T: AddInWrapper>(
let param_values = from_raw_parts(params, size_array as usize)
.iter()
.map(|x| ParamValue::from(x))
.map(ParamValue::from)
.collect::<Vec<ParamValue>>();
component

View File

@ -20,9 +20,9 @@ pub mod utils;
#[repr(C)]
#[derive(Debug)]
pub enum AttachType {
CanAttachNotIsolated = 1,
CanAttachIsolated,
CanAttachAny,
NotIsolated = 1,
Isolated,
Any,
}
#[repr(C)]

View File

@ -12,3 +12,22 @@ pub unsafe fn get_str<'a>(s: *const u16) -> &'a [u16] {
let len = strlen(s);
from_raw_parts(s, len)
}
#[cfg(target_family = "unix")]
pub fn os_string(s: &str) -> Vec<u16> {
s.encode_utf16().collect()
}
#[cfg(target_family = "windows")]
pub fn os_string(s: &str) -> Vec<u16> {
let os_str = std::ffi::OsStr::new(s);
std::os::windows::prelude::OsStrExt::encode_wide(os_str)
.chain(Some(0).into_iter())
.collect()
}
pub fn from_os_string(s: &[u16]) -> String {
String::from_utf16_lossy(s)
.trim_end_matches(char::from(0))
.to_string()
}

View File

@ -1,6 +1,16 @@
pub mod add_in;
mod ffi;
use crate::ffi::create_component;
use add_in::{
AddIn, AddInContainer, ComponentFuncDescription, ComponentPropDescription,
};
use ffi::{
connection::Connection, destroy_component, types::ParamValue,
utils::from_os_string, AttachType,
};
use color_eyre::eyre::{eyre, Result};
use std::{
ffi::{c_int, c_long, c_void},
sync::{
@ -10,19 +20,19 @@ use std::{
thread,
time::Duration,
};
use add_in::{AddIn, AddInContainer, ComponentFuncDescription, ComponentPropDescription};
use ffi::{connection::Connection, destroy_component, types::ParamValue, AttachType};
use utf16_lit::utf16_null;
use crate::ffi::create_component;
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
struct AddInDescription {
name: &'static [u16],
connection: Arc<Option<&'static Connection>>,
functions: Vec<(
ComponentFuncDescription,
fn(&mut Self, &[ParamValue]) -> Result<Option<ParamValue>>,
)>,
some_prop_container: i32,
}
@ -31,21 +41,66 @@ impl AddInDescription {
Self {
name: &utf16_null!("MyAddIn"),
connection: Arc::new(None),
functions: vec![
(
ComponentFuncDescription::new::<0>(
vec![
&utf16_null!("Итерировать"),
&utf16_null!("Iterate"),
],
false,
&[],
),
Self::iterate,
),
(
ComponentFuncDescription::new::<1>(
vec![&utf16_null!("Таймер"), &utf16_null!("Timer")],
true,
&[Some(ParamValue::I32(1000))],
),
Self::timer,
),
],
some_prop_container: 0,
}
}
fn iterate(&mut self) -> Result<(), &str> {
fn iterate(
&mut self,
_params: &[ParamValue],
) -> Result<Option<ParamValue>> {
if self.some_prop_container >= 105 {
return Err("container is too big");
return Err(eyre!("Prop is too big"));
}
self.some_prop_container += 1;
Ok(())
Ok(None)
}
fn timer(&mut self, params: &[ParamValue]) -> Result<Option<ParamValue>> {
let sleep_duration_ms = match params.get(0) {
Some(ParamValue::I32(val)) => *val,
_ => return Err(eyre!("Invalid parameter")),
};
let connection = self.connection.clone();
let name = from_os_string(self.name);
thread::spawn(move || {
thread::sleep(Duration::from_secs(1));
if let Some(connection) = &*connection {
connection.external_event(&name, "TimerEnd", "OK");
}
});
Ok(Some(ParamValue::I32(sleep_duration_ms)))
}
}
impl AddIn for AddInDescription {
fn init(&mut self, interface: &'static Connection) -> bool {
interface.set_event_buffer_depth(10);
self.connection = Arc::new(Some(interface));
self.some_prop_container = 100;
true
@ -55,33 +110,18 @@ impl AddIn for AddInDescription {
self.name
}
fn call_function(&mut self, name: &str, params: &[ParamValue]) -> Option<ParamValue> {
match name.trim_end() {
"iterate" => {
let Err(_e) = self.iterate() else { return None};
None
}
"err" => {
let Some(con) = self.connection.as_deref() else { return None };
con.add_error(13, "err", "error that was bound to happen");
None
}
"timer" => {
let ParamValue::I32(duration_ms) = params[0] else { return None };
let con_clone = self.connection.clone();
thread::spawn(move || {
let Some(con) = con_clone.as_deref() else { return };
if duration_ms <= 0 {
return;
}
thread::sleep(Duration::from_millis(duration_ms as u64));
con.external_event("timer", "timer", "timer");
});
fn call_function(
&mut self,
name: &str,
params: &[ParamValue],
) -> Result<Option<ParamValue>> {
let func = self
.functions
.iter()
.find(|(desc, _)| desc.str_names().iter().any(|n| n == name));
Some(ParamValue::I32(duration_ms))
}
_ => None,
}
let Some(func) = func.map(|(_, callback)| callback) else { return Err(eyre!("No function with such name")) };
func(self, params)
}
fn get_parameter(&self, name: &str) -> Option<ParamValue> {
@ -102,16 +142,8 @@ impl AddIn for AddInDescription {
}
}
fn list_functions(&self) -> Vec<ComponentFuncDescription> {
vec![
ComponentFuncDescription::new::<0>(&utf16_null!("iterate"), false, &[]),
ComponentFuncDescription::new::<0>(&utf16_null!("err"), false, &[]),
ComponentFuncDescription::new::<1>(
&utf16_null!("timer"),
true,
&[Some(ParamValue::I32(0))],
),
]
fn list_functions(&self) -> Vec<&ComponentFuncDescription> {
self.functions.iter().map(|(desc, _)| desc).collect()
}
fn list_parameters(&self) -> Vec<ComponentPropDescription> {
@ -125,10 +157,14 @@ impl AddIn for AddInDescription {
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn GetClassObject(name: *const u16, component: *mut *mut c_void) -> c_long {
pub unsafe extern "C" fn GetClassObject(
name: *const u16,
component: *mut *mut c_void,
) -> c_long {
match *name as u8 {
b'1' => {
let my_add_in_container = AddInContainer::new(AddInDescription::new());
let my_add_in_container =
AddInContainer::new(AddInDescription::new());
create_component(component, my_add_in_container)
}
_ => 0,
@ -158,5 +194,5 @@ pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn GetAttachType() -> AttachType {
AttachType::CanAttachAny
AttachType::Any
}