Merge branch 'dev'
This commit is contained in:
commit
28951823a8
@ -47,8 +47,8 @@ unsafe extern "system" fn done<T: AddInWrapper>(this: &mut This<0, T>) {
|
||||
component.addin.done()
|
||||
}
|
||||
|
||||
impl<T: AddInWrapper> InitDoneBaseVTable<T> {
|
||||
pub fn new() -> Self {
|
||||
impl<T: AddInWrapper> Default for InitDoneBaseVTable<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dtor: 0,
|
||||
#[cfg(target_family = "unix")]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{
|
||||
ffi::c_long,
|
||||
ptr::{self},
|
||||
slice::from_raw_parts,
|
||||
slice::from_raw_parts_mut,
|
||||
};
|
||||
|
||||
use crate::interface::AddInWrapper;
|
||||
@ -56,14 +56,14 @@ pub struct LanguageExtenderBaseVTable<T: AddInWrapper> {
|
||||
call_as_proc: unsafe extern "system" fn(
|
||||
&mut This<1, T>,
|
||||
c_long,
|
||||
*const TVariant,
|
||||
*mut TVariant,
|
||||
c_long,
|
||||
) -> bool,
|
||||
call_as_func: unsafe extern "system" fn(
|
||||
&mut This<1, T>,
|
||||
c_long,
|
||||
&mut TVariant,
|
||||
*const TVariant,
|
||||
*mut TVariant,
|
||||
c_long,
|
||||
) -> bool,
|
||||
}
|
||||
@ -79,7 +79,7 @@ unsafe extern "system" fn register_extension_as<T: AddInWrapper>(
|
||||
|
||||
let extension_name = component.addin.register_extension_as();
|
||||
|
||||
let Some(ptr) = allocator.alloc_str(extension_name.len()) else {
|
||||
let Ok(ptr) = allocator.alloc_str(extension_name.len()) else {
|
||||
return false;
|
||||
};
|
||||
ptr::copy_nonoverlapping(
|
||||
@ -123,7 +123,7 @@ unsafe extern "system" fn get_prop_name<T: AddInWrapper>(
|
||||
let Some(prop_name) = component.addin.get_prop_name(num as usize, alias as usize) else {
|
||||
return ptr::null();
|
||||
};
|
||||
let Some(ptr) = allocator.alloc_str(prop_name.len()) else {
|
||||
let Ok(ptr) = allocator.alloc_str(prop_name.len()) else {
|
||||
return ptr::null();
|
||||
};
|
||||
ptr::copy_nonoverlapping(prop_name.as_ptr(), ptr.as_ptr(), prop_name.len());
|
||||
@ -207,7 +207,7 @@ unsafe extern "system" fn get_method_name<T: AddInWrapper>(
|
||||
let Some(method_name) = component.addin.get_method_name(num as usize, alias as usize) else {
|
||||
return ptr::null();
|
||||
};
|
||||
let Some(ptr) = allocator.alloc_str(method_name.len()) else {
|
||||
let Ok(ptr) = allocator.alloc_str(method_name.len()) else {
|
||||
return ptr::null();
|
||||
};
|
||||
|
||||
@ -264,53 +264,116 @@ unsafe extern "system" fn has_ret_val<T: AddInWrapper>(
|
||||
unsafe extern "system" fn call_as_proc<T: AddInWrapper>(
|
||||
this: &mut This<1, T>,
|
||||
method_num: c_long,
|
||||
params: *const TVariant,
|
||||
params: *mut TVariant,
|
||||
size_array: c_long,
|
||||
) -> bool {
|
||||
let component = this.get_component();
|
||||
let param_values = from_raw_parts(params, size_array as usize)
|
||||
let Some(mem_mngr) = component.memory else { return false; };
|
||||
|
||||
let parameters_raw = from_raw_parts_mut(params, size_array as usize);
|
||||
let mut parameters_values = parameters_raw
|
||||
.iter()
|
||||
.map(ParamValue::from)
|
||||
.collect::<Vec<ParamValue>>();
|
||||
let parameters_values_buf = parameters_values.clone();
|
||||
|
||||
component
|
||||
let call_result = component
|
||||
.addin
|
||||
.call_as_proc(method_num as usize, param_values.as_slice())
|
||||
.call_as_proc(method_num as usize, &mut parameters_values);
|
||||
if !call_result {
|
||||
return false;
|
||||
}
|
||||
if parameters_values.len() != parameters_values_buf.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
for i in 0..parameters_values.len() {
|
||||
let raw_param = &mut parameters_raw[i];
|
||||
if parameters_values_buf[i] == parameters_values[i] {
|
||||
continue;
|
||||
}
|
||||
match ¶meters_values[i] {
|
||||
ParamValue::Str(v) => {
|
||||
let Ok(_) = raw_param.update_to_str(mem_mngr, v) else { return false; };
|
||||
}
|
||||
ParamValue::Blob(v) => {
|
||||
let Ok(_) = raw_param.update_to_blob(mem_mngr, v) else { return false; };
|
||||
}
|
||||
ParamValue::Bool(v) => raw_param.update_to_bool(*v),
|
||||
ParamValue::I32(v) => raw_param.update_to_i32(*v),
|
||||
ParamValue::F64(v) => raw_param.update_to_f64(*v),
|
||||
ParamValue::Date(v) => raw_param.update_to_date(*v),
|
||||
ParamValue::Empty => {}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
unsafe extern "system" fn call_as_func<T: AddInWrapper>(
|
||||
this: &mut This<1, T>,
|
||||
method_num: c_long,
|
||||
ret_value: &mut TVariant,
|
||||
params: *const TVariant,
|
||||
params: *mut TVariant,
|
||||
size_array: c_long,
|
||||
) -> bool {
|
||||
let component = this.get_component();
|
||||
let Some(mem) = component.memory else {
|
||||
return false;
|
||||
};
|
||||
let Some(mem_mngr) = component.memory else { return false; };
|
||||
|
||||
let mut result = true;
|
||||
let return_value = ReturnValue {
|
||||
mem,
|
||||
mem: mem_mngr,
|
||||
variant: ret_value,
|
||||
result: &mut result,
|
||||
};
|
||||
|
||||
let param_values = from_raw_parts(params, size_array as usize)
|
||||
let parameters_raw = from_raw_parts_mut(params, size_array as usize);
|
||||
let mut parameters_values = parameters_raw
|
||||
.iter()
|
||||
.map(ParamValue::from)
|
||||
.collect::<Vec<ParamValue>>();
|
||||
let parameters_values_buf = parameters_values.clone();
|
||||
|
||||
component.addin.call_as_func(
|
||||
let call_result = component.addin.call_as_func(
|
||||
method_num as usize,
|
||||
param_values.as_slice(),
|
||||
&mut parameters_values,
|
||||
return_value,
|
||||
) && result
|
||||
);
|
||||
if !call_result {
|
||||
return false;
|
||||
}
|
||||
if !result {
|
||||
return false;
|
||||
}
|
||||
if parameters_values.len() != parameters_values_buf.len() {
|
||||
return false;
|
||||
}
|
||||
|
||||
for i in 0..parameters_values.len() {
|
||||
let raw_param = &mut parameters_raw[i];
|
||||
if parameters_values_buf[i] == parameters_values[i] {
|
||||
continue;
|
||||
}
|
||||
match ¶meters_values[i] {
|
||||
ParamValue::Str(v) => {
|
||||
let Ok(_) = raw_param.update_to_str(mem_mngr, v) else { return false; };
|
||||
}
|
||||
ParamValue::Blob(v) => {
|
||||
let Ok(_) = raw_param.update_to_blob(mem_mngr, v) else { return false; };
|
||||
}
|
||||
ParamValue::Bool(v) => raw_param.update_to_bool(*v),
|
||||
ParamValue::I32(v) => raw_param.update_to_i32(*v),
|
||||
ParamValue::F64(v) => raw_param.update_to_f64(*v),
|
||||
ParamValue::Date(v) => raw_param.update_to_date(*v),
|
||||
ParamValue::Empty => {}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
impl<T: AddInWrapper> LanguageExtenderBaseVTable<T> {
|
||||
pub fn new() -> Self {
|
||||
impl<T: AddInWrapper> Default for LanguageExtenderBaseVTable<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dtor: 0,
|
||||
#[cfg(target_family = "unix")]
|
||||
|
@ -25,20 +25,28 @@ pub struct MemoryManager {
|
||||
vptr: &'static MemoryManagerVTable,
|
||||
}
|
||||
|
||||
pub struct AllocationError;
|
||||
|
||||
impl MemoryManager {
|
||||
/// Safe wrapper around `alloc_memory` method of the MemoryManager object
|
||||
/// to allocate memory for byte array
|
||||
/// # Arguments
|
||||
/// * `size` - size of the memory block to allocate
|
||||
/// # Returns
|
||||
/// `Option<NonNull<u8>>` - pointer to the allocated memory block
|
||||
pub fn alloc_blob(&self, size: usize) -> Option<NonNull<u8>> {
|
||||
/// `Result<NonNull<u8>, AllocationError>` - pointer to the allocated memory block
|
||||
pub fn alloc_blob(
|
||||
&self,
|
||||
size: usize,
|
||||
) -> Result<NonNull<u8>, AllocationError> {
|
||||
let mut ptr = ptr::null_mut::<c_void>();
|
||||
unsafe {
|
||||
if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong) {
|
||||
NonNull::new(ptr as *mut u8)
|
||||
if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong * 2) {
|
||||
match NonNull::new(ptr as *mut u8) {
|
||||
Some(ptr) => Ok(ptr),
|
||||
None => Err(AllocationError),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
Err(AllocationError)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,15 +56,27 @@ impl MemoryManager {
|
||||
/// # Arguments
|
||||
/// * `size` - size of the memory block to allocate
|
||||
/// # Returns
|
||||
/// `Option<NonNull<u16>>` - pointer to the allocated memory block
|
||||
pub fn alloc_str(&self, size: usize) -> Option<NonNull<u16>> {
|
||||
/// `Result<NonNull<u16>, AllocationError>` - pointer to the allocated memory block
|
||||
pub fn alloc_str(
|
||||
&self,
|
||||
size: usize,
|
||||
) -> Result<NonNull<u16>, AllocationError> {
|
||||
let mut ptr = ptr::null_mut::<c_void>();
|
||||
unsafe {
|
||||
if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong * 2) {
|
||||
NonNull::new(ptr as *mut u16)
|
||||
match NonNull::new(ptr as *mut u16) {
|
||||
Some(ptr) => Ok(ptr),
|
||||
None => Err(AllocationError),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
Err(AllocationError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn free_memory(&self, ptr: &mut *mut c_void) {
|
||||
unsafe {
|
||||
(self.vptr.free_memory)(self, ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,8 +110,8 @@ pub unsafe fn create_component<T: AddInWrapper>(
|
||||
component: *mut *mut c_void,
|
||||
addin: T,
|
||||
) -> c_long {
|
||||
let vptr1 = Box::new(InitDoneBaseVTable::new());
|
||||
let vptr2 = Box::new(LanguageExtenderBaseVTable::new());
|
||||
let vptr1 = Box::<InitDoneBaseVTable<T>>::default();
|
||||
let vptr2 = Box::<LanguageExtenderBaseVTable<T>>::default();
|
||||
let vptr3 = Box::new(LocaleBaseVTable {
|
||||
dtor: 0,
|
||||
#[cfg(target_family = "unix")]
|
||||
|
@ -1,7 +1,11 @@
|
||||
use chrono::{Datelike, Offset, Timelike};
|
||||
use std::{ffi::c_int, ptr, slice::from_raw_parts};
|
||||
use std::{
|
||||
ffi::{c_int, c_void},
|
||||
ptr,
|
||||
slice::{from_raw_parts, from_raw_parts_mut},
|
||||
};
|
||||
|
||||
use super::memory_manager::MemoryManager;
|
||||
use super::memory_manager::{AllocationError, MemoryManager};
|
||||
|
||||
/// Type representing 1C date and time values
|
||||
/// # Fields
|
||||
@ -121,6 +125,38 @@ impl From<Tm> for chrono::DateTime<chrono::FixedOffset> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
impl PartialEq for Tm {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.sec == other.sec
|
||||
&& self.min == other.min
|
||||
&& self.hour == other.hour
|
||||
&& self.mday == other.mday
|
||||
&& self.mon == other.mon
|
||||
&& self.year == other.year
|
||||
&& self.wday == other.wday
|
||||
&& self.yday == other.yday
|
||||
&& self.isdst == other.isdst
|
||||
&& self.gmtoff == other.gmtoff
|
||||
&& self.zone == other.zone
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_family = "windows")]
|
||||
impl PartialEq for Tm {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.sec == other.sec
|
||||
&& self.min == other.min
|
||||
&& self.hour == other.hour
|
||||
&& self.mday == other.mday
|
||||
&& self.mon == other.mon
|
||||
&& self.year == other.year
|
||||
&& self.wday == other.wday
|
||||
&& self.yday == other.yday
|
||||
&& self.isdst == other.isdst
|
||||
}
|
||||
}
|
||||
|
||||
/// Type representing 1C variant values
|
||||
/// # Fields
|
||||
/// `mem` - pointer to the MemoryManager object
|
||||
@ -165,7 +201,7 @@ impl<'a> ReturnValue<'a> {
|
||||
|
||||
/// Sets the value of the ReturnValue object to UTF-16 `&[u16]`
|
||||
pub fn set_str(self, val: &[u16]) {
|
||||
let Some(ptr) = self.mem.alloc_str(val.len()) else {
|
||||
let Ok(ptr) = self.mem.alloc_str(val.len()) else {
|
||||
*self.result = false;
|
||||
return;
|
||||
};
|
||||
@ -181,7 +217,7 @@ impl<'a> ReturnValue<'a> {
|
||||
|
||||
/// Sets the value of the ReturnValue object to blob `&[u8]`
|
||||
pub fn set_blob(self, val: &[u8]) {
|
||||
let Some(ptr) = self.mem.alloc_blob(val.len()) else {
|
||||
let Ok(ptr) = self.mem.alloc_blob(val.len()) else {
|
||||
*self.result = false;
|
||||
return;
|
||||
};
|
||||
@ -197,6 +233,7 @@ impl<'a> ReturnValue<'a> {
|
||||
}
|
||||
|
||||
/// Represents 1C variant values for parameters
|
||||
#[derive(Clone)]
|
||||
pub enum ParamValue {
|
||||
/// Empty value
|
||||
Empty,
|
||||
@ -214,6 +251,21 @@ pub enum ParamValue {
|
||||
Blob(Vec<u8>),
|
||||
}
|
||||
|
||||
impl<'a> PartialEq for ParamValue {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::Empty, Self::Empty) => true,
|
||||
(Self::Bool(a), Self::Bool(b)) => a == b,
|
||||
(Self::I32(a), Self::I32(b)) => a == b,
|
||||
(Self::F64(a), Self::F64(b)) => a == b,
|
||||
(Self::Date(a), Self::Date(b)) => a == b,
|
||||
(Self::Str(a), Self::Str(b)) => a == b,
|
||||
(Self::Blob(a), Self::Blob(b)) => a == b,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a TVariant> for ParamValue {
|
||||
fn from(param: &'a TVariant) -> ParamValue {
|
||||
unsafe {
|
||||
@ -245,7 +297,7 @@ impl<'a> From<&'a TVariant> for ParamValue {
|
||||
|
||||
#[repr(u16)]
|
||||
#[allow(dead_code)]
|
||||
enum VariantType {
|
||||
pub enum VariantType {
|
||||
Empty = 0,
|
||||
Null,
|
||||
Int16, //int16_t
|
||||
@ -281,7 +333,7 @@ enum VariantType {
|
||||
/// * `len` - length of the data
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct DataStr {
|
||||
pub struct DataStr {
|
||||
pub ptr: *mut u16,
|
||||
pub len: u32,
|
||||
}
|
||||
@ -292,7 +344,7 @@ struct DataStr {
|
||||
/// * `len` - length of the data
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct DataBlob {
|
||||
pub struct DataBlob {
|
||||
pub ptr: *mut u8,
|
||||
pub len: u32,
|
||||
}
|
||||
@ -306,7 +358,7 @@ struct DataBlob {
|
||||
/// * `data_str` - UTF-16 string value
|
||||
/// * `data_blob` - blob value
|
||||
#[repr(C)]
|
||||
union VariantValue {
|
||||
pub union VariantValue {
|
||||
pub bool: bool,
|
||||
pub i32: i32,
|
||||
pub f64: f64,
|
||||
@ -322,3 +374,68 @@ pub struct TVariant {
|
||||
elements: u32, //Dimension for an one-dimensional array in pvarVal
|
||||
vt: VariantType,
|
||||
}
|
||||
|
||||
impl TVariant {
|
||||
/// # Safety
|
||||
/// This function is unsafe because it manipulates pointers, provided by the 1C platform.
|
||||
/// Function is safe as long as 1C platform provides valid pointers.
|
||||
pub unsafe fn update_to_str(
|
||||
&mut self,
|
||||
mem_mngr: &MemoryManager,
|
||||
v: &[u16],
|
||||
) -> Result<u32, AllocationError> {
|
||||
let mut old_pointer = self.value.data_str.ptr;
|
||||
|
||||
let ptr = mem_mngr.alloc_str(v.len())?;
|
||||
ptr::copy_nonoverlapping(v.as_ptr(), ptr.as_ptr(), v.len());
|
||||
|
||||
self.value.data_str.ptr = ptr.as_ptr();
|
||||
self.value.data_str.len = v.len() as u32;
|
||||
|
||||
mem_mngr.free_memory(&mut old_pointer.cast::<c_void>());
|
||||
|
||||
self.vt = VariantType::WStr;
|
||||
|
||||
Ok(self.value.data_str.len)
|
||||
}
|
||||
|
||||
pub unsafe fn update_to_blob(
|
||||
&mut self,
|
||||
mem_mngr: &MemoryManager,
|
||||
v: &[u8],
|
||||
) -> Result<u32, AllocationError> {
|
||||
let mut old_pointer = self.value.data_blob.ptr;
|
||||
|
||||
let ptr = mem_mngr.alloc_blob(v.len())?;
|
||||
ptr::copy_nonoverlapping(v.as_ptr(), ptr.as_ptr(), v.len());
|
||||
|
||||
self.value.data_blob.ptr = ptr.as_ptr();
|
||||
self.value.data_blob.len = v.len() as u32;
|
||||
|
||||
mem_mngr.free_memory(&mut old_pointer.cast::<c_void>());
|
||||
|
||||
self.vt = VariantType::Blob;
|
||||
|
||||
Ok(self.value.data_blob.len)
|
||||
}
|
||||
|
||||
pub fn update_to_bool(&mut self, v: bool) {
|
||||
self.value.bool = v;
|
||||
self.vt = VariantType::Bool;
|
||||
}
|
||||
|
||||
pub fn update_to_i32(&mut self, v: i32) {
|
||||
self.value.i32 = v;
|
||||
self.vt = VariantType::Int32;
|
||||
}
|
||||
|
||||
pub fn update_to_f64(&mut self, v: f64) {
|
||||
self.value.f64 = v;
|
||||
self.vt = VariantType::Double;
|
||||
}
|
||||
|
||||
pub fn update_to_date(&mut self, v: Tm) {
|
||||
self.value.tm = v;
|
||||
self.vt = VariantType::Time;
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,27 @@ pub fn os_string_nil(s: &str) -> Vec<u16> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Helper function to convert Rust string to UTF-16 string
|
||||
/// # Arguments
|
||||
/// * `s` - Rust string
|
||||
/// # Returns
|
||||
/// `Vec<u16>` - UTF-16 string without null terminator
|
||||
#[cfg(target_family = "unix")]
|
||||
pub fn os_string(s: &str) -> Vec<u16> {
|
||||
s.encode_utf16().collect()
|
||||
}
|
||||
|
||||
/// Helper function to convert Rust string to UTF-16 string
|
||||
/// # Arguments
|
||||
/// * `s` - Rust string
|
||||
/// # Returns
|
||||
/// `Vec<u16>` - UTF-16 string with null terminator
|
||||
#[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).collect()
|
||||
}
|
||||
|
||||
/// Helper function to convert UTF-16 string to Rust string
|
||||
/// # Arguments
|
||||
/// * `s` - UTF-16 string
|
||||
|
@ -160,7 +160,7 @@ pub trait AddInWrapper {
|
||||
fn call_as_proc(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &[ParamValue],
|
||||
params: &mut [ParamValue],
|
||||
) -> bool;
|
||||
|
||||
/// Equivalent to `CallAsFunc` from Native API interface and is used to call method
|
||||
@ -174,7 +174,7 @@ pub trait AddInWrapper {
|
||||
fn call_as_func(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &[ParamValue],
|
||||
params: &mut [ParamValue],
|
||||
val: ReturnValue,
|
||||
) -> bool;
|
||||
|
||||
|
Reference in New Issue
Block a user