code_device/hgsane/sane_hg_mdw.cpp

2051 lines
54 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "sane_hg_mdw.h"
#include "json.h"
#include <stdarg.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mutex>
#ifdef WIN32
#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"
#ifndef VERSION_BUILD
#define VERSION_BUILD 22030
#endif
#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
static std::string g_sane_path = "";
namespace local_utility
{
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SANE_Status scanner_err_2_sane_statu(int hgerr)
{
#define RETURN_MATCH_ERROR(hg, sane) \
if(hgerr == hg) \
return sane;
RETURN_MATCH_ERROR(SCANNER_ERR_OK, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(SCANNER_ERR_INVALID_PARAMETER, SANE_STATUS_INVAL);
RETURN_MATCH_ERROR(SCANNER_ERR_INSUFFICIENT_MEMORY, SANE_STATUS_NO_MEM);
RETURN_MATCH_ERROR(SCANNER_ERR_ACCESS_DENIED, SANE_STATUS_ACCESS_DENIED);
RETURN_MATCH_ERROR(SCANNER_ERR_IO_PENDING, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(SCANNER_ERR_NOT_EXACT, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(SCANNER_ERR_CONFIGURATION_CHANGED, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(SCANNER_ERR_NOT_OPEN, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(SCANNER_ERR_NOT_START, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(SCANNER_ERR_NO_DATA, SANE_STATUS_EOF);
RETURN_MATCH_ERROR(SCANNER_ERR_HAS_DATA_YET, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(SCANNER_ERR_OUT_OF_RANGE, SANE_STATUS_NO_MEM);
RETURN_MATCH_ERROR(SCANNER_ERR_IO, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(SCANNER_ERR_TIMEOUT, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_NOT_FOUND, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_NOT_SUPPORT, SANE_STATUS_UNSUPPORTED);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_BUSY, SANE_STATUS_DEVICE_BUSY);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_COVER_OPENNED, SANE_STATUS_COVER_OPEN);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_NO_PAPER, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_PAPER_JAMMED, SANE_STATUS_JAMMED);
return (SANE_Status)hgerr;
}
int sane_statu_2_scanner_err(int statu)
{
#define RETURN_MATCH_ERROR(hg, sane) \
if(statu == sane) \
return hg;
RETURN_MATCH_ERROR(SCANNER_ERR_OK, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(SCANNER_ERR_INVALID_PARAMETER, SANE_STATUS_INVAL);
RETURN_MATCH_ERROR(SCANNER_ERR_INSUFFICIENT_MEMORY, SANE_STATUS_NO_MEM);
RETURN_MATCH_ERROR(SCANNER_ERR_ACCESS_DENIED, SANE_STATUS_ACCESS_DENIED);
RETURN_MATCH_ERROR(SCANNER_ERR_IO_PENDING, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(SCANNER_ERR_NOT_EXACT, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(SCANNER_ERR_CONFIGURATION_CHANGED, SANE_STATUS_GOOD);
RETURN_MATCH_ERROR(SCANNER_ERR_NOT_OPEN, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(SCANNER_ERR_NOT_START, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(SCANNER_ERR_NO_DATA, SANE_STATUS_EOF);
RETURN_MATCH_ERROR(SCANNER_ERR_HAS_DATA_YET, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(SCANNER_ERR_OUT_OF_RANGE, SANE_STATUS_NO_MEM);
RETURN_MATCH_ERROR(SCANNER_ERR_IO, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(SCANNER_ERR_TIMEOUT, SANE_STATUS_IO_ERROR);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_NOT_FOUND, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_NOT_SUPPORT, SANE_STATUS_UNSUPPORTED);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_BUSY, SANE_STATUS_DEVICE_BUSY);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_COVER_OPENNED, SANE_STATUS_COVER_OPEN);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_NO_PAPER, SANE_STATUS_NO_DOCS);
RETURN_MATCH_ERROR(SCANNER_ERR_DEVICE_PAPER_JAMMED, SANE_STATUS_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);
return malloc(bytes);
}
void free_memory(void* m)
{
if (m)
free(m);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// json parser ...
bool is_space(char ch)
{
return ch == ' ' || ch == '\t';
}
bool is_digital(char ch)
{
return ch >= '0' && ch <= '9';
}
bool is_hex_num(char ch)
{
if (is_digital(ch))
return true;
return (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F');
}
bool to_num(char ch, int& v, bool hex)
{
if (is_digital(ch))
{
v = ch - '0';
return true;
}
if (hex)
{
if (ch >= 'a' && ch <= 'f')
{
v = ch - 'a' + 10;
}
else if (ch >= 'A' && ch <= 'F')
{
v = ch - 'A' + 10;
}
else
{
hex = false;
}
}
return hex;
}
bool skip_space(const char*& str)
{
const char* bgn = str;
while (is_space(*str))
str++;
return str > bgn;
}
// 暂不支持科学计数<E8AEA1><E695B0>?1.2e+10
bool get_number(const char*& str, double& val)
{
const char* bgn = str;
double val_race = 10.0f,
val_sign = 1.0f,
digit_race = 1.0f,
digit_race_race = 1.0f;
val = .0f;
if (*str == '-')
{
str++;
val_sign = -1.0f;
}
if (*str == '.')
{
str++;
digit_race = digit_race_race = .1f;
val_race = 1.0f;
}
bgn = str;
while (*str && is_digital(*str))
{
int v = 0;
val *= val_race;
to_num(*str++, v, false);
val += v * digit_race;
digit_race *= digit_race_race;
}
if (*str == '.')
{
if (digit_race_race < 1.0f)
return false;
digit_race = digit_race_race = .1f;
val_race = 1.0f;
while (*str && is_digital(*str))
{
int v = 0;
val *= val_race;
to_num(*str++, v, false);
val += v * digit_race;
digit_race *= digit_race_race;
}
}
return str > bgn;
}
bool get_limit(const char*& str, std::string& l, std::string& r)
{
// set l = "a", r = "b" in text "[a, b]"
bool ret = *str == '[';
if (ret)
{
str++;
skip_space(str);
l = str;
size_t pos = l.find("]");
if (pos == -1)
return false;
l.erase(pos);
pos = l.find(",");
if (pos == -1)
return false;
r = l.substr(pos + 1);
l.erase(pos);
}
return ret;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static sane_callback cb_ui_ = NULL;
static void* cb_ui_parm_ = NULL;
static SANE_Auth_Callback cb_auth_ = NULL;
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)
{
std::lock_guard<std::mutex> lck(cb_lock_);
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);
VLOG_MINI_1(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_ = NULL;
cb_ui_parm_ = NULL;
cb_auth_ = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
hg_sane_middleware* hg_sane_middleware::inst_ = NULL;
const SANE_Device** hg_sane_middleware::dev_list_ = NULL;
hg_sane_middleware::hg_sane_middleware(void) : opt_0_(nullptr), std_opt_(nullptr)
{
char sane_ver[40] = { 0 };
sprintf(sane_ver, "%u.%u.%u", SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, VERSION_BUILD);
signal(SIGUSR1, &hg_sane_middleware::device_pnp);
hg_scanner_set_sane_info(GET_BACKEND_NAME, sane_ver);
hg_scanner_initialize(local_utility::ui_cb, NULL);
#ifndef WIN32
char path[512] = { 0 };
size_t pos = 0;
g_sane_path = get_file_path((std::string(GET_BACKEND_NAME) + ".so").c_str(), path);
pos = g_sane_path.rfind('/');
if (pos++ != std::string::npos)
g_sane_path.erase(pos);
#endif
}
hg_sane_middleware::~hg_sane_middleware()
{
for (size_t i = 0; i < opts_.size(); ++i)
{
local_utility::free_memory(opts_[i].desc);
}
for (size_t i = 0; i < openning_.size(); ++i)
hg_scanner_close(openning_[i].handle, true);
hg_scanner_uninitialize();
if (opt_0_)
local_utility::free_memory(opt_0_);
if (std_opt_)
delete std_opt_;
}
const SANE_Device** hg_sane_middleware::to_sane_device(ScannerInfo* hgscanner, int count)
{
// 将多级指针安排在一个连续的内存空间存放
SANE_Device** ret = NULL, * dev = NULL;
SANE_String val = NULL;
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 NULL;
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);
}
//VLOG_MINI_2(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)
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "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);
}
std::string hg_sane_middleware::option_value_2_string(SANE_Value_Type type, void* val)
{
std::string ret("unknown");
char buf[40];
switch (type)
{
case SANE_TYPE_BOOL:
ret = *(SANE_Bool*)val ? "true" : "false";
break;
case SANE_TYPE_INT:
sprintf(buf, "%d", *(SANE_Word*)val);
ret = buf;
break;
case SANE_TYPE_FIXED:
sprintf(buf, "%f", hg_sane_middleware::sane_fixed_2_double(*(SANE_Word*)val));
ret = buf;
break;
case SANE_TYPE_STRING:
ret = (char*)val;
break;
case SANE_TYPE_BUTTON:
ret = "Button";
break;
case SANE_TYPE_GROUP:
ret = "Group";
break;
default:
break;
}
return ret;
}
std::string hg_sane_middleware::sane_path(void)
{
return g_sane_path;
}
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::set_callback(sane_callback cb, void* param)
{
local_utility::set_callback(cb, param);
}
void hg_sane_middleware::clear(void)
{
local_utility::stop_work();
if (hg_sane_middleware::inst_)
{
delete hg_sane_middleware::inst_;
hg_sane_middleware::inst_ = NULL;
}
}
scanner_handle hg_sane_middleware::sane_handle_to_scanner(SANE_Handle h)
{
int bits = sizeof(h) / 2 * 8;
unsigned long long v = (unsigned long long)h;
v ^= v >> bits;
return (scanner_handle)(v);
}
SANE_Handle hg_sane_middleware::scanner_handle_to_sane(scanner_handle h)
{
int bits = sizeof(h) / 2 * 8;
unsigned long long v = (unsigned long long)h;
v ^= v >> bits;
return (SANE_Handle)(v);
}
SANE_Option_Descriptor* hg_sane_middleware::string_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<std::string>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(char*);
SANE_Option_Descriptor *sod = NULL;
char *str = NULL, **str_arr = NULL;
bytes += ALIGN_INT(strlen(name) + 1);
bytes += ALIGN_INT(strlen(title) + 1);
bytes += ALIGN_INT(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(char*);
for (size_t i = 0; i < values.size(); ++i)
bytes += ALIGN_INT(values[i].length() + 1);
bytes += sizeof(char*) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "hg_sane_middleware::string_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INT(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INT(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INT(strlen(str) + 1);
sod->type = SANE_TYPE_STRING;
sod->unit = SANE_UNIT_NONE;
sod->size = values.size();
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
| SANE_CAP_AUTOMATIC; // 硬件可设置默认<E9BB98><E8AEA4>?
if (values.size())
{
sod->constraint_type = SANE_CONSTRAINT_STRING_LIST;
sod->constraint.string_list = (char**)str;
str_arr = (char**)str;
str += (values.size() + 1) * sizeof(char*);
for (size_t i = 0; i < values.size(); ++i)
{
str_arr[i] = str;
strcpy(str, values[i].c_str());
str += ALIGN_INT(values[i].length() + 1);
}
}
//VLOG_MINI_2(LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* hg_sane_middleware::number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, bool double_val, double* lower, double* upper)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor *sod = NULL;
char *str = NULL;
bytes += ALIGN_INT(strlen(name) + 1);
bytes += ALIGN_INT(strlen(title) + 1);
bytes += ALIGN_INT(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Range*) + sizeof(SANE_Range);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "hg_sane_middleware::number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INT(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INT(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INT(strlen(str) + 1);
sod->type = double_val ? SANE_TYPE_FIXED : SANE_TYPE_INT;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
/*| SANE_CAP_AUTOMATIC*/; // 硬件可设置默认<E9BB98><E8AEA4>?
if (lower || upper)
{
sod->size = sizeof(SANE_Range);
sod->constraint_type = SANE_CONSTRAINT_RANGE;
sod->constraint.range = (SANE_Range*)str;
if (lower)
{
if (double_val)
(*(SANE_Range*)str).min = hg_sane_middleware::double_2_sane_fixed(*lower);
else
(*(SANE_Range*)str).min = *lower;
}
if (upper)
{
if (double_val)
(*(SANE_Range*)str).max = hg_sane_middleware::double_2_sane_fixed(*upper);
else
(*(SANE_Range*)str).max = *upper;
}
(*(SANE_Range*)str).quant = 0;
str = (char*)((SANE_Range*)str + 1);
}
//VLOG_MINI_2(LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* hg_sane_middleware::number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<int>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor* sod = NULL;
char* str = NULL;
bytes += ALIGN_INT(strlen(name) + 1);
bytes += ALIGN_INT(strlen(title) + 1);
bytes += ALIGN_INT(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Word*) + sizeof(SANE_Word) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "hg_sane_middleware::number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INT(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INT(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INT(strlen(str) + 1);
sod->type = SANE_TYPE_INT;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
/*| SANE_CAP_AUTOMATIC*/; // 硬件可设置默认<E9BB98><E8AEA4>?
if (values.size())
{
SANE_Word *val = (SANE_Word*)str;
sod->constraint.word_list = val;
sod->constraint_type = SANE_CONSTRAINT_WORD_LIST;
*val++ = values.size();
for (size_t i = 0; i < values.size(); ++i)
val[i] = values[i];
str = (char*)(val + values.size());
}
//VLOG_MINI_2(LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
SANE_Option_Descriptor* hg_sane_middleware::number_option_to_SANE_descriptor(const char* name, const char* title, const char* desc
, const std::vector<double>& values)
{
int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range);
SANE_Option_Descriptor* sod = NULL;
char* str = NULL;
bytes += ALIGN_INT(strlen(name) + 1);
bytes += ALIGN_INT(strlen(title) + 1);
bytes += ALIGN_INT(strlen(desc) + 1);
bytes += sizeof(SANE_Option_Descriptor);
bytes += sizeof(SANE_Word*) + sizeof(SANE_Word) * (values.size() + 1);
sod = (SANE_Option_Descriptor*)local_utility::acquire_memory(bytes, "hg_sane_middleware::number_option_to_SANE_descriptor");
bzero(sod, bytes);
str = (char*)sod;
str += sizeof(SANE_Option_Descriptor);
sod->name = str;
strcpy(str, name);
str += ALIGN_INT(strlen(str) + 1);
sod->title = str;
strcpy(str, title);
str += ALIGN_INT(strlen(str) + 1);
sod->desc = str;
strcpy(str, desc);
str += ALIGN_INT(strlen(str) + 1);
sod->type = SANE_TYPE_FIXED;
sod->unit = SANE_UNIT_NONE;
sod->size = sizeof(SANE_Word);
sod->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT // 软件可设置选项
/*| SANE_CAP_AUTOMATIC*/; // 硬件可设置默认<E9BB98><E8AEA4>?
if (values.size())
{
SANE_Word* val = (SANE_Word*)str;
sod->constraint.word_list = val;
sod->constraint_type = SANE_CONSTRAINT_WORD_LIST;
*val++ = values.size();
for (size_t i = 0; i < values.size(); ++i)
val[i] = hg_sane_middleware::double_2_sane_fixed(values[i]);
str = (char*)(val + values.size());
}
//VLOG_MINI_2(LOG_LEVEL_ALL, "Memory usage: %u/%u\n", str - (char*)sod, bytes);
return sod;
}
void hg_sane_middleware::on_device_closed(scanner_handle h)
{
// 由于目前对多设备的支持还不是刚需故代码只考虑单设备情况设备关闭后清除所有变<E69C89><E58F98>?
for (size_t i = 0; i < opts_.size(); ++i)
{
local_utility::free_memory(opts_[i].desc);
}
opts_.clear();
for (size_t i = 0; i < openning_.size(); ++i)
{
if (openning_[i].handle == h)
{
openning_.erase(openning_.begin() + i);
i--;
}
}
cur_vals_.clear();
slave_options_.clear();
master_options_.clear();
if (std_opt_)
delete std_opt_;
std_opt_ = nullptr;
}
SANE_Status hg_sane_middleware::open(SANE_String_Const devicename, SANE_Handle* handle, const char* name, const char* pwd, const char* method, char* rsc)
{
scanner_handle h = NULL;
scanner_err err = SCANNER_ERR_OK;
if (handle == NULL)
return SANE_STATUS_INVAL;
err = hg_scanner_open(&h, devicename, false, NULL, NULL, NULL, rsc);
if (err == SCANNER_ERR_OK)
{
OPENDEV od;
od.dev_name = devicename;
od.handle = h;
od.scan_count = -1;
openning_.push_back(od);
*handle = hg_sane_middleware::scanner_handle_to_sane(h);
if (!local_utility::cb_ui_)
{
long count = 0;
hg_scanner_get_parameter(h, 0, NULL, &count);
std_opt_ = new sane_std_opts(count);
}
return SANE_STATUS_GOOD;
}
else if (err == SCANNER_ERR_ACCESS_DENIED)
{
return SANE_STATUS_ACCESS_DENIED;
}
else
return SANE_STATUS_UNSUPPORTED;
}
SANE_Option_Descriptor* hg_sane_middleware::from_json(scanner_handle h, json* jsn, int opt_no)
{
std::string name(""), title(""), desc(""), val("");
std::vector<std::string> constraints;
double lower = .0f, upper = .0f;
bool db_val = false;
jsn->get_value("name", name);
jsn->get_value("title", title);
jsn->get_value("desc", desc);
if (!jsn->get_value("type", val))
return NULL;
SANE_Option_Descriptor* ret = NULL;
if (val == "string")
{
json* range = NULL;
std::vector<std::string> constraints;
jsn->get_value("range", range);
if (range)
{
if (range->first_child(val))
{
constraints.push_back(val);
while (range->next_child(val))
{
constraints.push_back(val);
}
}
delete range;
}
ret = hg_sane_middleware::string_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
else if (val == "int" || val == "float")
{
json* range = NULL;
jsn->get_value("range", range);
if (range)
{
if (val == "int")
{
int l = 0;
if (range->get_value("min", l))
{
int u = 0;
range->get_value("max", u);
lower = l;
upper = u;
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, &lower, &upper);
}
else
{
std::vector<int> constraints;
if (range->first_child(val))
{
constraints.push_back(atoi(val.c_str()));
while (range->next_child(val))
{
constraints.push_back(atoi(val.c_str()));
}
}
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
}
else
{
if (range->get_value("min", lower))
{
range->get_value("max", upper);
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, true, &lower, &upper);
}
else
{
std::vector<double> constraints;
if (range->first_child(val))
{
constraints.push_back(atof(val.c_str()));
while (range->next_child(val))
{
constraints.push_back(atof(val.c_str()));
}
}
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, constraints);
}
}
delete range;
}
else
{
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL);
}
}
else if (val == "bool")
{
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL);
ret->type = SANE_TYPE_BOOL;
}
else if (val == "button")
{
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL);
ret->type = SANE_TYPE_BUTTON;
}
else if (val == "group")
{
ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str()
, false, NULL, NULL);
ret->type = SANE_TYPE_GROUP;
}
// fill the 'size' field, for SANE_ACTION_GET action ...
if (ret)
{
int bytes = 0;
jsn->get_value("size", bytes);
ret->size = bytes;
val = "";
jsn->get_value("category", val);
if (val == "advanced")
{
ret->cap |= SANE_CAP_ADVANCED;
}
if (strcmp(ret->title, "\345\210\206\350\276\250\347\216\207") == 0)
{
LOG_INFO(LOG_LEVEL_DEBUG_INFO, "set \345\210\206\350\276\250\347\216\207 unit to DPI\n");
ret->unit = SANE_UNIT_DPI;
}
else if (strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT) == 0 ||
strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT) == 0 ||
strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_TOP) == 0 ||
strcmp(ret->name, SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM) == 0)
ret->unit = SANE_UNIT_MM;
//bool enabled = true;
//if (jsn->get_value("enable", enabled) && !enabled)
// ret->cap |= SANE_CAP_INACTIVE;
// 关联<E585B3><E88194>?
json* depend = NULL;
SLAVEOP so;
if (jsn->get_value("depend_or", depend))
{
so.is_enable = &hg_sane_middleware::is_enable_or;
}
else if (jsn->get_value("depend_and", depend))
{
so.is_enable = &hg_sane_middleware::is_enable_and;
}
if (depend)
{
if (parse_depends(depend, so))
{
so.enable_now = (ret->cap & SANE_CAP_INACTIVE) != SANE_CAP_INACTIVE;
so.option_no = opt_no;
// initializing status ...
if (so.master.size())
{
std::string master(get_option_json(h, so.master[0].option_no));
json* m = new json();
if (m->attach_text(&master[0]))
{
bool integer = false;
master = "";
m->get_value("type", master);
integer = master == "int";
master = "";
m->get_value_as_string("cur", master, integer);
so.enable_now = so.is_enable(so.master, cur_vals_);
if (!so.enable_now)
ret->cap |= SANE_CAP_INACTIVE;
}
delete m;
}
slave_options_.push_back(so);
}
delete depend;
}
}
return ret;
}
scanner_handle hg_sane_middleware::find_openning_device(SANE_Handle h, bool rmv, OPENDEV* dev)
{
scanner_handle handle = hg_sane_middleware::sane_handle_to_scanner(h);
std::vector<OPENDEV>::iterator it = std::find(openning_.begin(), openning_.end(), handle);
if (it == openning_.end())
handle = NULL;
else
{
if (dev)
*dev = *it;
if (rmv)
openning_.erase(it);
}
return handle;
}
std::string hg_sane_middleware::get_option_json(scanner_handle handle, int opt_no)
{
char* json_txt = NULL;
long length = 0;
scanner_err err = hg_scanner_get_parameter(handle, opt_no, json_txt, &length);
std::string ret("");
if (err == SCANNER_ERR_INSUFFICIENT_MEMORY)
{
json_txt = (char*)local_utility::acquire_memory(ALIGN_INT(length + 4), "hg_sane_middleware::get_option_json");
bzero(json_txt, length + 4);
err = hg_scanner_get_parameter(handle, opt_no, json_txt, &length);
if (err == SCANNER_ERR_OK)
{
ret = json_txt;
}
free(json_txt);
}
return ret;
}
SANE_Option_Descriptor* hg_sane_middleware::find_stored_descriptor(const char* name, int option)
{
for (size_t i = 0; i < opts_.size(); ++i)
{
if (opts_[i].dev_name == name && opts_[i].option_no == option)
return opts_[i].desc;
}
return NULL;
}
SANE_Option_Descriptor* hg_sane_middleware::find_stored_descriptor(SANE_Handle handle, int option)
{
OPENDEV dev;
scanner_handle h = find_openning_device(handle, false, &dev);
if (!h)
return NULL;
else
return find_stored_descriptor(dev.dev_name.c_str(), option);
}
void hg_sane_middleware::reload_current_value(scanner_handle handle, std::vector<int>* changed)
{
long count = 0;
if (changed)
changed->clear();
hg_scanner_get_parameter(handle, 0, NULL, &count);
for (int i = 1; i < count; ++i)
{
std::string val(get_option_json(handle, i));
json* jsn = new json();
if (jsn->attach_text(&val[0]) &&
jsn->get_value("type", val))
{
if (refresh_current_value(i, jsn))
changed->push_back(i);
}
delete jsn;
}
}
bool hg_sane_middleware::get_current_value(scanner_handle handle, int option, void* value, SANE_Value_Type* type)
{
std::string val(get_option_json(handle, option));
json* jsn = new json();
int estimate = 20;
bool ret = false;
if (jsn->attach_text(&val[0]) &&
jsn->get_value("type", val))
{
SANE_Value_Type t = SANE_TYPE_STRING;
std::string name("");
jsn->get_value("name", name);
ret = true;
if (val == "int")
{
int v = 0;
jsn->get_value("cur", v);
*((SANE_Int*)value) = v;
t = SANE_TYPE_INT;
}
else if (val == "bool")
{
bool yesorno = false;
jsn->get_value("cur", yesorno);
*(SANE_Bool*)value = yesorno;
t = SANE_TYPE_BOOL;
}
else if (val == "float")
{
double v = .0f;
jsn->get_value("cur", v);
*((SANE_Fixed*)value) = hg_sane_middleware::double_2_sane_fixed(v);
t = SANE_TYPE_FIXED;
}
else
{
val = "";
jsn->get_value("cur", val);
strcpy((char*)value, val.c_str());
estimate += val.length();
}
if (type)
*type = t;
refresh_current_value(option, jsn);
jsn->get_value("title", val);
VLOG_MINI_3(LOG_LEVEL_ALL, "<--Get option(%d - %s) value: %s\n", option, val.c_str(), hg_sane_middleware::option_value_2_string(t, value).c_str());
}
delete jsn;
return ret;
}
void* hg_sane_middleware::get_default_value(scanner_handle handle, int option)
{
std::string val(get_option_json(handle, option));
void* data = nullptr;
json* jsn = new json();
if (jsn->attach_text(&val[0]) &&
jsn->get_value("type", val))
{
if (val == "bool")
{
bool v = false;
jsn->get_value("default", v);
data = local_utility::acquire_memory(sizeof(v), "");
memcpy(data, &v, sizeof(v));
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "option %d default value is: %s\n", option, v ? "true" : "false");
}
else if (val == "int")
{
int v = 0;
jsn->get_value("default", v);
data = local_utility::acquire_memory(sizeof(v), "");
memcpy(data, &v, sizeof(v));
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "option %d default value is: %d\n", option, v);
}
else if (val == "float")
{
double v = .0f;
jsn->get_value("default", v);
data = local_utility::acquire_memory(sizeof(v), "");
memcpy(data, &v, sizeof(v));
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "option %d default value is: %f\n", option, v);
}
else if (val == "string")
{
int size = 0;
jsn->get_value("size", size);
val = "";
jsn->get_value("default", val);
if (size < val.length())
size = val.length();
data = local_utility::acquire_memory(size + 4, "");
strcpy((char*)data, val.c_str());
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "option %d default value is: %s\n", option, (char*)data);
}
else
{
VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "option %d type is '%s' and cannot be set value.\n", option, val.c_str());
}
}
delete jsn;
if (!data && std_opt_)
{
data = std_opt_->get_default_value(handle, option);
}
return data;
}
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 = NULL;
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; // 为两次hg_scanner_enum间隙可能新增的设备预留空<E79599><E7A9BA>?
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)
{
free(dev);
dev = NULL;
}
}
if (hgerr == SCANNER_ERR_OK)
{
*device_list = hg_sane_middleware::to_sane_device(dev, count);
if (dev)
free(dev);
}
else
ret = local_utility::scanner_err_2_sane_statu(hgerr);
if (hg_sane_middleware::dev_list_)
free(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)
{
char rsc[128];
SANE_Status ret = SANE_STATUS_GOOD;
bzero(rsc, sizeof(rsc));
ret = open(devicename, handle, NULL, NULL, NULL, rsc);
if (ret == SANE_STATUS_ACCESS_DENIED && rsc[0])
{
SANEAUTH auth;
bzero(&auth, sizeof(auth));
auth.resource = rsc;
if (local_utility::ui_cb(NULL, SANE_EVENT_NEED_AUTH, (void*)&auth, NULL, NULL))
{
return SANE_STATUS_CANCELLED;
}
ret = open(devicename, handle, auth.name, auth.pwd, auth.method, rsc);
}
return ret;
}
SANE_Status hg_sane_middleware::close_device(SANE_Handle h)
{
scanner_handle hs = find_openning_device(h, true);
SANE_Status err = SANE_STATUS_GOOD;
if (hs)
err = local_utility::scanner_err_2_sane_statu(hg_scanner_close(hs, true));
if (err == SANE_STATUS_GOOD)
on_device_closed(hs);
return err;
}
SANE_Status hg_sane_middleware::get_image_parameters(SANE_Handle handle, SANE_Parameters* params)
{
scanner_handle h = find_openning_device(handle);
scanner_err err = SCANNER_ERR_NOT_START;
if (!params)
return SANE_STATUS_INVAL;
err = hg_scanner_get_img_info(h, params, sizeof(*params));
return local_utility::scanner_err_2_sane_statu(err);
}
SANE_Status hg_sane_middleware::start(SANE_Handle h, void* async_event)
{
OPENDEV dev;
scanner_handle hs = find_openning_device(h, false, &dev);
scanner_err err = SCANNER_ERR_INVALID_PARAMETER;
if(hs)
err = hg_scanner_start(hs, async_event, dev.scan_count);
return local_utility::scanner_err_2_sane_statu(err);
}
SANE_Status hg_sane_middleware::read(SANE_Handle h, void* buf, int* bytes)
{
scanner_handle hs = find_openning_device(h);
scanner_err err = SCANNER_ERR_INVALID_PARAMETER;
long r = bytes ? *bytes : 0;
if (bytes && hs)
{
err = hg_scanner_read_img_data(hs, (unsigned char*)buf, &r);
*bytes = r;
}
return local_utility::scanner_err_2_sane_statu(err);
}
SANE_Status hg_sane_middleware::stop(SANE_Handle h)
{
scanner_handle hs = find_openning_device(h);
if(hs)
hg_scanner_stop(hs);
return SANE_STATUS_GOOD;
}
SANE_Option_Descriptor* hg_sane_middleware::get_option_descriptor(SANE_Handle h, SANE_Int option)
{
OPENDEV dev;
scanner_handle handle = find_openning_device(h, false, &dev);
SANE_Option_Descriptor* ret = NULL;
if (!handle)
return NULL;
if (option == 0)
{
if (!opt_0_)
{
opt_0_ = (SANE_Option_Descriptor*)local_utility::acquire_memory(sizeof(SANE_Option_Descriptor), "");
opt_0_->cap = SANE_CAP_SOFT_DETECT;
opt_0_->name = "option-count";
opt_0_->title = "";
opt_0_->desc = "Number of options";
opt_0_->type = SANE_TYPE_INT;
opt_0_->size = sizeof(SANE_TYPE_INT);
}
LOG_INFO(LOG_LEVEL_DEBUG_INFO, "get_option_descriptor(0)\n");
return opt_0_;
}
ret = find_stored_descriptor(dev.dev_name.c_str(), option);
if (!ret)
{
std::string json_txt(get_option_json(handle, option));
if (json_txt.length())
{
json* jsn = new json();
if (jsn->attach_text(&json_txt[0]))
{
ret = from_json(handle, jsn, option);
if (ret)
{
DEVOPT devopt;
devopt.dev_name = dev.dev_name;
devopt.option_no = option;
devopt.desc = ret;
opts_.push_back(devopt);
refresh_current_value(option, jsn);
}
}
delete jsn;
}
}
if (ret)
{
if (std_opt_)
std_opt_->init_known_opt(option, ret);
}
else if (std_opt_)
ret = std_opt_->get_option(option);
return ret;
}
SANE_Status hg_sane_middleware::set_option(SANE_Handle h, SANE_Int option, SANE_Action action, void* value, SANE_Int* after_do)
{
OPENDEV dev;
scanner_handle handle = find_openning_device(h, false, &dev);
if (!handle || (action == SANE_ACTION_GET_VALUE && !value))
return SANE_STATUS_INVAL;
if (action == SANE_ACTION_GET_VALUE)
{
if (after_do)
*after_do = 0;
SANE_Status ret = SANE_STATUS_IO_ERROR;
if (option == 0)
{
long count = 0;
hg_scanner_get_parameter(handle, option, NULL, &count);
*((SANE_Int*)value) = count;
ret = SANE_STATUS_GOOD;
VLOG_MINI_1(LOG_LEVEL_WARNING, "get option count = %d.\n", count);
}
else
{
if (std_opt_ && std_opt_->is_known_option(option))
{
std_opt_->get_value(h, option, value);
ret = SANE_STATUS_GOOD;
}
else if(get_current_value(handle, option, value))
ret = SANE_STATUS_GOOD;
}
return ret;
}
else
{
SANE_Option_Descriptor* desc = find_stored_descriptor(dev.dev_name.c_str(), option);
bool release_value = false;
scanner_err err = SCANNER_ERR_OK;
SANE_Status status = SANE_STATUS_GOOD;
std::string prev(""), v("");
if (std_opt_ && std_opt_->is_known_option(option, &desc))
{
SANE_Option_Descriptor* known = std_opt_->get_option(option);
prev = hg_sane_middleware::option_value_2_string(known->type, value);
err = std_opt_->set_value(handle, option, value);
v = hg_sane_middleware::option_value_2_string(known->type, value);
}
else
{
if (!desc)
{
VLOG_MINI_1(LOG_LEVEL_FATAL, "Option descriptor %d not found.\n", option);
return SANE_STATUS_UNSUPPORTED;
}
else if (!value && desc->type != SANE_TYPE_BUTTON)
{
if (action == SANE_ACTION_SET_AUTO) // we assume the driver can set the option properbly, and no work to do
{
VLOG_MINI_2(LOG_LEVEL_WARNING, "Option %d(%s) call SANE_ACTION_SET_AUTO, we set default value.\n", option, desc->title);
value = get_default_value(handle, option);
if (!value)
return SANE_STATUS_GOOD;
release_value = true;
}
else
{
VLOG_MINI_2(LOG_LEVEL_WARNING, "Option descriptor %d(%s) need a value!.\n", option, desc->title);
return SANE_STATUS_INVAL;
}
}
void* pass = value;
double dv = .0f;
bool bv = false;
int size = desc->size;
prev = hg_sane_middleware::option_value_2_string(desc->type, value);
if (desc->type == SANE_TYPE_BOOL)
{
bv = *((SANE_Bool*)value) == SANE_TRUE;
pass = &bv;
size = sizeof(bv);
}
else if (desc->type == SANE_TYPE_FIXED)
{
dv = hg_sane_middleware::sane_fixed_2_double(*((SANE_Fixed*)value));
pass = &dv;
size = sizeof(dv);
}
err = hg_scanner_set_parameter(handle, option, pass, size);
if (desc->type == SANE_TYPE_BOOL)
{
*((SANE_Bool*)value) = bv ? SANE_TRUE : SANE_FALSE;
}
else if (desc->type == SANE_TYPE_FIXED)
{
*((SANE_Fixed*)value) = hg_sane_middleware::double_2_sane_fixed(dv);
}
v = hg_sane_middleware::option_value_2_string(desc->type, value);
}
if (prev == v)
{
VLOG_MINI_3(LOG_LEVEL_ALL, "-->Set option(%d - %s) value: %s\n", option, desc->title, v.c_str());
}
else
{
VLOG_4(LOG_LEVEL_ALL, 512, "-->Set option(%d - %s) value: %s(Applied: %s)\n", option, desc->title, prev.c_str(), v.c_str());
}
if (err == SCANNER_ERR_OK)
{
err = (scanner_err)something_after_do(handle, dev.dev_name.c_str(), option, v.c_str());
}
else if (err == SCANNER_ERR_NOT_EXACT)
{
err = (scanner_err)(something_after_do(handle, dev.dev_name.c_str(), option, v.c_str()) | SANE_INFO_INEXACT);
}
else if (err == SCANNER_ERR_CONFIGURATION_CHANGED)
{
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "the setting '%s' affects other options value, RELOAD ...\n", desc->title);
on_SCANNER_ERR_CONFIGURATION_CHANGED(handle, dev.dev_name.c_str());
err = (scanner_err)SANE_INFO_RELOAD_OPTIONS;
}
else if (err == SCANNER_ERR_ACCESS_DENIED)
status = SANE_STATUS_ACCESS_DENIED;
else
status = SANE_STATUS_INVAL;
if (after_do)
*after_do = err;
if (release_value)
local_utility::free_memory(value);
return status;
}
}
bool hg_sane_middleware::get_cur_value(SANE_Handle handle, int option, void* value, SANE_Value_Type* type)
{
scanner_handle h = find_openning_device(handle);
if (!h)
return false;
return get_current_value(h, option, value, type);
}
void* hg_sane_middleware::get_def_value(SANE_Handle handle, int option)
{
scanner_handle h = find_openning_device(handle);
if (!h)
return NULL;
return get_default_value(h, option);
}
SANE_Status hg_sane_middleware::io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len)
{
OPENDEV od;
scanner_handle handle = find_openning_device(h, false, &od);
// commented at 2022-03-23 for getting app about info before open any device
//
//if (!handle)
// return SANE_STATUS_INVAL;
int ret = hg_scanner_control(handle, code, data, len);
if (ret == SCANNER_ERR_CONFIGURATION_CHANGED)
{
int nc = code;
VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "the setting '0x%08x' affects other options value, RELOAD ...\n", nc);
on_SCANNER_ERR_CONFIGURATION_CHANGED(handle, od.dev_name.c_str());
}
return local_utility::scanner_err_2_sane_statu(ret);
}
/// <summary>
/// 关联项处<E9A1B9><E5A484>?
bool hg_sane_middleware::compare_val_equal(const char* cur_val, const char* limit_l, const char* limit_r)
{
return strcmp(cur_val, limit_l) == 0;
}
bool hg_sane_middleware::compare_val_not_equal(const char* cur_val, const char* limit_l, const char* limit_r)
{
return !hg_sane_middleware::compare_val_equal(cur_val, limit_l, limit_r);
}
bool hg_sane_middleware::compare_val_great(const char* cur_val, const char* limit_l, const char* limit_r)
{
return atof(cur_val) > atof(limit_l);
}
bool hg_sane_middleware::compare_val_not_less(const char* cur_val, const char* limit_l, const char* limit_r)
{
return !hg_sane_middleware::compare_val_less(cur_val, limit_l, limit_r);
}
bool hg_sane_middleware::compare_val_less(const char* cur_val, const char* limit_l, const char* limit_r)
{
return atof(cur_val) < atof(limit_l);
}
bool hg_sane_middleware::compare_val_not_great(const char* cur_val, const char* limit_l, const char* limit_r)
{
return !hg_sane_middleware::compare_val_great(cur_val, limit_l, limit_r);
}
bool hg_sane_middleware::compare_val_between(const char* cur_val, const char* limit_l, const char* limit_r)
{
return atof(limit_l) < atof(cur_val) && atof(cur_val) < atof(limit_r);
}
bool hg_sane_middleware::compare_val_not_between(const char* cur_val, const char* limit_l, const char* limit_r)
{
return !hg_sane_middleware::compare_val_between(cur_val, limit_l, limit_r);
}
bool hg_sane_middleware::is_enable_and(const std::vector<MASTEROP>& master, std::vector<CURVAL>& curvals)
{
// NOTE: logical operator '&&' should get all master's value to check, here we only consider ONE master !!!!
bool enabled = true;
for (size_t i = 0; enabled && i < master.size(); ++i)
{
std::vector<CURVAL>::iterator it = std::find(curvals.begin(), curvals.end(), master[i].option_no);
if (it == curvals.end())
{
VLOG_MINI_1(LOG_LEVEL_WARNING, "option %d's current value is not found, other options depend it maybe in wrong status.\n", master[i].option_no);
continue;
}
enabled &= master[i].compare_val(it->val.c_str(), master[i].limit_l.c_str(), master[i].limit_r.c_str());
}
return enabled;
}
bool hg_sane_middleware::is_enable_or(const std::vector<MASTEROP>& master, std::vector<CURVAL>& curvals)
{
bool enabled = false;
for (size_t i = 0; !enabled && i < master.size(); ++i)
{
std::vector<CURVAL>::iterator it = std::find(curvals.begin(), curvals.end(), master[i].option_no);
if (it == curvals.end())
{
VLOG_MINI_1(LOG_LEVEL_WARNING, "option %d's current value is not found, other options depend it maybe in wrong status.\n", master[i].option_no);
continue;
}
enabled |= master[i].compare_val(it->val.c_str(), master[i].limit_l.c_str(), master[i].limit_r.c_str());
}
return enabled;
}
bool hg_sane_middleware::parse_master_option(const char* depend_str, MASTEROP& mo)
{
bool ret = true;
double num = .0f;
mo.option_no = 0;
mo.compare_val = &hg_sane_middleware::compare_val_equal;
mo.limit_l = mo.limit_r = "";
local_utility::skip_space(depend_str);
ret = local_utility::get_number(depend_str, num);
if (ret)
{
mo.option_no = num;
local_utility::skip_space(depend_str);
if (*depend_str == '=')
{
depend_str++;
if (*depend_str == '=')
{
depend_str++;
if (*depend_str == '[')
{
ret = local_utility::get_limit(depend_str, mo.limit_l, mo.limit_r);
mo.compare_val = &hg_sane_middleware::compare_val_between;
}
else
{
mo.compare_val = &hg_sane_middleware::compare_val_equal;
mo.limit_l = depend_str;
}
}
else
{
ret = false;
}
}
else if (*depend_str == '>')
{
depend_str++;
if (*depend_str == '=')
{
depend_str++;
mo.compare_val = &hg_sane_middleware::compare_val_not_less;
}
else
{
mo.compare_val = &hg_sane_middleware::compare_val_great;
}
mo.limit_l = depend_str;
}
else if (*depend_str == '<')
{
depend_str++;
if (*depend_str == '=')
{
depend_str++;
mo.compare_val = &hg_sane_middleware::compare_val_not_great;
}
else
{
mo.compare_val = &hg_sane_middleware::compare_val_less;
}
mo.limit_l = depend_str;
}
else if (*depend_str == '!')
{
depend_str++;
if (*depend_str == '=')
{
depend_str++;
if (*depend_str == '[')
{
ret = local_utility::get_limit(depend_str, mo.limit_l, mo.limit_r);
mo.compare_val = &hg_sane_middleware::compare_val_not_between;
}
else
{
mo.compare_val = &hg_sane_middleware::compare_val_not_equal;
mo.limit_l = depend_str;
}
}
else
{
ret = false;
}
}
else
{
ret = false;
}
}
return ret;
}
bool hg_sane_middleware::parse_depends(json* jsn, SLAVEOP& so)
{
std::string val("");
bool ret = jsn->first_child(val);
while(ret)
{
MASTEROP mo;
ret = parse_master_option(val.c_str(), mo);
if (!ret)
break;
so.master.push_back(mo);
if (std::find(master_options_.begin(), master_options_.end(), mo.option_no) == master_options_.end())
{
master_options_.push_back(mo.option_no);
std::sort(master_options_.begin(), master_options_.end());
}
ret = jsn->next_child(val);
}
return so.master.size() > 0;
}
bool hg_sane_middleware::is_associatived(const SLAVEOP& slave, int master_opt)
{
bool result = false;
for (size_t i = 0; i < slave.master.size(); ++i)
{
if (slave.master[i].option_no == master_opt)
{
result = true;
break;
}
}
return result;
}
bool hg_sane_middleware::set_stored_option_enabled(const char* dev_name, int option, bool enable, int* size)
{
SANE_Option_Descriptor* opt = find_stored_descriptor(dev_name, option);
bool ret = false;
if (opt)
{
if(size)
*size = opt->size;
ret = true;
if (enable)
opt->cap &= ~SANE_CAP_INACTIVE;
else
opt->cap |= SANE_CAP_INACTIVE;
}
return ret;
}
int hg_sane_middleware::something_after_do(scanner_handle h, const char* dev_name, int option_no, const char* cur_val)
{
int after = 0;
OPTENABLE oe;
std::vector<OPTENABLE> changed_options;
refresh_current_value(option_no, cur_val);
if (std::find(master_options_.begin(), master_options_.end(), option_no) == master_options_.end())
{
return after;
}
oe.opt_no = option_no;
oe.enable = true;
changed_options.push_back(oe);
for (size_t i = 0; i < changed_options.size(); ++i)
{
for (size_t slave = 0; slave < slave_options_.size(); ++slave)
{
if (slave_options_[slave].option_no == changed_options[i].opt_no ||
!is_associatived(slave_options_[slave], changed_options[i].opt_no))
continue;
bool enable = changed_options[i].enable;
int bytes = 0;
if (enable)
enable = slave_options_[slave].is_enable(slave_options_[slave].master, cur_vals_);
if (enable == slave_options_[slave].enable_now)
continue;
slave_options_[slave].enable_now = enable;
if (!set_stored_option_enabled(dev_name, slave_options_[slave].option_no, enable, &bytes))
continue;
OPTEN* op = get_control_enalbe_data(slave_options_[slave]);
hg_scanner_control(h, HG_CONTROL_CODE_OPTION_ENABLE, op, NULL);
free_control_enable_data(op);
if (std::find(changed_options.begin(), changed_options.end(), slave_options_[slave].option_no) != changed_options.end())
continue;
oe.opt_no = slave_options_[slave].option_no;
oe.enable = slave_options_[slave].enable_now;
changed_options.push_back(oe);
}
}
if (changed_options.size() > 1)
after = SANE_INFO_RELOAD_OPTIONS;
return after;
}
bool hg_sane_middleware::refresh_current_value(int opt, json* jsn)
{
std::vector<CURVAL>::iterator it = std::find(cur_vals_.begin(), cur_vals_.end(), opt);
if (it == cur_vals_.end())
{
CURVAL cv;
jsn->get_value("type", cv.type);
cv.opt_no = opt;
jsn->get_value_as_string("cur", cv.val, cv.type == "int");
cur_vals_.push_back(cv);
return false;
}
else
{
std::string old(it->val);
jsn->get_value_as_string("cur", it->val, it->type == "int");
return old != it->val;
}
}
bool hg_sane_middleware::refresh_current_value(int opt, const char* val)
{
std::vector<CURVAL>::iterator it = std::find(cur_vals_.begin(), cur_vals_.end(), opt);
if (it != cur_vals_.end())
{
bool ret = strcmp(it->val.c_str(), val) == 0;
it->val = val;
return ret;
}
return false;
}
OPTEN* hg_sane_middleware::get_control_enalbe_data(const SLAVEOP& slave)
{
std::vector<int> master;
OPTEN* opt = NULL;
size_t size = sizeof(OPTEN);
for (size_t i = 0; i < slave.master.size(); ++i)
{
if (std::find(master.begin(), master.end(), slave.master[i].option_no) == master.end())
master.push_back(slave.master[i].option_no);
}
size += master.size() * sizeof(OPTVAL);
opt = (OPTEN*)malloc(size);
bzero(opt, size);
opt->enabled = slave.enable_now;
opt->opt_num = slave.option_no;
opt->master_count = 0;
for (size_t i = 0; i < master.size(); ++i)
{
std::vector<CURVAL>::iterator m = std::find(cur_vals_.begin(), cur_vals_.end(), master[i]);
if (m == cur_vals_.end())
continue;
opt->master[opt->master_count].opt_num = master[i];
if (m->type == "string")
{
opt->master[opt->master_count].data = malloc(m->val.length() + 4);
strcpy((char*)opt->master[opt->master_count].data, m->val.c_str());
}
else
{
opt->master[opt->master_count].data = malloc(sizeof(double));
if (m->type == "bool")
*((bool*)opt->master[opt->master_count].data) = (m->val == "true");
else if (m->type == "int")
*((int*)opt->master[opt->master_count].data) = atoi(m->val.c_str());
else
*((double*)opt->master[opt->master_count].data) = atof(m->val.c_str());
opt->master_count++;
}
}
return opt;
}
void hg_sane_middleware::free_control_enable_data(OPTEN* opt)
{
if (opt)
{
for (int i = 0; i < opt->master_count; ++i)
{
if (opt->master[i].data)
free(opt->master[i].data);
}
free(opt);
}
}
void hg_sane_middleware::on_SCANNER_ERR_CONFIGURATION_CHANGED(scanner_handle handle, const char* dev_name)
{
std::vector<int> changed;
reload_current_value(handle, &changed);
if (changed.size())
{
for (size_t i = 0; i < changed.size(); ++i)
{
std::vector<CURVAL>::iterator it = std::find(cur_vals_.begin(), cur_vals_.end(), changed[i]);
if (it != cur_vals_.end())
something_after_do(handle, dev_name, it->opt_no, it->val.c_str());
}
}
}
/// </summary>
/// <summary>
/// 导出接口
/// </summary>
extern "C" { // avoid compiler exporting name in C++ style !!!
SANE_Status inner_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize)
{
local_utility::cb_auth_ = authorize;
hg_sane_middleware::instance();
local_utility::get_version(version_code);
return SANE_STATUS_GOOD;
}
void inner_sane_exit(void)
{
hg_sane_middleware::clear();
}
SANE_Status inner_sane_get_devices(const SANE_Device*** device_list, SANE_Bool local_only)
{
SANE_Status code = hg_sane_middleware::instance()->get_devices(device_list, local_only);
return code;
}
SANE_Status inner_sane_open(SANE_String_Const devicename, SANE_Handle* handle)
{
return hg_sane_middleware::instance()->open_device(devicename, handle);
}
void inner_sane_close(SANE_Handle handle)
{
hg_sane_middleware::instance()->close_device(handle);
}
const SANE_Option_Descriptor*
inner_sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)
{
return hg_sane_middleware::instance()->get_option_descriptor(handle, option);
}
SANE_Status inner_sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void* value, SANE_Int* info)
{
return hg_sane_middleware::instance()->set_option(handle, option, action, value, info);
}
SANE_Status inner_sane_get_parameters(SANE_Handle handle, SANE_Parameters* params)
{
return hg_sane_middleware::instance()->get_image_parameters(handle, params);
}
SANE_Status inner_sane_start(SANE_Handle handle)
{
LOG_INFO(LOG_LEVEL_ALL, "sane_start\n");
return hg_sane_middleware::instance()->start(handle, NULL);
}
SANE_Status inner_sane_read(SANE_Handle handle, SANE_Byte* data, SANE_Int max_length, SANE_Int* length)
{
if (!length)
length = &max_length;
else
*length = max_length;
return hg_sane_middleware::instance()->read(handle, data, length);
}
void inner_sane_cancel(SANE_Handle handle)
{
hg_sane_middleware::instance()->stop(handle);
}
SANE_Status inner_sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)
{
LOG_INFO(LOG_LEVEL_ALL, "sane_set_io_mode\n");
return non_blocking ? SANE_STATUS_UNSUPPORTED : SANE_STATUS_GOOD;
}
SANE_Status inner_sane_get_select_fd(SANE_Handle handle, SANE_Int* fd)
{
return SANE_STATUS_UNSUPPORTED;
}
SANE_String_Const inner_sane_strstatus(SANE_Status status)
{
return hg_scanner_err_name(status);
}
SANE_Status inner_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param)
{
local_utility::set_callback(cb, param);
hg_sane_middleware::instance();
local_utility::get_version(version_code);
return SANE_STATUS_GOOD;
}
SANE_Status inner_sane_io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len)
{
return hg_sane_middleware::instance()->io_control(h, code, data, len);
}
void sanei_debug_msg(int level, int max_level, const char* be, const char* fmt, va_list ap)
{
}
}
#ifdef WIN32
BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
{
if (g_sane_path.empty())
{
char path[MAX_PATH] = { 0 };
GetModuleFileNameA(inst, path, _countof(path) - 1);
if (strrchr(path, '\\'))
{
strrchr(path, '\\')[1] = 0;
g_sane_path = path;
}
}
}
else if (reason == DLL_PROCESS_DETACH)
{
inner_sane_exit();
}
return TRUE;
}
#endif