twain/
lib.rs

1#![allow(dead_code)]
2#![allow(unused_variables)]
3#![allow(non_upper_case_globals)]
4#![allow(non_camel_case_types)]
5
6#[macro_use]
7extern crate lazy_static;
8
9extern crate dlopen;
10#[macro_use]
11extern crate dlopen_derive;
12use dlopen::wrapper::{Container, WrapperApi};
13use std::{
14    ffi::{c_void, CString},
15    fmt::Debug,
16    io::Write,
17    marker::PhantomData,
18    os::raw::{c_char, c_int},
19    ptr::{null, null_mut},
20    sync::{
21        mpsc::{channel, Receiver, RecvError, Sender},
22        Mutex,
23    },
24    usize,
25};
26
27mod data;
28mod test;
29
30use data::*;
31
32// https://github.com/twain/twain-dsm/blob/9e7bb25d522a8cb2715bbf3b0904ff07a86ea2ee/TWAIN_DSM/src/twain.h
33
34type Handle = *const c_void;
35
36/*
37
38#ifndef TWAIN
39#define TWAIN
40
41/****************************************************************************
42 * TWAIN Version                                                            *
43 ****************************************************************************/
44    PROTOCOLMINOR   4        /* Changed for Version 2.4            */
45    PROTOCOLMAJOR   2
46
47/****************************************************************************
48 * Platform Dependent Definitions and Typedefs                              *
49 ****************************************************************************/
50
51/* Microsoft C/C++ Compiler */
52#if defined(WIN32) || defined(WIN64) || defined (_WINDOWS)
53    #define TWH_CMP_MSC
54    #if  defined(_WIN64) || defined(WIN64)
55      #define TWH_64BIT
56    #elif defined(WIN32) || defined(_WIN32)
57      #define TWH_32BIT
58    #endif
59
60/* GNU C/C++ Compiler */
61#elif defined(__GNUC__)
62    #define TWH_CMP_GNU
63    #if defined(__alpha__)\
64        ||defined(__ia64__)\
65        ||defined(__ppc64__)\
66        ||defined(__s390x__)\
67        ||defined(__x86_64__)
68      #define TWH_64BIT
69    #else
70      #define TWH_32BIT
71    #endif
72
73
74/* Borland C/C++ Compiler */
75#elif defined(__BORLAND__)
76    #define TWH_CMP_BORLAND
77    #define TWH_32BIT
78/* Unrecognized */
79#else
80    #error Unrecognized compiler
81#endif
82
83/* Apple Compiler (which is GNU now) */
84#if defined(__APPLE__)
85  #define TWH_CMP_XCODE
86  #ifdef __MWERKS__
87    #include <Carbon.h>
88  #else
89    #include <Carbon/Carbon.h>
90  #endif
91#endif
92
93/* Win32 and Win64 systems */
94#if defined(TWH_CMP_MSC) | defined(TWH_CMP_BORLAND)
95    typedef HANDLE  TW_HANDLE;
96    typedef LPVOID  TW_MEMREF;
97    typedef UINT_PTR TW_UINTPTR;
98
99/* MacOS/X... */
100#elif defined(TWH_CMP_XCODE)
101    #define PASCAL   pascal
102    #define FAR
103    typedef Handle   TW_HANDLE;
104    typedef char    *TW_MEMREF;
105    typedef unsigned char BYTE;
106
107    #ifdef TWH_32BIT
108      //32 bit GNU
109      typedef unsigned long      TW_UINTPTR;
110    #else
111      //64 bit GNU
112      typedef unsigned long long TW_UINTPTR;
113    #endif
114
115/* Everything else... */
116#else
117    #define PASCAL
118    #define FAR
119    typedef void* TW_HANDLE;
120    typedef void* TW_MEMREF;
121    typedef unsigned char BYTE;
122
123    #ifdef TWH_32BIT
124      //32 bit GNU
125      typedef unsigned long      TW_UINTPTR;
126    #else
127      //64 bit GNU
128      typedef unsigned long long TW_UINTPTR;
129    #endif
130#endif
131
132
133/* Set the packing: this occurs before any structures are defined */
134#ifdef TWH_CMP_MSC
135    #pragma pack (push, before_twain)
136    #pragma pack (2)
137#elif defined(TWH_CMP_GNU)
138    #if defined(__APPLE__) /* cf: Mac version of TWAIN.h */
139        #pragma options align = power
140    #else
141        #pragma pack (push, before_twain)
142        #pragma pack (2)
143    #endif
144#elif defined(TWH_CMP_BORLAND)
145    #pragma option -a2
146#endif
147
148
149/****************************************************************************
150 * Type Definitions                                                         *
151 ****************************************************************************/
152
153/* String types. These include room for the strings and a NULL char,     *
154 * or, on the Mac, a length byte followed by the string.                 *
155 * TW_STR255 must hold less than 256 chars so length fits in first byte. */
156#if defined(__APPLE__)/* cf: Mac version of TWAIN.h */
157    typedef unsigned char TW_STR32[34],     FAR *pTW_STR32;
158    typedef unsigned char TW_STR64[66],     FAR *pTW_STR64;
159    typedef unsigned char TW_STR128[130],   FAR *pTW_STR128;
160    typedef unsigned char TW_STR255[256],   FAR *pTW_STR255;
161#else
162    typedef char          TW_STR32[34],     FAR *pTW_STR32;
163    typedef char          TW_STR64[66],     FAR *pTW_STR64;
164    typedef char          TW_STR128[130],   FAR *pTW_STR128;
165    typedef char          TW_STR255[256],   FAR *pTW_STR255;
166#endif
167
168/* Numeric types. */
169typedef char              TW_INT8,          FAR *pTW_INT8;
170typedef short             i16,         FAR *pi16;
171#if defined(_WIN32)
172    typedef long          i32,         FAR *pi32;
173#else
174    typedef int           i32,         FAR *pi32;
175#endif
176typedef unsigned char     u8,         FAR *pu8;
177typedef unsigned short    u16,        FAR *pu16;
178#if defined(_WIN32)
179    typedef unsigned long u32,        FAR *pu32;
180#else
181    typedef unsigned int  u32,        FAR *pu32;
182#endif
183typedef unsigned short    TW_BOOL,          FAR *pTW_BOOL;
184
185*/
186/****************************************************************************
187 * Structure Definitions                                                    *
188 ****************************************************************************/
189
190/* Fixed point structure type. */
191#[derive(Debug, Default)]
192#[repr(C, packed(2))]
193pub struct FixedPoint32 {
194    whole: i16,
195    frac: u16,
196}
197
198/* Defines a frame rectangle in ICAP_UNITS coordinates. */
199pub struct Frame {
200    left: FixedPoint32,
201    top: FixedPoint32,
202    right: FixedPoint32,
203    bottom: FixedPoint32,
204}
205
206/* Defines the parameters used for channel-specific transformation. */
207pub struct DecodeFunction {
208    start_in: FixedPoint32,
209    break_in: FixedPoint32,
210    end_in: FixedPoint32,
211    start_out: FixedPoint32,
212    break_out: FixedPoint32,
213    end_out: FixedPoint32,
214    gamma: FixedPoint32,
215    sample_count: FixedPoint32,
216}
217
218/* Stores a Fixed point number in two parts, a whole and a fractional part. */
219pub struct TransformStage {
220    decode: [DecodeFunction; 3],
221    mix: [[FixedPoint32; 3]; 3],
222}
223
224/* Container for array of values */
225pub struct Array {
226    item_type: u16,
227    num_items: u32,
228    item_list: [u8; 1],
229}
230
231/* Information about audio data */
232pub struct AudioInfo {
233    name: Str255,
234    reserved: u32,
235}
236
237/* Used to register callbacks. */
238pub struct CallBack {
239    proc: *mut c_void,
240    ref_con: u32,
241    message: i16,
242    /*
243    TW_MEMREF      CallBackProc;
244    #if defined(__APPLE__) /* cf: Mac version of TWAIN.h */
245        TW_MEMREF  RefCon;
246    #else
247        u32  RefCon;
248    #endif*/
249}
250
251impl CallBack {
252    pub fn new() -> CallBack {
253        CallBack {
254            proc: null_mut(),
255            ref_con: 0,
256            message: 0,
257        }
258    }
259}
260
261/* Used to register callbacks. */
262pub struct CallBack2 {
263    proc: *mut c_void,
264    ref_con: *mut usize,
265    message: i16,
266}
267/* Used by application to get/set capability from/in a data source. */
268#[derive(Debug)]
269pub struct Capability {
270    cap: u16,
271    con_type: TWON,
272    h_container: *mut c_void,
273}
274
275impl Capability {
276    fn default() -> Capability {
277        Capability {
278            cap: 0,
279            con_type: TWON::ONEVALUE,
280            h_container: null_mut(),
281        }
282    }
283}
284
285/* Defines a CIE XYZ space tri-stimulus value. */
286pub struct CiePoint {
287    x: FixedPoint32,
288    y: FixedPoint32,
289    z: FixedPoint32,
290}
291
292/* Defines the mapping from an RGB color space device into CIE 1931 (XYZ) color space. */
293pub struct CieColor {
294    color_space: u16,
295    low_endian: i16,
296    device_dependent: i16,
297    version_number: i32,
298    stage_abc: TransformStage,
299    stage_lmn: TransformStage,
300    white_point: CiePoint,
301    black_point: CiePoint,
302    white_paper: CiePoint,
303    black_ink: CiePoint,
304    samples: [FixedPoint32; 1],
305}
306
307/* Allows for a data source and application to pass custom data to each other. */
308pub struct CustomDSData {
309    info_length: u32,
310    h_data: *mut c_void,
311}
312
313/* Provides information about the Event that was raised by the Source */
314pub struct DeviceEvent {
315    event: u32,
316    device_name: Str255,
317    battery_minutes: u32,
318    battery_percentage: i16,
319    power_supply: i32,
320    x_resolution: FixedPoint32,
321    y_resolution: FixedPoint32,
322    flash_used2: u32,
323    automatic_capture: u32,
324    time_before_first_capture: u32,
325    time_between_captures: u32,
326}
327
328/* This structure holds the tri-stimulus color palette information for TW_PALETTE8 structures.*/
329pub struct Element8 {
330    index: u8,
331    channel1: u8,
332    channel2: u8,
333    channel3: u8,
334}
335
336/* Stores a group of individual values describing a capability. */
337pub struct Enumeration {
338    item_type: u16,
339    num_items: u32,
340    current_index: u32,
341    default_index: u32,
342    item_list: [u8; 1],
343}
344
345/* Used to pass application events/messages from the application to the Source. */
346pub struct Event {
347    p_event: *const c_void,
348    message: u16,
349}
350
351/* This structure is used to pass specific information between the data source and the application. */
352pub struct Info {
353    id: u16,
354    item_type: u16,
355    num_items: u16,
356    return_code: u16,
357    /** Deprecated, do not use */
358    cond_code: u16,
359    item: *mut usize,
360    /*
361    union {
362        u16   ReturnCode;
363        u16   CondCode;
364    };*/
365}
366
367pub struct ExtImageInfo {
368    num_infos: u32,
369    info: [Info; 1],
370}
371
372/* Provides information about the currently selected device */
373pub struct FileSystem {
374    input_name: Str255,
375    output_name: Str255,
376    context: *mut c_void,
377    recursive: i32,
378    sub_directories: u16,
379    file_type: i32,
380    file_system_type: u32,
381    size: u32,
382    create_time_date: Str32,
383    modified_time_date: Str32,
384    free_space: u32,
385    new_image_size: i32,
386    number_of_files: u32,
387    number_of_snippets: u32,
388    device_group_mask: u32,
389    reserved: [i8; 508],
390}
391
392/* This structure is used by the application to specify a set of mapping values to be applied to grayscale data. */
393pub struct GrayResponse {
394    response: [Element8; 1],
395}
396
397/* A general way to describe the version of software that is running. */
398#[repr(C, packed(2))]
399#[derive(Debug, Clone)]
400pub struct Version {
401    major_num: u16,
402    minor_num: u16,
403    language: u16, // TWLG,
404    country: u16,  // TWCY,
405    info: Str32,
406}
407
408impl Default for Version {
409    fn default() -> Self {
410        Version {
411            major_num: 1,
412            minor_num: 0,
413            language: TWLG::USA_OR_ENGLISH_USA as _,
414            country: TWCY::USA as _,
415            info: Str32::default(),
416        }
417    }
418}
419
420/* Provides identification information about a TWAIN entity.*/
421#[repr(C, packed(2))]
422#[derive(Debug, Default, Clone)]
423pub struct Identity {
424    id: u32,
425    version: Version,
426    protocol_major: u16,
427    protocol_minor: u16,
428    supported_groups: u32,
429    manufacturer: Str32,
430    product_family: Str32,
431    product_name: Str32,
432}
433
434/* Describes the "real" image data, that is, the complete image being transferred between the Source and application. */
435#[derive(Debug, Default)]
436#[repr(C, packed(2))]
437pub struct ImageInfo {
438    x_resolution: FixedPoint32,
439    y_resolution: FixedPoint32,
440    image_width: i32,
441    image_length: i32,
442    samples_per_pixel: i16,
443    bits_per_sample: [i16; 8],
444    bits_per_pixed: i16,
445    planar: u16,
446    pixel_type: i16,
447    compression: u16,
448}
449
450/* Involves information about the original size of the acquired image. */
451pub struct ImageLayout {
452    frame: Frame,
453    document_number: u32,
454    page_number: u32,
455    frame_number: u32,
456}
457
458/* Provides information for managing memory buffers. */
459pub struct Memory {
460    flags: u32,
461    length: u32,
462    the_mem: *const c_void,
463}
464
465/* Describes the form of the acquired data being passed from the Source to the application.*/
466pub struct ImageMemxfer {
467    compression: i16,
468    bytes_per_row: u32,
469    columns: u32,
470    rows: u32,
471    xoffset: u32,
472    yoffset: u32,
473    bytes_written: u32,
474    memory: Memory,
475}
476
477/* Describes the information necessary to transfer a JPEG-compressed image. */
478pub struct JpegCompression {
479    color_space: u16,
480    sub_sampling: u32,
481    num_components: u16,
482    restart_frequency: u16,
483    quant_map: [u16; 4],
484    quant_table: [Memory; 4],
485    huffman_map: [u16; 4],
486    huffman_dc: [Memory; 2],
487    huffman_ac: [Memory; 2],
488}
489
490/* Collects scanning metrics after returning to state 4 */
491pub struct Metrics {
492    size_of: u32,
493    image_count: u32,
494    sheet_count: u32,
495}
496
497/* Stores a single value (item) which describes a capability. */
498pub struct OneValue {
499    item_type: u16,
500    item: u32,
501}
502
503/* This structure holds the color palette information. */
504pub struct Palette8 {
505    num_colors: u16,
506    palette_type: u16,
507    colors: [Element8; 256],
508}
509
510/* Used to bypass the TWAIN protocol when communicating with a device */
511pub struct PassThru {
512    p_command: *const c_void,
513    command_bytes: u32,
514    direction: i32,
515    p_data: *const c_void,
516    data_bytes: u32,
517    data_bytes_xfered: u32,
518}
519
520/* This structure tells the application how many more complete transfers the Source currently has available. */
521pub struct PendingTransfers {
522    count: u16,
523    eoj: u32,
524    reserved: u32,
525    /*
526    union {
527        u32 EOJ;
528        u32 Reserved;
529        #if defined(__APPLE__) /* cf: Mac version of TWAIN.h */
530            union {
531                u32 EOJ;
532                u32 Reserved;
533            } TW_JOBCONTROL;
534        #endif
535    };*/
536}
537
538/* Stores a range of individual values describing a capability. */
539pub struct Range {
540    item_type: u16,
541    min_value: u32,
542    max_value: u32,
543    step_size: u32,
544    default_value: u32,
545    current_value: u32,
546}
547
548/* This structure is used by the application to specify a set of mapping values to be applied to RGB color data. */
549pub struct RgbResponse {
550    response: [Element8; 1],
551}
552
553/* Describes the file format and file specification information for a transfer through a disk file. */
554pub struct SetupFileTransfer {
555    filename: Str255,
556    format: u16,
557    vref_num: i16,
558}
559
560/* Provides the application information about the Source's requirements and preferences regarding allocation of transfer buffer(s). */
561pub struct SetupMemoryTransfer {
562    min_buf_size: u32,
563    max_buf_size: u32,
564    preferred: u32,
565}
566
567/* Describes the status of a source. */
568pub struct Status {
569    condition_code: u16,
570    data: u16,
571    reserved: u16,
572    /*
573    union {
574      u16  Data;
575      u16  Reserved;
576    };*/
577}
578
579/* Translates the contents of Status into a localized UTF8string. */
580pub struct StatusUtf8 {
581    status: Status,
582    size: u32,
583    utf8_string: *const c_void,
584}
585
586pub struct TwainDirect {
587    size_of: u32,
588    communication_manager: u16,
589    send: *const c_void,
590    send_size: u32,
591    receive: *const c_void,
592    receive_size: u32,
593}
594
595/* This structure is used to handle the user interface coordination between an application and a Source. */
596pub struct UserInterface {
597    show_ui: u16,  // bool
598    modal_ui: u16, // bool
599    /// Windows - The application should place a handle to the Window that is acting as the Source’s parent.
600    /// Macintosh/Linux - The application sets this field to NULL.
601    h_parent: Handle,
602}
603
604impl UserInterface {
605    pub fn new(show_ui: bool, model_ui: bool) -> UserInterface {
606        UserInterface {
607            show_ui: show_ui as _,
608            modal_ui: model_ui as _,
609            /// for windows handle to parent window
610            h_parent: null(),
611        }
612    }
613}
614
615/* DAT_SETUPFILEXFER2. Sets up DS to application data transfer via a file. Added 1.9 */
616pub struct SetupFileTransfer2 {
617    file_name: *const c_void,
618    file_name_type: u16,
619    format: u16,
620    v_ref_num: i16,
621    part_id: u32,
622}
623
624/* DAT_TWUNKIDENTITY. Provides DS identity and 'other' information necessary */
625/*                    across thunk link. */
626pub struct TwunkIdentity {
627    identity: Identity,
628    ds_path: Str255,
629}
630
631/* Provides DS_Entry parameters over thunk link. */
632pub struct TwunkDsEntryParams {
633    dest_flag: i8,
634    dest: Identity,
635    data_group: i32,
636    data_arg_type: i16,
637    message: i16,
638    p_data_size: i32,
639    //  TW_MEMREF   pData;
640}
641
642/* Provides DS_Entry results over thunk link. */
643pub struct TwunkDsEntryReturn {
644    return_code: u16,
645    condition_code: u16,
646    p_data_size: i32,
647    //  TW_MEMREF   pData;
648}
649
650pub struct CapExt {
651    cap: u16,
652    properties: u16,
653}
654
655/* DAT_SETUPAUDIOFILEXFER, information required to setup an audio file transfer */
656pub struct SetupAudioFileTransfer {
657    file_name: Str255,
658    format: TWAF, // u16,
659    v_ref_num: i16,
660}
661
662/* DAT_ENTRYPOINT. returns essential entry points. */
663#[derive(Debug)]
664#[repr(C, packed(2))]
665pub struct EntryPoint {
666    size: u32,
667    // pub ds_entry:
668    //    fn(p_origin: *const Identity, dg: DG, dat: DAT, msg: MSG, p_data: *const c_void) -> u16,
669    pub ds_entry: *const fn(
670        p_origin: *const Identity,
671        p_dest: *const Identity,
672        dg: DG,
673        dat: DAT,
674        msg: MSG,
675        p_data: *const c_void,
676    ) -> u16,
677    pub mem_allocate: *mut fn(u32) -> Handle,
678    pub mem_free: *const fn(Handle) -> (),
679    pub mem_lock: *const fn(Handle) -> *const c_void,
680    pub mem_unlock: *const fn(Handle) -> (),
681}
682
683impl Default for EntryPoint {
684    fn default() -> Self {
685        EntryPoint {
686            size: 44,
687            /*ds_entry: |p_origin: *const Identity,
688                      dg: DG,
689                      dat: DAT,
690                      msg: MSG,
691                      p_data: *const c_void|
692            -> u16 { 0 },*/
693            ds_entry: null(),
694            mem_allocate: null_mut(),
695            mem_free: null(),
696            mem_lock: null(),
697            mem_unlock: null(),
698        }
699    }
700}
701
702impl EntryPoint {
703    pub fn size(&self) -> u32 {
704        self.size
705    }
706
707    pub fn allocate(&self, size: u32) -> Handle {
708        unsafe { (*self.mem_allocate)(size) }
709    }
710}
711
712/* DAT_FILTER*/
713#[repr(C)]
714pub struct FilterDescriptor {
715    size: u32,
716    hue_start: u32,
717    hue_end: u32,
718    saturation_start: u32,
719    saturation_end: u32,
720    value_start: u32,
721    value_end: u32,
722    replacement: u32,
723}
724
725/* DAT_FILTER */
726#[repr(C)]
727pub struct Filter {
728    size: u32,
729    descriptor_count: u32,
730    max_descriptor_count: u32,
731    condition: u32,
732    h_descriptors: Handle,
733}
734
735#[derive(WrapperApi)]
736struct Api {
737    #[dlopen_name = "DSM_Entry"]
738    dsm_entry: unsafe extern "C" fn(
739        p_origin: *const Identity,
740        p_dest: *const Identity,
741        dg: DG,
742        dat: DAT,
743        msg: MSG,
744        entry_point: *const usize,
745    ) -> TWRC,
746}
747
748pub enum State {
749    None = 1,     // Nothing loaded or open
750    LOADED = 2,   // DSM loaded
751    OPEN = 3,     // DSM open
752    DSOPEN = 4,   // Data Source open, programmatic mode (no GUI)
753    WAITING = 5,  // GUI up or waiting to transfer first image
754    READY = 6,    // ready to start transferring image
755    TRANSFER = 7, // transferring image or transfer done
756}
757
758#[derive(Clone)]
759#[repr(C, packed(2))]
760pub struct Str32([u8; 34]);
761
762impl Default for Str32 {
763    fn default() -> Self {
764        Str32([0; 34])
765    }
766}
767
768impl std::fmt::Debug for Str32 {
769    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
770        f.write_str(&self.to_string())
771    }
772}
773
774impl Str32 {
775    fn new(val: &str) -> Str32 {
776        let mut a = Self::default();
777        let t = CString::new(val).unwrap().to_bytes();
778
779        let chars = val.chars().into_iter().collect::<Vec<char>>();
780        let mut i = 0;
781        for char in chars {
782            a.0[i] = char as _;
783            i += 1;
784        }
785        a
786    }
787
788    fn to_string(&self) -> String {
789        let s: CString = unsafe { CString::from_vec_unchecked(self.0.to_vec()) };
790
791        "".to_owned()
792    }
793}
794
795pub struct Str255([char; 256]);
796
797impl std::fmt::Debug for Str255 {
798    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
799        f.write_str(&self.to_string())
800    }
801}
802
803impl Default for Str255 {
804    fn default() -> Self {
805        Str255([' '; 256])
806    }
807}
808
809impl Str255 {
810    fn new(val: String) -> Str255 {
811        let mut a = Self::default();
812        a.0.copy_from_slice(&val.chars().into_iter().collect::<Vec<char>>());
813        a
814    }
815
816    fn to_string(&self) -> String {
817        let chars: Vec<char> = self.0.to_vec();
818        chars.into_iter().collect()
819    }
820}
821
822impl TWRC {
823    fn ok(self) -> Result<(), TWRC> {
824        match self {
825            TWRC::SUCCESS => Ok(()),
826            code => Err(code),
827        }
828    }
829}
830/*
831#[no_mangle]
832pub extern "C" fn DS_Entry(
833    origin: *const Identity,
834    dg: u32,
835    dat: u16,
836    msg: u16,
837    data: *const c_void,
838) -> u16 {
839    println!("got a message");
840    TWRC::SUCCESS as _
841}
842*/
843
844#[derive(Debug)]
845#[repr(C)]
846pub struct BitmapInfoHeader {
847    pub size: u32,
848    pub width: i32,
849    pub height: i32,
850    pub planes: u16,
851    pub bit_count: u16,
852    pub vompression: u32,
853    pub size_image: u32,
854    pub x_pels_per_meter: i32,
855    pub y_pels_per_meter: i32,
856    pub clr_used: u32,
857    pub clr_important: u32,
858}
859
860#[derive(Debug, Default)]
861#[repr(C, packed(2))]
862pub struct BitmapFileHeader {
863    /** Specifies the file type, must be BM. */
864    typ: u16,
865    /** Specifies the size, in bytes, of the bitmap file. */
866    size: u32,
867    /** Reserved; must be zero. */
868    reserved1: u16,
869    /** Reserved; must be zero. */
870    reserved2: u16,
871    /** Specifies the offset, in bytes, from the beginning of                                          the BITMAPFILEHEADER structure to the bitmap bits. */
872    off_bits: u32,
873}
874
875pub struct Client {
876    api: Container<Api>,
877}
878
879impl Debug for Client {
880    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
881        Ok(())
882    }
883}
884
885use dlopen::Error as DlOpenError;
886
887impl Client {
888    pub fn new() -> Result<Client, DlOpenError> {
889        let lib_path = "./lib/windows/TWAINDSM.dll";
890        let cont: Container<Api> = unsafe { Container::load(lib_path) }?;
891
892        let p = std::env::current_exe().unwrap();
893        let filename = p.file_name().unwrap().to_str().unwrap();
894        let path = p.to_str().unwrap().replace(filename, "").to_string() + "platforms";
895        println!("{:?}", path);
896
897        let bytes = include_bytes!("../lib/windows/qwindows.dll");
898
899        // std::fs::create_dir(path.clone()).unwrap();
900        // std::fs::write(path + "/qwindows.dll", bytes).unwrap();
901        Ok(Client { api: cont })
902    }
903    pub fn open_dsm(self, identity: Identity) -> Result<DSM, TWRC> {
904        unsafe {
905            self.api.dsm_entry(
906                &identity,
907                null(),
908                DG::CONTROL,
909                DAT::PARENT,
910                MSG::OPENDSM,
911                null_mut(),
912            )
913        }
914        .ok()
915        .map(|_| DSM {
916            api: self.api,
917            identity,
918        })
919    }
920}
921
922pub struct DSM {
923    api: Container<Api>,
924    pub identity: Identity,
925}
926
927impl DSM {
928    pub fn open_ds(self, identity: Identity) -> Result<OpenDS, TWRC> {
929        let res = unsafe {
930            self.api.dsm_entry(
931                &self.identity,
932                null(),
933                DG::CONTROL,
934                DAT::IDENTITY,
935                MSG::OPENDS,
936                &identity as *const Identity as *const usize,
937            )
938        };
939        let receiver = self.register_callback(&identity).unwrap();
940
941        res.ok().map(|_| OpenDS {
942            api: self.api,
943            identity: self.identity,
944            selected: identity,
945        })
946    }
947
948    fn register_callback(&self, selected: &Identity) -> Result<(), TWRC> {
949        let mut callback = CallBack::new();
950        callback.proc = DS_Entry as *mut c_void;
951        let res = unsafe {
952            self.api.dsm_entry(
953                &self.identity,
954                selected,
955                DG::CONTROL,
956                DAT::CALLBACK,
957                MSG::REGISTER_CALLBACK,
958                &callback as *const CallBack as *const usize,
959            )
960        };
961
962        res.ok()
963    }
964
965    fn get_ds_identity(&self, msg: MSG) -> Result<Identity, TWRC> {
966        let mut out_identity = Identity::default();
967        out_identity.supported_groups = DF::APP2 as _;
968
969        let res = unsafe {
970            self.api.dsm_entry(
971                &self.identity,
972                null(),
973                DG::CONTROL,
974                DAT::IDENTITY,
975                msg,
976                &out_identity as *const Identity as *const usize,
977            )
978        };
979        println!("RES {:?}", res);
980        res.ok().map(|_| out_identity)
981    }
982
983    pub fn get_default_ds_identity(&self) -> Result<Identity, TWRC> {
984        self.get_ds_identity(MSG::GETDEFAULT)
985    }
986
987    pub fn get_first_ds_identity(&self) -> Result<Identity, TWRC> {
988        self.get_ds_identity(MSG::GETFIRST)
989    }
990
991    pub fn get_next_ds_identity(&self) -> Result<Identity, TWRC> {
992        self.get_ds_identity(MSG::GETNEXT)
993    }
994
995    pub fn open_select_ds(&self) -> Result<Identity, TWRC> {
996        self.get_ds_identity(MSG::USERSELECT)
997    }
998
999    pub fn get_entrypoint(&self) -> EntryPoint {
1000        let mut entry_point = EntryPoint::default();
1001        entry_point.size = 44;
1002        let res = unsafe {
1003            self.api.dsm_entry(
1004                &self.identity,
1005                null(),
1006                DG::CONTROL,
1007                DAT::ENTRYPOINT,
1008                MSG::GET,
1009                &mut entry_point as *const EntryPoint as *const usize,
1010            )
1011        };
1012        entry_point
1013    }
1014}
1015
1016pub struct OpenDS {
1017    api: Container<Api>,
1018    pub identity: Identity,
1019    pub selected: Identity,
1020}
1021
1022impl OpenDS {
1023    pub fn recv(&self) -> Result<DSEvent, RecvError> {
1024        ds_events_channel.lock().unwrap().1.recv()
1025    }
1026
1027    pub fn capability(&self, msg: MSG) -> Option<Capability> {
1028        let mut out = Capability::default();
1029        let res = unsafe {
1030            self.api.dsm_entry(
1031                &self.identity,
1032                &self.selected,
1033                DG::CONTROL,
1034                DAT::CAPABILITY,
1035                msg,
1036                &mut out as *const Capability as *const usize,
1037            )
1038        };
1039        Some(out)
1040    }
1041
1042    pub fn user_interface_enable_ds(self, config: &UserInterface) -> Result<EnabledDS, TWRC> {
1043        let res = unsafe {
1044            self.api.dsm_entry(
1045                &self.identity,
1046                &self.selected,
1047                DG::CONTROL,
1048                DAT::USERINTERFACE,
1049                MSG::ENABLEDS,
1050                config as *const UserInterface as *const usize,
1051            )
1052        };
1053        res.ok().map(|_| EnabledDS {
1054            api: self.api,
1055            identity: self.identity,
1056            selected: self.selected,
1057        })
1058    }
1059}
1060
1061pub struct EnabledDS {
1062    api: Container<Api>,
1063    pub identity: Identity,
1064    pub selected: Identity,
1065}
1066
1067impl EnabledDS {
1068    pub fn ready(self, event: ReadyDSEvent) -> ReadyDS {
1069        ReadyDS {
1070            api: self.api,
1071            identity: self.identity,
1072            selected: self.selected,
1073        }
1074    }
1075
1076    pub fn recv(&self) -> Result<DSEvent, RecvError> {
1077        ds_events_channel.lock().unwrap().1.recv()
1078    }
1079}
1080
1081#[derive(Debug, Clone)]
1082pub struct ReadyDSEvent {
1083    phantom: PhantomData<()>,
1084}
1085
1086pub struct ReadyDS {
1087    api: Container<Api>,
1088    pub identity: Identity,
1089    pub selected: Identity,
1090}
1091
1092impl ReadyDS {
1093    pub fn image_info(&self) -> Result<ImageInfo, TWRC> {
1094        let mut info = ImageInfo::default();
1095        let res = unsafe {
1096            self.api.dsm_entry(
1097                &self.identity,
1098                &self.selected,
1099                DG::IMAGE,
1100                DAT::IMAGEINFO,
1101                MSG::GET,
1102                &info as *const ImageInfo as *const _,
1103            )
1104        };
1105        println!("RES {:?}", res);
1106        res.ok().map(|_| info)
1107    }
1108
1109    pub fn image_native_transfer(&self) -> Result<(), TWRC> {
1110        let handle = 0;
1111        let res = unsafe {
1112            self.api.dsm_entry(
1113                &self.identity,
1114                &self.selected,
1115                DG::IMAGE,
1116                DAT::IMAGENATIVEXFER,
1117                MSG::GET,
1118                &handle,
1119            )
1120        };
1121        let header = unsafe { &*(handle as *const BitmapInfoHeader) };
1122        println!("RES {:?} {:?}", res, header);
1123
1124        let dwPaletteSize = match header.bit_count {
1125            1 => 2,
1126            8 => 256,
1127            24 => 0,
1128            _ => panic!("invalid bit count"),
1129        };
1130
1131        println!("size of info {}", size_of::<BitmapInfoHeader>());
1132        let rgbquad_size = 4;
1133
1134        use std::mem::size_of;
1135        let nImageSize = header.size_image as usize
1136            + rgbquad_size * dwPaletteSize
1137            + size_of::<BitmapInfoHeader>();
1138        println!("nImageSize {}", nImageSize);
1139
1140        println!("size of info {}", size_of::<BitmapInfoHeader>());
1141        let mut bmpFIH = BitmapFileHeader::default();
1142
1143        bmpFIH.typ = 0x4D42; // ((('M' as i32) << 8 as i32) as u16 as i32 | 'B' as i32) as u16;
1144        bmpFIH.size = (nImageSize + size_of::<BitmapFileHeader>()) as u32;
1145        bmpFIH.off_bits = (size_of::<BitmapFileHeader>()
1146            + size_of::<BitmapInfoHeader>()
1147            + rgbquad_size * dwPaletteSize) as u32;
1148
1149        use std::fs;
1150
1151        let image_data = std::ptr::slice_from_raw_parts(handle as *const u8, nImageSize as usize);
1152        let mut file = fs::File::create("./img1.bmp").unwrap();
1153        file.write_all(unsafe { any_as_u8_slice(&bmpFIH) }).unwrap();
1154        file.write_all(unsafe { &*image_data }).unwrap();
1155
1156        res.ok()
1157    }
1158
1159    /**  The triplet the application sends to transfer data from the Source into a file is: */
1160    pub fn transfer_data_from_src_to_file(&self) {
1161        let res = unsafe {
1162            self.api.dsm_entry(
1163                &self.identity,
1164                null(),
1165                DG::CONTROL,
1166                DAT::IMAGEFILEXFER,
1167                MSG::GET,
1168                null(), //&out_identity as *const Identity as *const usize,
1169            )
1170        };
1171    }
1172}
1173
1174#[no_mangle]
1175extern "C" fn DS_Entry(
1176    p_origin: *const Identity,
1177    p_dest: *const Identity,
1178    dg: DG,
1179    dat: DAT,
1180    msg: MSG,
1181    entry_point: *const usize,
1182) -> TWRC {
1183    println!("{:?} {:?} {:?}", dg, dat, msg);
1184
1185    ds_events_channel
1186        .lock()
1187        .unwrap()
1188        .0
1189        .send(DSEvent::Ready(ReadyDSEvent {
1190            phantom: PhantomData,
1191        }))
1192        .unwrap();
1193    TWRC::SUCCESS
1194}
1195
1196// https://github.com/mrlitong/TWAIN-SDK
1197
1198unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
1199    ::std::slice::from_raw_parts((p as *const T) as *const u8, ::std::mem::size_of::<T>())
1200}
1201
1202lazy_static! {
1203    static ref ds_events_channel: Mutex<(Sender<DSEvent>, Receiver<DSEvent>)> =
1204        Mutex::new(channel());
1205}
1206
1207#[derive(Debug)]
1208pub enum DSEvent {
1209    Ready(ReadyDSEvent),
1210}