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