837 lines
23 KiB
C++
837 lines
23 KiB
C++
#include "sane_hg_mdw.h"
|
|
|
|
#include "sane_opt/sane_opts.h"
|
|
|
|
#include <stdarg.h>
|
|
#include <time.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <mutex>
|
|
#include <thread>
|
|
#if defined(WIN32) || defined(_WIN64)
|
|
#include <windows.h>
|
|
#include <direct.h>
|
|
#define pthread_t DWORD
|
|
#define pthread_self GetCurrentThreadId
|
|
#define MKDIR(a, b) mkdir(a)
|
|
#else
|
|
#define MKDIR(a, b) mkdir(a, b)
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#include "../../sdk/include/sane/sane_option_definitions.h"
|
|
#include "sane_option.h"
|
|
#include <lang/app_language.h>
|
|
#include "../sdk/hginclude/utils.h"
|
|
#include <huagao/brand.h>
|
|
|
|
#ifndef SIGUSR1
|
|
#define SIGUSR1 10
|
|
#endif
|
|
|
|
// copy to /usr/lib/x86_64-linux-gnu/sane
|
|
// export SANE_DEBUG_DLL=5
|
|
|
|
#ifndef iconv_t
|
|
#define iconv_t void*
|
|
#endif
|
|
|
|
namespace local_utility
|
|
{
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#define RETURN_MATCH_ERROR(err, from, to) \
|
|
if(err == from) \
|
|
return to;
|
|
|
|
SANE_Status scanner_err_2_sane_statu(int hgerr)
|
|
{
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_OK, SANE_STATUS_GOOD);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_INVALID_PARAMETER, SANE_STATUS_INVAL);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_INSUFFICIENT_MEMORY, SANE_STATUS_NO_MEM);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_ACCESS_DENIED, SANE_STATUS_ACCESS_DENIED);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_IO_PENDING, SANE_STATUS_GOOD);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_NOT_EXACT, SANE_STATUS_GOOD);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_CONFIGURATION_CHANGED, SANE_STATUS_GOOD);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_RELOAD_IMAGE_PARAM, SANE_STATUS_GOOD);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_RELOAD_OPT_PARAM, SANE_STATUS_GOOD);
|
|
//RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_NOT_OPEN, SANE_STATUS_NO_DOCS);
|
|
//RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_NOT_START, SANE_STATUS_NO_DOCS);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_NO_DATA, SANE_STATUS_EOF);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_IO, SANE_STATUS_IO_ERROR);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_OUT_OF_RANGE, SANE_STATUS_INVAL);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_IO, SANE_STATUS_IO_ERROR);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_TIMEOUT, SANE_STATUS_IO_ERROR);
|
|
|
|
// RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_DEVICE_NOT_FOUND, SANE_STATUS_NO_DOCS);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_DEVICE_NOT_SUPPORT, SANE_STATUS_UNSUPPORTED);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_DEVICE_BUSY, SANE_STATUS_DEVICE_BUSY);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_DEVICE_COVER_OPENNED, SANE_STATUS_COVER_OPEN);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_DEVICE_NO_PAPER, SANE_STATUS_NO_DOCS);
|
|
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_DEVICE_PAPER_JAMMED, SANE_STATUS_JAMMED);
|
|
|
|
return (SANE_Status)hgerr;
|
|
}
|
|
int sane_statu_2_scanner_err(int statu)
|
|
{
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_GOOD, SCANNER_ERR_OK);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_INVAL, SCANNER_ERR_INVALID_PARAMETER);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_NO_MEM, SCANNER_ERR_INSUFFICIENT_MEMORY);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_ACCESS_DENIED, SCANNER_ERR_ACCESS_DENIED);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_GOOD, SCANNER_ERR_IO_PENDING);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_GOOD, SCANNER_ERR_NOT_EXACT);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_GOOD, SCANNER_ERR_CONFIGURATION_CHANGED);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_GOOD, SCANNER_ERR_RELOAD_IMAGE_PARAM);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_GOOD, SCANNER_ERR_RELOAD_OPT_PARAM);
|
|
//RETURN_MATCH_ERROR(statu, SANE_STATUS_NO_DOCS, SCANNER_ERR_NOT_OPEN);
|
|
//RETURN_MATCH_ERROR(statu, SANE_STATUS_NO_DOCS, SCANNER_ERR_NOT_START);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_EOF, SCANNER_ERR_NO_DATA);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_IO_ERROR, SCANNER_ERR_IO);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_INVAL, SCANNER_ERR_OUT_OF_RANGE);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_IO_ERROR, SCANNER_ERR_IO);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_IO_ERROR, SCANNER_ERR_TIMEOUT);
|
|
|
|
//RETURN_MATCH_ERROR(statu, SANE_STATUS_NO_DOCS, SCANNER_ERR_DEVICE_NOT_FOUND);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_UNSUPPORTED, SCANNER_ERR_DEVICE_NOT_SUPPORT);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_DEVICE_BUSY, SCANNER_ERR_DEVICE_BUSY);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_COVER_OPEN, SCANNER_ERR_DEVICE_COVER_OPENNED);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_NO_DOCS, SCANNER_ERR_DEVICE_NO_PAPER);
|
|
RETURN_MATCH_ERROR(statu, SANE_STATUS_JAMMED, SCANNER_ERR_DEVICE_PAPER_JAMMED);
|
|
|
|
return statu;
|
|
}
|
|
|
|
void* acquire_memory(size_t bytes, const char* info)
|
|
{
|
|
//if (!info)
|
|
// info = "";
|
|
//hg_sane_middleware::log(strlen(info) + 80, "allocate memory with %u bytes from %s\n", bytes, info);
|
|
|
|
void* buf = malloc(bytes);
|
|
|
|
if (buf)
|
|
memset(buf, 0, bytes);
|
|
|
|
return buf;
|
|
}
|
|
void free_memory(void* m)
|
|
{
|
|
if (m)
|
|
free(m);
|
|
}
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
static sane_callback cb_ui_ = nullptr;
|
|
static void* cb_ui_parm_ = nullptr;
|
|
static SANE_Auth_Callback cb_auth_ = nullptr;
|
|
static std::mutex cb_lock_;
|
|
|
|
static std::string sane_event(SANE_Event ev)
|
|
{
|
|
RETURN_IF(ev, SANE_EVENT_NONE);
|
|
RETURN_IF(ev, SANE_EVENT_SUPPORT_ASYNC_IO);
|
|
RETURN_IF(ev, SANE_EVENT_IS_MEMORY_ENOUGH);
|
|
RETURN_IF(ev, SANE_EVENT_NEED_AUTH);
|
|
RETURN_IF(ev, SANE_EVENT_DEVICE_ARRIVED);
|
|
RETURN_IF(ev, SANE_EVENT_DEVICE_LEFT);
|
|
RETURN_IF(ev, SANE_EVENT_STATUS);
|
|
RETURN_IF(ev, SANE_EVENT_ERROR);
|
|
RETURN_IF(ev, SANE_EVENT_WORKING);
|
|
RETURN_IF(ev, SANE_EVENT_IMAGE_OK);
|
|
RETURN_IF(ev, SANE_EVENT_SCAN_FINISHED);
|
|
RETURN_IF(ev, SANE_EVENT_ABOUT_INFORMATION);
|
|
RETURN_IF(ev, SANE_EVENT_SCANNER_CLOSED);
|
|
|
|
char unk[20];
|
|
sprintf(unk, "%d", ev);
|
|
|
|
return unk;
|
|
}
|
|
int ui_cb(scanner_handle dev, int code, void* data, unsigned int* len, void* unused)
|
|
{
|
|
sane_callback cb_ui = nullptr;
|
|
void* cb_ui_parm = nullptr;
|
|
SANE_Auth_Callback cb_auth = nullptr;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lck(cb_lock_);
|
|
cb_ui = cb_ui_;
|
|
cb_ui_parm = cb_ui_parm_;
|
|
cb_auth_ = cb_auth;
|
|
}
|
|
|
|
if (SANE_EVENT_SUPPORT_ASYNC_IO == code)
|
|
return cb_ui_ ? SCANNER_ERR_OK : SCANNER_ERR_DEVICE_NOT_SUPPORT;
|
|
|
|
SANE_Handle h = hg_sane_middleware::scanner_handle_to_sane(dev);
|
|
|
|
// utils::to_log_with_api(hg_scanner_log_is_enable, hg_scanner_log, LOG_LEVEL_ALL, "sane callback invoked of event %s\n", sane_event((SANE_Event)code).c_str());
|
|
|
|
if (cb_ui)
|
|
{
|
|
return cb_ui(h, code, data, len, cb_ui_parm);
|
|
}
|
|
else if (cb_auth && code == SANE_EVENT_NEED_AUTH)
|
|
{
|
|
SANEAUTH* auth = (SANEAUTH*)data;
|
|
cb_auth(auth->resource, auth->name, auth->pwd);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void get_version(SANE_Int* version_code)
|
|
{
|
|
if (version_code)
|
|
*version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, VERSION_BUILD); // leading-char '1' is used for avoid compiler considering '0118' as an octal number :)
|
|
}
|
|
void set_callback(sane_callback cb, void* param)
|
|
{
|
|
std::lock_guard<std::mutex> lck(cb_lock_);
|
|
cb_ui_ = cb;
|
|
cb_ui_parm_ = param;
|
|
}
|
|
void stop_work(void)
|
|
{
|
|
std::lock_guard<std::mutex> lck(cb_lock_);
|
|
cb_ui_ = nullptr;
|
|
cb_ui_parm_ = nullptr;
|
|
cb_auth_ = nullptr;
|
|
}
|
|
|
|
static void dump_msg(const char* msg)
|
|
{
|
|
utils::to_log_with_api(hg_scanner_log_is_enable, hg_scanner_log, LOG_LEVEL_DEBUG, msg);
|
|
}
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
hg_sane_middleware* hg_sane_middleware::inst_ = nullptr;
|
|
const SANE_Device** hg_sane_middleware::dev_list_ = nullptr;
|
|
|
|
hg_sane_middleware::hg_sane_middleware(void) : init_ok_(false), offline_(nullptr)
|
|
{
|
|
char sane_ver[40] = { 0 };
|
|
|
|
init_ok_ = true;
|
|
|
|
sprintf(sane_ver, "%u.%u.%u", SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, VERSION_BUILD);
|
|
#if defined(WIN32)
|
|
hg_scanner_set_sane_info("sane", sane_ver);
|
|
#else
|
|
signal(SIGUSR1, &hg_sane_middleware::device_pnp);
|
|
hg_scanner_set_sane_info(GET_BACKEND_NAME, sane_ver);
|
|
#endif
|
|
hg_scanner_initialize(local_utility::ui_cb, nullptr);
|
|
|
|
// initialize offline options with scanner_handle nullptr:
|
|
{
|
|
offline_ = new DEVINST;
|
|
offline_->opts = new device_opts();
|
|
reload_options(offline_);
|
|
}
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500)); // wait for device OK
|
|
}
|
|
hg_sane_middleware::~hg_sane_middleware()
|
|
{
|
|
for (auto& v : openning_)
|
|
{
|
|
hg_sane_middleware::free_device_instance(v);
|
|
}
|
|
hg_sane_middleware::free_device_instance(offline_);
|
|
offline_ = nullptr;
|
|
openning_.clear();
|
|
hg_scanner_uninitialize();
|
|
|
|
if (hg_sane_middleware::dev_list_)
|
|
local_utility::free_memory(hg_sane_middleware::dev_list_);
|
|
}
|
|
|
|
const SANE_Device** hg_sane_middleware::to_sane_device(ScannerInfo* hgscanner, int count)
|
|
{
|
|
// 将多级指针安排在一个连续的内存空间存放
|
|
SANE_Device** ret = nullptr, * dev = nullptr;
|
|
SANE_String val = nullptr;
|
|
unsigned long bytes = (count + 1) * (sizeof(SANE_Device) + sizeof(SANE_Device*)), total = 0;
|
|
|
|
// calculate space ...
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
bytes += ALIGN_INT(strlen(hgscanner[i].name) + 1);
|
|
bytes += ALIGN_INT(strlen(hgscanner[i].vendor) + 1);
|
|
bytes += ALIGN_INT(strlen(hgscanner[i].model) + 1);
|
|
bytes += ALIGN_INT(strlen(hgscanner[i].type) + 1);
|
|
}
|
|
|
|
bytes = ALIGN_INT(bytes + 16);
|
|
dev = (SANE_Device*)local_utility::acquire_memory(bytes, "hg_sane_middleware::to_sane_device");
|
|
total = bytes;
|
|
if (!dev)
|
|
return nullptr;
|
|
|
|
memset(dev, 0, bytes);
|
|
ret = (SANE_Device**)dev;
|
|
dev = (SANE_Device*)((SANE_Device**)dev + count + 1);
|
|
val = (SANE_String)(dev + count);
|
|
|
|
#define COPY_DEVICE_MEMBER(m) \
|
|
dev->m = val; \
|
|
strcpy(val, hgscanner[i].m); \
|
|
bytes = ALIGN_INT(strlen(val) + 1); \
|
|
val += bytes;
|
|
|
|
for (int i = 0; i < count; ++i, ++dev)
|
|
{
|
|
ret[i] = dev;
|
|
COPY_DEVICE_MEMBER(name);
|
|
COPY_DEVICE_MEMBER(vendor);
|
|
COPY_DEVICE_MEMBER(model);
|
|
COPY_DEVICE_MEMBER(type);
|
|
}
|
|
|
|
//utils::to_log_with_api(hg_scanner_log_is_enable, hg_scanner_log, LOG_LEVEL_ALL, "Memory usage: %u / %u\n", val - (char*)ret, total);
|
|
|
|
return (const SANE_Device**)ret;
|
|
}
|
|
void hg_sane_middleware::free_sane_device(SANE_Device** dev)
|
|
{
|
|
char* mem = (char*)dev;
|
|
|
|
if (mem)
|
|
{
|
|
free(mem);
|
|
}
|
|
}
|
|
void hg_sane_middleware::device_pnp(int sig)
|
|
{
|
|
utils::to_log_with_api(hg_scanner_log_is_enable, hg_scanner_log, LOG_LEVEL_DEBUG, "Device list changed (%d)...", sig);
|
|
}
|
|
SANE_Fixed hg_sane_middleware::double_2_sane_fixed(double v)
|
|
{
|
|
return SANE_FIX(v);
|
|
}
|
|
double hg_sane_middleware::sane_fixed_2_double(SANE_Fixed v)
|
|
{
|
|
return SANE_UNFIX(v);
|
|
}
|
|
scanner_handle hg_sane_middleware::sane_handle_to_scanner(SANE_Handle h)
|
|
{
|
|
if (!h)
|
|
return nullptr;
|
|
|
|
int bits = sizeof(h) / 2 * 8;
|
|
uint64_t v = (uint64_t)h;
|
|
|
|
v ^= v >> bits;
|
|
|
|
return (scanner_handle)(v);
|
|
}
|
|
SANE_Handle hg_sane_middleware::scanner_handle_to_sane(scanner_handle h)
|
|
{
|
|
if (!h)
|
|
return nullptr;
|
|
|
|
int bits = sizeof(h) / 2 * 8;
|
|
uint64_t v = (uint64_t)h;
|
|
|
|
v ^= v >> bits;
|
|
|
|
return (SANE_Handle)(v);
|
|
}
|
|
void hg_sane_middleware::free_device_instance(LPDEVINST inst)
|
|
{
|
|
if (inst)
|
|
{
|
|
if (inst->dev)
|
|
hg_scanner_close(inst->dev, true);
|
|
if (inst->opts)
|
|
delete inst->opts;
|
|
|
|
delete inst;
|
|
}
|
|
}
|
|
|
|
hg_sane_middleware::LPDEVINST hg_sane_middleware::find_openning_device(SANE_Handle h, bool rmv)
|
|
{
|
|
LPDEVINST ret = nullptr;
|
|
scanner_handle handle = hg_sane_middleware::sane_handle_to_scanner(h);
|
|
|
|
for (int i = 0; i < openning_.size(); ++i)
|
|
{
|
|
if (openning_[i]->dev == handle)
|
|
{
|
|
ret = openning_[i];
|
|
if (rmv)
|
|
openning_.erase(openning_.begin() + i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
hg_sane_middleware::LPDEVINST hg_sane_middleware::find_openning_device(const char* name, bool rmv)
|
|
{
|
|
LPDEVINST ret = nullptr;
|
|
|
|
for(int i = 0; i < openning_.size(); ++i)
|
|
{
|
|
if (openning_[i]->name == name)
|
|
{
|
|
ret = openning_[i];
|
|
if (rmv)
|
|
openning_.erase(openning_.begin() + i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
bool hg_sane_middleware::reload_options(LPDEVINST inst)
|
|
{
|
|
long len = 0;
|
|
char *buf = nullptr;
|
|
scanner_err err = hg_scanner_get_option(inst->dev, PARAM_ALL, buf, &len, OPT_VAL_JSON);
|
|
|
|
if (err == SCANNER_ERR_INSUFFICIENT_MEMORY)
|
|
{
|
|
buf = new char[len + 4];
|
|
err = hg_scanner_get_option(inst->dev, PARAM_ALL, buf, &len, OPT_VAL_JSON);
|
|
}
|
|
|
|
if (err == SCANNER_ERR_OK && len)
|
|
{
|
|
if (!inst->opts->init_from(buf, local_utility::dump_msg))
|
|
err = SCANNER_ERR_DATA_DAMAGED;
|
|
}
|
|
if (buf)
|
|
delete[] buf;
|
|
|
|
return err == SCANNER_ERR_OK;
|
|
}
|
|
|
|
scanner_err hg_sane_middleware::read_value(scanner_handle h, const char* name, SANE_Value_Type type, size_t len, void* value, bool to_default)
|
|
{
|
|
scanner_err err = SCANNER_ERR_INVALID_PARAMETER;
|
|
|
|
if (type == SANE_TYPE_BOOL)
|
|
{
|
|
bool v = false;
|
|
long len = sizeof(v);
|
|
err = hg_scanner_get_option(h, name, (char*)&v, &len, to_default ? OPT_VAL_DEFAULT : OPT_VAL_CURRENT);
|
|
if (value)
|
|
*(SANE_Bool*)value = v ? SANE_TRUE : SANE_FALSE;
|
|
}
|
|
else if (type == SANE_TYPE_INT)
|
|
{
|
|
int v = 0;
|
|
long len = sizeof(v);
|
|
err = hg_scanner_get_option(h, name, (char*)&v, &len, to_default ? OPT_VAL_DEFAULT : OPT_VAL_CURRENT);
|
|
if (value)
|
|
*(SANE_Int*)value = v;
|
|
}
|
|
else if (type == SANE_TYPE_FIXED)
|
|
{
|
|
double v = .0f;
|
|
long len = sizeof(v);
|
|
err = hg_scanner_get_option(h, name, (char*)&v, &len, to_default ? OPT_VAL_DEFAULT : OPT_VAL_CURRENT);
|
|
if (value)
|
|
*(SANE_Fixed*)value = hg_sane_middleware::double_2_sane_fixed(v);
|
|
}
|
|
else
|
|
{
|
|
long l = len;
|
|
err = hg_scanner_get_option(h, name, (char*)value, &l, to_default ? OPT_VAL_DEFAULT : OPT_VAL_CURRENT);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
scanner_err hg_sane_middleware::write_value(scanner_handle h, const char* name, SANE_Value_Type type, void* value, bool to_default, LPDEVINST optinst, SANE_Int* affect)
|
|
{
|
|
scanner_err err = SCANNER_ERR_INVALID_PARAMETER;
|
|
|
|
if (type == SANE_TYPE_BOOL)
|
|
{
|
|
bool v = value ? *(SANE_Bool*)value == SANE_TRUE : false;
|
|
err = hg_scanner_set_option(h, name, &v, to_default);
|
|
if (value)
|
|
*(SANE_Bool*)value = v ? SANE_TRUE : SANE_FALSE;
|
|
}
|
|
else if (type == SANE_TYPE_INT)
|
|
{
|
|
int v = value ? *(SANE_Int*)value : 0;
|
|
err = hg_scanner_set_option(h, name, &v, to_default);
|
|
if (value)
|
|
*(SANE_Int*)value = v;
|
|
}
|
|
else if (type == SANE_TYPE_FIXED)
|
|
{
|
|
double v = value ? hg_sane_middleware::sane_fixed_2_double(*(SANE_Fixed*)value) : .0f;
|
|
err = hg_scanner_set_option(h, name, &v, to_default);
|
|
if (value)
|
|
*(SANE_Fixed*)value = hg_sane_middleware::double_2_sane_fixed(v);
|
|
}
|
|
else
|
|
{
|
|
err = hg_scanner_set_option(h, name, value, to_default);
|
|
}
|
|
|
|
if (affect)
|
|
*affect = 0;
|
|
|
|
if (err == SCANNER_ERR_RELOAD_OPT_PARAM || err == SCANNER_ERR_CONFIGURATION_CHANGED)
|
|
{
|
|
if(optinst)
|
|
reload_options(optinst);
|
|
if (affect)
|
|
*affect = SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS;
|
|
err = SCANNER_ERR_OK;
|
|
}
|
|
else if (err == SCANNER_ERR_RELOAD_IMAGE_PARAM)
|
|
{
|
|
err = SCANNER_ERR_OK;
|
|
if (affect)
|
|
*affect = SANE_INFO_RELOAD_PARAMS;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
SANE_Status hg_sane_middleware::get_current_value(LPDEVINST inst, const void* opt, void* value, bool default_val)
|
|
{
|
|
std::string val("");
|
|
SANE_Option_Descriptor* desc = inst->opts->get_opt_descriptor(opt);
|
|
|
|
if (!desc && inst != offline_)
|
|
{
|
|
desc = offline_->opts->get_opt_descriptor(opt, nullptr, inst->opts->get_option_count());
|
|
if (desc)
|
|
inst = offline_;
|
|
else
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
else if (!desc)
|
|
{
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
if (desc)
|
|
{
|
|
scanner_err err = read_value(inst->dev, desc->name, desc->type, desc->size, value, default_val);
|
|
|
|
return local_utility::scanner_err_2_sane_statu(err);
|
|
}
|
|
else
|
|
{
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
}
|
|
SANE_Status hg_sane_middleware::set_value(LPDEVINST inst, const void* opt, void* value, SANE_Int* affect, bool to_default)
|
|
{
|
|
bool empty_value = false;
|
|
SANE_Option_Descriptor* desc = inst->opts->get_opt_descriptor(opt);
|
|
|
|
if (!desc && inst != offline_)
|
|
{
|
|
desc = offline_->opts->get_opt_descriptor(opt, nullptr, inst->opts->get_option_count());
|
|
if (desc)
|
|
inst = offline_;
|
|
else
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
else if (!desc)
|
|
{
|
|
return SANE_STATUS_INVAL;
|
|
}
|
|
|
|
if (IS_CAP_READONLY(desc->cap))
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
if (to_default && (desc->cap & SANE_CAP_AUTOMATIC) == 0)
|
|
return SANE_STATUS_UNSUPPORTED;
|
|
|
|
scanner_err err = write_value(inst->dev, desc->name, desc->type, value, to_default, inst, affect);
|
|
|
|
return local_utility::scanner_err_2_sane_statu(err);
|
|
}
|
|
SANE_Status hg_sane_middleware::get_option_fixed_id(LPDEVINST inst, const void* opt, void* value)
|
|
{
|
|
int fix_id = 0;
|
|
|
|
if (!inst->opts->get_opt_descriptor(opt, &fix_id) && inst != offline_)
|
|
{
|
|
offline_->opts->get_opt_descriptor(opt, &fix_id, inst->opts->get_option_count());
|
|
}
|
|
*(SANE_Int*)value = fix_id;
|
|
|
|
return fix_id <= 0 ? SANE_STATUS_INVAL : SANE_STATUS_GOOD;
|
|
}
|
|
|
|
|
|
void hg_sane_middleware::set_app_callback(void* cb, void* param, int type)
|
|
{
|
|
if (type == APP_CALLBACK_EX)
|
|
local_utility::set_callback((sane_callback)cb, param);
|
|
else
|
|
local_utility::cb_auth_ = (SANE_Auth_Callback)cb;
|
|
}
|
|
void hg_sane_middleware::get_version(SANE_Int* ver)
|
|
{
|
|
if (ver)
|
|
*ver = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, VERSION_BUILD); // leading-char '1' is used for avoid compiler considering '0118' as an octal number :)
|
|
}
|
|
hg_sane_middleware* hg_sane_middleware::instance(void)
|
|
{
|
|
if (!hg_sane_middleware::inst_)
|
|
hg_sane_middleware::inst_ = new hg_sane_middleware();
|
|
|
|
return hg_sane_middleware::inst_;
|
|
}
|
|
void hg_sane_middleware::clear(void)
|
|
{
|
|
local_utility::stop_work();
|
|
if (hg_sane_middleware::inst_)
|
|
{
|
|
delete hg_sane_middleware::inst_;
|
|
hg_sane_middleware::inst_ = nullptr;
|
|
}
|
|
}
|
|
|
|
SANE_Status hg_sane_middleware::get_devices(const SANE_Device*** device_list, SANE_Bool local_only)
|
|
{
|
|
if (!device_list)
|
|
return SANE_STATUS_INVAL;
|
|
|
|
ScannerInfo * dev = nullptr;
|
|
long count = 0;
|
|
scanner_err hgerr = hg_scanner_enum(dev, &count, local_only);
|
|
SANE_Status ret = SANE_STATUS_GOOD;
|
|
|
|
if (hgerr == SCANNER_ERR_INSUFFICIENT_MEMORY)
|
|
{
|
|
count += 4;
|
|
dev = (ScannerInfo*)local_utility::acquire_memory(sizeof(ScannerInfo) * count, "hg_sane_middleware::get_devices");
|
|
hgerr = hg_scanner_enum(dev, &count, local_only);
|
|
}
|
|
|
|
if (hgerr == SCANNER_ERR_OK)
|
|
*device_list = hg_sane_middleware::to_sane_device(dev, count);
|
|
else
|
|
ret = local_utility::scanner_err_2_sane_statu(hgerr);
|
|
if (dev)
|
|
local_utility::free_memory(dev);
|
|
|
|
|
|
if (hg_sane_middleware::dev_list_)
|
|
local_utility::free_memory(hg_sane_middleware::dev_list_);
|
|
hg_sane_middleware::dev_list_ = *device_list;
|
|
|
|
return ret;
|
|
}
|
|
SANE_Status hg_sane_middleware::open_device(SANE_String_Const devicename, SANE_Handle* handle)
|
|
{
|
|
if (!handle)
|
|
return SANE_STATUS_INVAL;
|
|
|
|
char rsc[128] = { 0 };
|
|
scanner_handle h = nullptr;
|
|
scanner_err se = hg_scanner_open(&h, devicename, false, nullptr, nullptr, nullptr, rsc);
|
|
|
|
if (se == SCANNER_ERR_ACCESS_DENIED && rsc[0])
|
|
{
|
|
SANEAUTH auth;
|
|
memset(&auth, 0, sizeof(auth));
|
|
auth.resource = rsc;
|
|
if (local_utility::ui_cb(nullptr, SANE_EVENT_NEED_AUTH, (void*)&auth, nullptr, nullptr))
|
|
{
|
|
return SANE_STATUS_CANCELLED;
|
|
}
|
|
|
|
se = hg_scanner_open(&h, devicename, false, auth.name, auth.pwd, auth.method, rsc);
|
|
}
|
|
|
|
if (se == SCANNER_ERR_OK)
|
|
{
|
|
// for depend item maybe later, we move the depend-logic-operation out of 'from_json'. to ensure the status, we get all options actively and do depend-logic operation after all options got - 2023-06-21
|
|
LPDEVINST inst = new DEVINST;
|
|
|
|
inst->dev = h;
|
|
inst->name = devicename;
|
|
inst->opts = new device_opts();
|
|
if(reload_options(inst))
|
|
{
|
|
openning_.push_back(inst);
|
|
*handle = hg_sane_middleware::scanner_handle_to_sane(h);
|
|
}
|
|
else
|
|
{
|
|
hg_sane_middleware::free_device_instance(inst);
|
|
*handle = nullptr;
|
|
se = SCANNER_ERR_DATA_DAMAGED;
|
|
}
|
|
}
|
|
|
|
return local_utility::scanner_err_2_sane_statu(se);
|
|
}
|
|
SANE_Status hg_sane_middleware::close_device(SANE_Handle h)
|
|
{
|
|
LPDEVINST inst = find_openning_device(h, true);
|
|
SANE_Status err = SANE_STATUS_GOOD;
|
|
|
|
if (inst)
|
|
{
|
|
if(inst->dev)
|
|
err = local_utility::scanner_err_2_sane_statu(hg_scanner_close(inst->dev, true));
|
|
inst->dev = nullptr;
|
|
hg_sane_middleware::free_device_instance(inst);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
SANE_Status hg_sane_middleware::get_image_parameters(SANE_Handle handle, SANE_Parameters* params)
|
|
{
|
|
if (!params)
|
|
return SANE_STATUS_INVAL;
|
|
|
|
LPDEVINST inst = find_openning_device(handle);
|
|
scanner_err err = SCANNER_ERR_NOT_START;
|
|
|
|
if(inst && inst->dev)
|
|
err = hg_scanner_get_img_info(inst->dev, params, sizeof(*params));
|
|
|
|
return local_utility::scanner_err_2_sane_statu(err);
|
|
}
|
|
SANE_Status hg_sane_middleware::start(SANE_Handle h, void* async_event)
|
|
{
|
|
LPDEVINST dev = find_openning_device(h);
|
|
scanner_err err = SCANNER_ERR_INVALID_PARAMETER;
|
|
|
|
if(dev && dev->dev)
|
|
err = hg_scanner_start(dev->dev, async_event, -1);
|
|
|
|
return local_utility::scanner_err_2_sane_statu(err);
|
|
}
|
|
SANE_Status hg_sane_middleware::read(SANE_Handle h, void* buf, int* bytes)
|
|
{
|
|
LPDEVINST dev = find_openning_device(h);
|
|
scanner_err err = SCANNER_ERR_INVALID_PARAMETER;
|
|
long r = bytes ? *bytes : 0;
|
|
|
|
if (bytes)
|
|
{
|
|
if (dev && dev->dev)
|
|
{
|
|
err = hg_scanner_read_img_data(dev->dev, (unsigned char*)buf, &r);
|
|
*bytes = r;
|
|
}
|
|
else
|
|
err = SCANNER_ERR_NOT_OPEN;
|
|
}
|
|
|
|
return local_utility::scanner_err_2_sane_statu(err);
|
|
}
|
|
SANE_Status hg_sane_middleware::stop(SANE_Handle h)
|
|
{
|
|
LPDEVINST dev = find_openning_device(h);
|
|
scanner_err err = SCANNER_ERR_OK;
|
|
|
|
if (dev && dev->dev)
|
|
err = hg_scanner_stop(dev->dev);
|
|
|
|
return local_utility::scanner_err_2_sane_statu(err);
|
|
}
|
|
SANE_Option_Descriptor* hg_sane_middleware::get_option_descriptor(SANE_Handle h, const void* option)
|
|
{
|
|
SANE_Option_Descriptor* ret = nullptr;
|
|
LPDEVINST dev = find_openning_device(h);
|
|
int base_ind = 0;
|
|
|
|
if (dev)
|
|
{
|
|
base_ind = dev->opts->get_option_count();
|
|
ret = dev->opts->get_opt_descriptor(option);
|
|
}
|
|
|
|
if (!ret)
|
|
ret = offline_->opts->get_opt_descriptor(option, nullptr, base_ind);
|
|
|
|
return ret;
|
|
}
|
|
SANE_Status hg_sane_middleware::control_option(SANE_Handle h, const void* option, SANE_Action action, void* value, SANE_Int* after_do)
|
|
{
|
|
SANE_Status err = SANE_STATUS_INVAL;
|
|
LPDEVINST inst = find_openning_device(h);
|
|
|
|
if (!inst)
|
|
{
|
|
if(h)
|
|
return local_utility::scanner_err_2_sane_statu(SCANNER_ERR_NOT_OPEN);
|
|
|
|
inst = offline_;
|
|
}
|
|
|
|
if (action == SANE_ACTION_GET_VALUE)
|
|
{
|
|
if (!option)
|
|
{
|
|
*(SANE_Int*)value = inst->opts->get_option_count() + offline_->opts->get_option_count();
|
|
err = SANE_STATUS_GOOD;
|
|
}
|
|
else
|
|
{
|
|
err = get_current_value(inst, option, value, false);
|
|
}
|
|
}
|
|
else if (action == SANE_ACTION_SET_VALUE || action == SANE_ACTION_SET_AUTO)
|
|
{
|
|
err = set_value(inst, option, value, after_do, action == SANE_ACTION_SET_AUTO);
|
|
}
|
|
|
|
// extension ...
|
|
else if (action == SANE_ACTION_GET_DEFAULT_VALUE)
|
|
{
|
|
err = get_current_value(inst, option, value, true);
|
|
}
|
|
else if (action == SANE_ACTION_GET_FIX_ID)
|
|
{
|
|
err = get_option_fixed_id(inst, option, value);
|
|
}
|
|
else if (action == SANE_ACTION_ENUM_INVISIBLE_FIX_ID)
|
|
{
|
|
struct _fix_id_cb* fcb = (struct _fix_id_cb*)value;
|
|
if (!inst->opts->enum_invisible_fix_ids(fcb) && inst != offline_)
|
|
offline_->opts->enum_invisible_fix_ids(fcb);
|
|
|
|
err = SANE_STATUS_GOOD;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
SANE_Status hg_sane_middleware::ex_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len)
|
|
{
|
|
LPDEVINST dev = find_openning_device(h);
|
|
int ret = SANE_STATUS_GOOD;
|
|
|
|
// commented at 2022-03-23 for getting app about info before open any device
|
|
//
|
|
//if (!handle)
|
|
// return SANE_STATUS_INVAL;
|
|
ret = hg_scanner_control(dev->dev, code, data, len);
|
|
if (ret == SCANNER_ERR_CONFIGURATION_CHANGED)
|
|
{
|
|
int nc = code;
|
|
utils::to_log_with_api(hg_scanner_log_is_enable, hg_scanner_log, LOG_LEVEL_DEBUG, "the setting '0x%08x' affects other options value, RELOAD ...\n", nc);
|
|
reload_options(dev);
|
|
}
|
|
|
|
return local_utility::scanner_err_2_sane_statu(ret);
|
|
}
|
|
bool hg_sane_middleware::is_ready(void)
|
|
{
|
|
return init_ok_;
|
|
}
|
|
|