2050 lines
54 KiB
C++
2050 lines
54 KiB
C++
#include "sane_hg_mdw.h"
|
||
#include "json.h"
|
||
#include <stdarg.h>
|
||
#include <time.h>
|
||
#include <fcntl.h>
|
||
#include <sys/stat.h>
|
||
#include <mutex>
|
||
#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"
|
||
|
||
#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("");
|
||
static std::string g_sane_name(GET_BACKEND_NAME);
|
||
|
||
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_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_HAS_DATA_YET, SANE_STATUS_IO_ERROR);
|
||
RETURN_MATCH_ERROR(hgerr, SCANNER_ERR_OUT_OF_RANGE, SANE_STATUS_NO_MEM);
|
||
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_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_HAS_DATA_YET);
|
||
RETURN_MATCH_ERROR(statu, SANE_STATUS_NO_MEM, 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);
|
||
|
||
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(g_sane_name.c_str(), sane_ver);
|
||
hg_scanner_initialize(local_utility::ui_cb, NULL);
|
||
|
||
#if !defined(WIN32) && !defined(_WIN64)
|
||
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*/;
|
||
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 = (SANE_Word)*lower;
|
||
}
|
||
if (upper)
|
||
{
|
||
if (double_val)
|
||
(*(SANE_Range*)str).max = hg_sane_middleware::double_2_sane_fixed(*upper);
|
||
else
|
||
(*(SANE_Range*)str).max = (SANE_Word)*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 < (int)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 = (int)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)
|
||
{
|
||
}
|
||
}
|
||
|
||
|
||
#if defined(WIN32) || defined(_WIN64)
|
||
HMODULE g_my_inst = NULL;
|
||
BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved)
|
||
{
|
||
if (reason == DLL_PROCESS_ATTACH)
|
||
{
|
||
g_my_inst = inst;
|
||
if (g_sane_path.empty())
|
||
{
|
||
char path[MAX_PATH] = { 0 };
|
||
|
||
GetModuleFileNameA(inst, path, _countof(path) - 1);
|
||
if (strrchr(path, '\\'))
|
||
{
|
||
g_sane_name = strrchr(path, '\\') + 1;
|
||
strrchr(path, '\\')[1] = 0;
|
||
g_sane_path = path;
|
||
if (g_sane_name.rfind('.') != std::string::npos)
|
||
g_sane_name.erase(g_sane_name.rfind('.'));
|
||
}
|
||
}
|
||
}
|
||
else if (reason == DLL_PROCESS_DETACH)
|
||
{
|
||
inner_sane_exit();
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
#endif
|