#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#[macro_use]
extern crate lazy_static;
extern crate dlopen;
#[macro_use]
extern crate dlopen_derive;
use dlopen::wrapper::{Container, WrapperApi};
use std::{
ffi::{c_void, CString},
fmt::Debug,
io::Write,
marker::PhantomData,
os::raw::{c_char, c_int},
ptr::{null, null_mut},
sync::{
mpsc::{channel, Receiver, RecvError, Sender},
Mutex,
},
usize,
};
mod data;
mod test;
use data::*;
type Handle = *const c_void;
#[derive(Debug, Default)]
#[repr(C, packed(2))]
pub struct FixedPoint32 {
whole: i16,
frac: u16,
}
pub struct Frame {
left: FixedPoint32,
top: FixedPoint32,
right: FixedPoint32,
bottom: FixedPoint32,
}
pub struct DecodeFunction {
start_in: FixedPoint32,
break_in: FixedPoint32,
end_in: FixedPoint32,
start_out: FixedPoint32,
break_out: FixedPoint32,
end_out: FixedPoint32,
gamma: FixedPoint32,
sample_count: FixedPoint32,
}
pub struct TransformStage {
decode: [DecodeFunction; 3],
mix: [[FixedPoint32; 3]; 3],
}
pub struct Array {
item_type: u16,
num_items: u32,
item_list: [u8; 1],
}
pub struct AudioInfo {
name: Str255,
reserved: u32,
}
pub struct CallBack {
proc: *mut c_void,
ref_con: u32,
message: i16,
}
impl CallBack {
pub fn new() -> CallBack {
CallBack {
proc: null_mut(),
ref_con: 0,
message: 0,
}
}
}
pub struct CallBack2 {
proc: *mut c_void,
ref_con: *mut usize,
message: i16,
}
#[derive(Debug)]
pub struct Capability {
cap: u16,
con_type: TWON,
h_container: *mut c_void,
}
impl Capability {
fn default() -> Capability {
Capability {
cap: 0,
con_type: TWON::ONEVALUE,
h_container: null_mut(),
}
}
}
pub struct CiePoint {
x: FixedPoint32,
y: FixedPoint32,
z: FixedPoint32,
}
pub struct CieColor {
color_space: u16,
low_endian: i16,
device_dependent: i16,
version_number: i32,
stage_abc: TransformStage,
stage_lmn: TransformStage,
white_point: CiePoint,
black_point: CiePoint,
white_paper: CiePoint,
black_ink: CiePoint,
samples: [FixedPoint32; 1],
}
pub struct CustomDSData {
info_length: u32,
h_data: *mut c_void,
}
pub struct DeviceEvent {
event: u32,
device_name: Str255,
battery_minutes: u32,
battery_percentage: i16,
power_supply: i32,
x_resolution: FixedPoint32,
y_resolution: FixedPoint32,
flash_used2: u32,
automatic_capture: u32,
time_before_first_capture: u32,
time_between_captures: u32,
}
pub struct Element8 {
index: u8,
channel1: u8,
channel2: u8,
channel3: u8,
}
pub struct Enumeration {
item_type: u16,
num_items: u32,
current_index: u32,
default_index: u32,
item_list: [u8; 1],
}
pub struct Event {
p_event: *const c_void,
message: u16,
}
pub struct Info {
id: u16,
item_type: u16,
num_items: u16,
return_code: u16,
cond_code: u16,
item: *mut usize,
}
pub struct ExtImageInfo {
num_infos: u32,
info: [Info; 1],
}
pub struct FileSystem {
input_name: Str255,
output_name: Str255,
context: *mut c_void,
recursive: i32,
sub_directories: u16,
file_type: i32,
file_system_type: u32,
size: u32,
create_time_date: Str32,
modified_time_date: Str32,
free_space: u32,
new_image_size: i32,
number_of_files: u32,
number_of_snippets: u32,
device_group_mask: u32,
reserved: [i8; 508],
}
pub struct GrayResponse {
response: [Element8; 1],
}
#[repr(C, packed(2))]
#[derive(Debug, Clone)]
pub struct Version {
major_num: u16,
minor_num: u16,
language: u16, country: u16, info: Str32,
}
impl Default for Version {
fn default() -> Self {
Version {
major_num: 1,
minor_num: 0,
language: TWLG::USA_OR_ENGLISH_USA as _,
country: TWCY::USA as _,
info: Str32::default(),
}
}
}
#[repr(C, packed(2))]
#[derive(Debug, Default, Clone)]
pub struct Identity {
id: u32,
version: Version,
protocol_major: u16,
protocol_minor: u16,
supported_groups: u32,
manufacturer: Str32,
product_family: Str32,
product_name: Str32,
}
#[derive(Debug, Default)]
#[repr(C, packed(2))]
pub struct ImageInfo {
x_resolution: FixedPoint32,
y_resolution: FixedPoint32,
image_width: i32,
image_length: i32,
samples_per_pixel: i16,
bits_per_sample: [i16; 8],
bits_per_pixed: i16,
planar: u16,
pixel_type: i16,
compression: u16,
}
pub struct ImageLayout {
frame: Frame,
document_number: u32,
page_number: u32,
frame_number: u32,
}
pub struct Memory {
flags: u32,
length: u32,
the_mem: *const c_void,
}
pub struct ImageMemxfer {
compression: i16,
bytes_per_row: u32,
columns: u32,
rows: u32,
xoffset: u32,
yoffset: u32,
bytes_written: u32,
memory: Memory,
}
pub struct JpegCompression {
color_space: u16,
sub_sampling: u32,
num_components: u16,
restart_frequency: u16,
quant_map: [u16; 4],
quant_table: [Memory; 4],
huffman_map: [u16; 4],
huffman_dc: [Memory; 2],
huffman_ac: [Memory; 2],
}
pub struct Metrics {
size_of: u32,
image_count: u32,
sheet_count: u32,
}
pub struct OneValue {
item_type: u16,
item: u32,
}
pub struct Palette8 {
num_colors: u16,
palette_type: u16,
colors: [Element8; 256],
}
pub struct PassThru {
p_command: *const c_void,
command_bytes: u32,
direction: i32,
p_data: *const c_void,
data_bytes: u32,
data_bytes_xfered: u32,
}
pub struct PendingTransfers {
count: u16,
eoj: u32,
reserved: u32,
}
pub struct Range {
item_type: u16,
min_value: u32,
max_value: u32,
step_size: u32,
default_value: u32,
current_value: u32,
}
pub struct RgbResponse {
response: [Element8; 1],
}
pub struct SetupFileTransfer {
filename: Str255,
format: u16,
vref_num: i16,
}
pub struct SetupMemoryTransfer {
min_buf_size: u32,
max_buf_size: u32,
preferred: u32,
}
pub struct Status {
condition_code: u16,
data: u16,
reserved: u16,
}
pub struct StatusUtf8 {
status: Status,
size: u32,
utf8_string: *const c_void,
}
pub struct TwainDirect {
size_of: u32,
communication_manager: u16,
send: *const c_void,
send_size: u32,
receive: *const c_void,
receive_size: u32,
}
pub struct UserInterface {
show_ui: u16, modal_ui: u16, h_parent: Handle,
}
impl UserInterface {
pub fn new(show_ui: bool, model_ui: bool) -> UserInterface {
UserInterface {
show_ui: show_ui as _,
modal_ui: model_ui as _,
h_parent: null(),
}
}
}
pub struct SetupFileTransfer2 {
file_name: *const c_void,
file_name_type: u16,
format: u16,
v_ref_num: i16,
part_id: u32,
}
pub struct TwunkIdentity {
identity: Identity,
ds_path: Str255,
}
pub struct TwunkDsEntryParams {
dest_flag: i8,
dest: Identity,
data_group: i32,
data_arg_type: i16,
message: i16,
p_data_size: i32,
}
pub struct TwunkDsEntryReturn {
return_code: u16,
condition_code: u16,
p_data_size: i32,
}
pub struct CapExt {
cap: u16,
properties: u16,
}
pub struct SetupAudioFileTransfer {
file_name: Str255,
format: TWAF, v_ref_num: i16,
}
#[derive(Debug)]
#[repr(C, packed(2))]
pub struct EntryPoint {
size: u32,
pub ds_entry: *const fn(
p_origin: *const Identity,
p_dest: *const Identity,
dg: DG,
dat: DAT,
msg: MSG,
p_data: *const c_void,
) -> u16,
pub mem_allocate: *mut fn(u32) -> Handle,
pub mem_free: *const fn(Handle) -> (),
pub mem_lock: *const fn(Handle) -> *const c_void,
pub mem_unlock: *const fn(Handle) -> (),
}
impl Default for EntryPoint {
fn default() -> Self {
EntryPoint {
size: 44,
ds_entry: null(),
mem_allocate: null_mut(),
mem_free: null(),
mem_lock: null(),
mem_unlock: null(),
}
}
}
impl EntryPoint {
pub fn size(&self) -> u32 {
self.size
}
pub fn allocate(&self, size: u32) -> Handle {
unsafe { (*self.mem_allocate)(size) }
}
}
#[repr(C)]
pub struct FilterDescriptor {
size: u32,
hue_start: u32,
hue_end: u32,
saturation_start: u32,
saturation_end: u32,
value_start: u32,
value_end: u32,
replacement: u32,
}
#[repr(C)]
pub struct Filter {
size: u32,
descriptor_count: u32,
max_descriptor_count: u32,
condition: u32,
h_descriptors: Handle,
}
#[derive(WrapperApi)]
struct Api {
#[dlopen_name = "DSM_Entry"]
dsm_entry: unsafe extern "C" fn(
p_origin: *const Identity,
p_dest: *const Identity,
dg: DG,
dat: DAT,
msg: MSG,
entry_point: *const usize,
) -> TWRC,
}
pub enum State {
None = 1, LOADED = 2, OPEN = 3, DSOPEN = 4, WAITING = 5, READY = 6, TRANSFER = 7, }
#[derive(Clone)]
#[repr(C, packed(2))]
pub struct Str32([u8; 34]);
impl Default for Str32 {
fn default() -> Self {
Str32([0; 34])
}
}
impl std::fmt::Debug for Str32 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_string())
}
}
impl Str32 {
fn new(val: &str) -> Str32 {
let mut a = Self::default();
let t = CString::new(val).unwrap().to_bytes();
let chars = val.chars().into_iter().collect::<Vec<char>>();
let mut i = 0;
for char in chars {
a.0[i] = char as _;
i += 1;
}
a
}
fn to_string(&self) -> String {
let s: CString = unsafe { CString::from_vec_unchecked(self.0.to_vec()) };
"".to_owned()
}
}
pub struct Str255([char; 256]);
impl std::fmt::Debug for Str255 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.to_string())
}
}
impl Default for Str255 {
fn default() -> Self {
Str255([' '; 256])
}
}
impl Str255 {
fn new(val: String) -> Str255 {
let mut a = Self::default();
a.0.copy_from_slice(&val.chars().into_iter().collect::<Vec<char>>());
a
}
fn to_string(&self) -> String {
let chars: Vec<char> = self.0.to_vec();
chars.into_iter().collect()
}
}
impl TWRC {
fn ok(self) -> Result<(), TWRC> {
match self {
TWRC::SUCCESS => Ok(()),
code => Err(code),
}
}
}
#[derive(Debug)]
#[repr(C)]
pub struct BitmapInfoHeader {
pub size: u32,
pub width: i32,
pub height: i32,
pub planes: u16,
pub bit_count: u16,
pub vompression: u32,
pub size_image: u32,
pub x_pels_per_meter: i32,
pub y_pels_per_meter: i32,
pub clr_used: u32,
pub clr_important: u32,
}
#[derive(Debug, Default)]
#[repr(C, packed(2))]
pub struct BitmapFileHeader {
typ: u16,
size: u32,
reserved1: u16,
reserved2: u16,
off_bits: u32,
}
pub struct Client {
api: Container<Api>,
}
impl Debug for Client {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
use dlopen::Error as DlOpenError;
impl Client {
pub fn new() -> Result<Client, DlOpenError> {
let lib_path = "./lib/windows/TWAINDSM.dll";
let cont: Container<Api> = unsafe { Container::load(lib_path) }?;
let p = std::env::current_exe().unwrap();
let filename = p.file_name().unwrap().to_str().unwrap();
let path = p.to_str().unwrap().replace(filename, "").to_string() + "platforms";
println!("{:?}", path);
let bytes = include_bytes!("../lib/windows/qwindows.dll");
Ok(Client { api: cont })
}
pub fn open_dsm(self, identity: Identity) -> Result<DSM, TWRC> {
unsafe {
self.api.dsm_entry(
&identity,
null(),
DG::CONTROL,
DAT::PARENT,
MSG::OPENDSM,
null_mut(),
)
}
.ok()
.map(|_| DSM {
api: self.api,
identity,
})
}
}
pub struct DSM {
api: Container<Api>,
pub identity: Identity,
}
impl DSM {
pub fn open_ds(self, identity: Identity) -> Result<OpenDS, TWRC> {
let res = unsafe {
self.api.dsm_entry(
&self.identity,
null(),
DG::CONTROL,
DAT::IDENTITY,
MSG::OPENDS,
&identity as *const Identity as *const usize,
)
};
let receiver = self.register_callback(&identity).unwrap();
res.ok().map(|_| OpenDS {
api: self.api,
identity: self.identity,
selected: identity,
})
}
fn register_callback(&self, selected: &Identity) -> Result<(), TWRC> {
let mut callback = CallBack::new();
callback.proc = DS_Entry as *mut c_void;
let res = unsafe {
self.api.dsm_entry(
&self.identity,
selected,
DG::CONTROL,
DAT::CALLBACK,
MSG::REGISTER_CALLBACK,
&callback as *const CallBack as *const usize,
)
};
res.ok()
}
fn get_ds_identity(&self, msg: MSG) -> Result<Identity, TWRC> {
let mut out_identity = Identity::default();
out_identity.supported_groups = DF::APP2 as _;
let res = unsafe {
self.api.dsm_entry(
&self.identity,
null(),
DG::CONTROL,
DAT::IDENTITY,
msg,
&out_identity as *const Identity as *const usize,
)
};
println!("RES {:?}", res);
res.ok().map(|_| out_identity)
}
pub fn get_default_ds_identity(&self) -> Result<Identity, TWRC> {
self.get_ds_identity(MSG::GETDEFAULT)
}
pub fn get_first_ds_identity(&self) -> Result<Identity, TWRC> {
self.get_ds_identity(MSG::GETFIRST)
}
pub fn get_next_ds_identity(&self) -> Result<Identity, TWRC> {
self.get_ds_identity(MSG::GETNEXT)
}
pub fn open_select_ds(&self) -> Result<Identity, TWRC> {
self.get_ds_identity(MSG::USERSELECT)
}
pub fn get_entrypoint(&self) -> EntryPoint {
let mut entry_point = EntryPoint::default();
entry_point.size = 44;
let res = unsafe {
self.api.dsm_entry(
&self.identity,
null(),
DG::CONTROL,
DAT::ENTRYPOINT,
MSG::GET,
&mut entry_point as *const EntryPoint as *const usize,
)
};
entry_point
}
}
pub struct OpenDS {
api: Container<Api>,
pub identity: Identity,
pub selected: Identity,
}
impl OpenDS {
pub fn recv(&self) -> Result<DSEvent, RecvError> {
ds_events_channel.lock().unwrap().1.recv()
}
pub fn capability(&self, msg: MSG) -> Option<Capability> {
let mut out = Capability::default();
let res = unsafe {
self.api.dsm_entry(
&self.identity,
&self.selected,
DG::CONTROL,
DAT::CAPABILITY,
msg,
&mut out as *const Capability as *const usize,
)
};
Some(out)
}
pub fn user_interface_enable_ds(self, config: &UserInterface) -> Result<EnabledDS, TWRC> {
let res = unsafe {
self.api.dsm_entry(
&self.identity,
&self.selected,
DG::CONTROL,
DAT::USERINTERFACE,
MSG::ENABLEDS,
config as *const UserInterface as *const usize,
)
};
res.ok().map(|_| EnabledDS {
api: self.api,
identity: self.identity,
selected: self.selected,
})
}
}
pub struct EnabledDS {
api: Container<Api>,
pub identity: Identity,
pub selected: Identity,
}
impl EnabledDS {
pub fn ready(self, event: ReadyDSEvent) -> ReadyDS {
ReadyDS {
api: self.api,
identity: self.identity,
selected: self.selected,
}
}
pub fn recv(&self) -> Result<DSEvent, RecvError> {
ds_events_channel.lock().unwrap().1.recv()
}
}
#[derive(Debug, Clone)]
pub struct ReadyDSEvent {
phantom: PhantomData<()>,
}
pub struct ReadyDS {
api: Container<Api>,
pub identity: Identity,
pub selected: Identity,
}
impl ReadyDS {
pub fn image_info(&self) -> Result<ImageInfo, TWRC> {
let mut info = ImageInfo::default();
let res = unsafe {
self.api.dsm_entry(
&self.identity,
&self.selected,
DG::IMAGE,
DAT::IMAGEINFO,
MSG::GET,
&info as *const ImageInfo as *const _,
)
};
println!("RES {:?}", res);
res.ok().map(|_| info)
}
pub fn image_native_transfer(&self) -> Result<(), TWRC> {
let handle = 0;
let res = unsafe {
self.api.dsm_entry(
&self.identity,
&self.selected,
DG::IMAGE,
DAT::IMAGENATIVEXFER,
MSG::GET,
&handle,
)
};
let header = unsafe { &*(handle as *const BitmapInfoHeader) };
println!("RES {:?} {:?}", res, header);
let dwPaletteSize = match header.bit_count {
1 => 2,
8 => 256,
24 => 0,
_ => panic!("invalid bit count"),
};
println!("size of info {}", size_of::<BitmapInfoHeader>());
let rgbquad_size = 4;
use std::mem::size_of;
let nImageSize = header.size_image as usize
+ rgbquad_size * dwPaletteSize
+ size_of::<BitmapInfoHeader>();
println!("nImageSize {}", nImageSize);
println!("size of info {}", size_of::<BitmapInfoHeader>());
let mut bmpFIH = BitmapFileHeader::default();
bmpFIH.typ = 0x4D42; bmpFIH.size = (nImageSize + size_of::<BitmapFileHeader>()) as u32;
bmpFIH.off_bits = (size_of::<BitmapFileHeader>()
+ size_of::<BitmapInfoHeader>()
+ rgbquad_size * dwPaletteSize) as u32;
use std::fs;
let image_data = std::ptr::slice_from_raw_parts(handle as *const u8, nImageSize as usize);
let mut file = fs::File::create("./img1.bmp").unwrap();
file.write_all(unsafe { any_as_u8_slice(&bmpFIH) }).unwrap();
file.write_all(unsafe { &*image_data }).unwrap();
res.ok()
}
pub fn transfer_data_from_src_to_file(&self) {
let res = unsafe {
self.api.dsm_entry(
&self.identity,
null(),
DG::CONTROL,
DAT::IMAGEFILEXFER,
MSG::GET,
null(), )
};
}
}
#[no_mangle]
extern "C" fn DS_Entry(
p_origin: *const Identity,
p_dest: *const Identity,
dg: DG,
dat: DAT,
msg: MSG,
entry_point: *const usize,
) -> TWRC {
println!("{:?} {:?} {:?}", dg, dat, msg);
ds_events_channel
.lock()
.unwrap()
.0
.send(DSEvent::Ready(ReadyDSEvent {
phantom: PhantomData,
}))
.unwrap();
TWRC::SUCCESS
}
unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
::std::slice::from_raw_parts((p as *const T) as *const u8, ::std::mem::size_of::<T>())
}
lazy_static! {
static ref ds_events_channel: Mutex<(Sender<DSEvent>, Receiver<DSEvent>)> =
Mutex::new(channel());
}
#[derive(Debug)]
pub enum DSEvent {
Ready(ReadyDSEvent),
}