#include "sane_hg_mdw.h" #include "json.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 #endif #include "../../sdk/include/sane/sane_option_definitions.h" #include "sane_option.h" #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 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_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); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 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; } // 暂不支持科学计数?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; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // fixed id map static void init_fixed_id(const char* name, int id, std::map& mapid, int* fixid = nullptr) { #define TRY_MATCH(n) \ if(strcmp(SANE_STD_OPT_NAME_##n, name) == 0) \ { \ mapid[SANE_OPT_ID_##n] = id; \ if(fixid) \ *fixid = SANE_OPT_ID_##n; \ return; \ } TRY_MATCH(IS_MULTI_OUT); TRY_MATCH(MULTI_OUT_TYPE); TRY_MATCH(COLOR_MODE); TRY_MATCH(FILTER); TRY_MATCH(RID_MULTIOUT_RED); TRY_MATCH(RID_ANSWER_SHEET_RED); TRY_MATCH(ERASE_BACKGROUND); TRY_MATCH(BKG_COLOR_RANGE); TRY_MATCH(SHARPEN); TRY_MATCH(RID_MORR); TRY_MATCH(RID_GRID); TRY_MATCH(ERROR_EXTENSION); TRY_MATCH(NOISE_OPTIMIZE); TRY_MATCH(NOISE_SIZE); TRY_MATCH(PAPER); TRY_MATCH(CUSTOM_AREA); TRY_MATCH(CUSTOM_AREA_LEFT); TRY_MATCH(CUSTOM_AREA_RIGHT); TRY_MATCH(CUSTOM_AREA_TOP); TRY_MATCH(CUSTOM_AREA_BOTTOM); TRY_MATCH(SIZE_CHECK); TRY_MATCH(PAGE); TRY_MATCH(DISCARD_BLANK_SENS); TRY_MATCH(RESOLUTION); TRY_MATCH(IMAGE_QUALITY); TRY_MATCH(EXCHANGE); TRY_MATCH(SPLIT); TRY_MATCH(ANTI_SKEW); TRY_MATCH(IS_CUSTOM_GAMMA); TRY_MATCH(BRIGHTNESS); TRY_MATCH(CONTRAST); TRY_MATCH(GAMMA); TRY_MATCH(ERASE_BLACK_FRAME); TRY_MATCH(DARK_SAMPLE); TRY_MATCH(THRESHOLD); TRY_MATCH(ANTI_NOISE_LEVEL); TRY_MATCH(MARGIN); TRY_MATCH(FILL_BKG_MODE); TRY_MATCH(IS_ANTI_PERMEATE); TRY_MATCH(ANTI_PERMEATE_LEVEL); TRY_MATCH(RID_HOLE); TRY_MATCH(SEARCH_HOLE_RANGE); TRY_MATCH(IS_FILL_COLOR); TRY_MATCH(IS_ULTROSONIC_CHECK); TRY_MATCH(IS_CHECK_STAPLE); TRY_MATCH(SCAN_MODE); TRY_MATCH(SCAN_COUNT); TRY_MATCH(TEXT_DIRECTION); TRY_MATCH(IS_ROTATE_BKG_180); TRY_MATCH(IS_CHECK_DOG_EAR); TRY_MATCH(DOG_EAR_SIZE); TRY_MATCH(IS_CHECK_ASKEW); TRY_MATCH(ASKEW_RANGE); TRY_MATCH(BINARY_THRESHOLD); TRY_MATCH(IS_PHOTO_MODE); TRY_MATCH(DOUBLE_FEED_HANDLE); TRY_MATCH(WAIT_TO_SCAN); TRY_MATCH(FEED_STRENGTH); TRY_MATCH(TIME_TO_SLEEP); TRY_MATCH(IS_AUTO_FEED_STRENGTH); TRY_MATCH(FEED_STRENGTH_VALUE); TRY_MATCH(REVERSE_01); TRY_MATCH(RID_HOLE_L); TRY_MATCH(SEARCH_HOLE_RANGE_L); TRY_MATCH(RID_HOLE_R); TRY_MATCH(SEARCH_HOLE_RANGE_R); TRY_MATCH(RID_HOLE_T); TRY_MATCH(SEARCH_HOLE_RANGE_T); TRY_MATCH(RID_HOLE_B); TRY_MATCH(SEARCH_HOLE_RANGE_B); TRY_MATCH(FOLD_TYPE); TRY_MATCH(COLOR_CORRECTION); TRY_MATCH(LANGUAGE); TRY_MATCH(INITIAL_BOOT_TIME); //TRY_MATCH(HISTORY_COUNT); //TRY_MATCH(DRIVER_VERSION); //TRY_MATCH(MANUFACTURER); //TRY_MATCH(COPYRIGHT); //TRY_MATCH(CO_URL); //TRY_MATCH(CO_TEL); //TRY_MATCH(CO_ADDR); //TRY_MATCH(CO_GPS); //TRY_MATCH(HELP); //TRY_MATCH(VID); //TRY_MATCH(PID); //TRY_MATCH(DEV_NAME); //TRY_MATCH(DEV_FAMILY); //TRY_MATCH(LOGIN); //TRY_MATCH(LOGOUT); //TRY_MATCH(ROLLER_COUNT); //TRY_MATCH(DRIVER_LOG); //TRY_MATCH(DEVICE_LOG); } static std::string un_json_option_name(int id, int *len) { int tmp = sizeof(int); if (!len) len = &tmp; #define FIX_ID_TO_NAME(fid, l) \ if(id == SANE_OPT_ID_##fid) \ { \ *len = l; \ return SANE_STD_OPT_NAME_##fid; \ } FIX_ID_TO_NAME(HISTORY_COUNT, sizeof(int)); FIX_ID_TO_NAME(DRIVER_VERSION, 255); FIX_ID_TO_NAME(MANUFACTURER, 255); FIX_ID_TO_NAME(COPYRIGHT, 255); FIX_ID_TO_NAME(CO_URL, 255); FIX_ID_TO_NAME(CO_TEL, 255); FIX_ID_TO_NAME(CO_ADDR, 255); FIX_ID_TO_NAME(CO_GPS, 255); FIX_ID_TO_NAME(VID, sizeof(int)); FIX_ID_TO_NAME(PID, sizeof(int)); FIX_ID_TO_NAME(DEV_NAME, 255); FIX_ID_TO_NAME(DEV_FAMILY, 255); FIX_ID_TO_NAME(ROLLER_COUNT, sizeof(int)); FIX_ID_TO_NAME(HELP, sizeof(int)); FIX_ID_TO_NAME(LOGIN, 255); FIX_ID_TO_NAME(LOGOUT, 255); FIX_ID_TO_NAME(DRIVER_LOG, 255); FIX_ID_TO_NAME(DEVICE_LOG, 255); FIX_ID_TO_NAME(MOTOR_VER, 255); FIX_ID_TO_NAME(INITIAL_BOOT_TIME, 255); FIX_ID_TO_NAME(DEVICE_SERIAL_NO, 255); FIX_ID_TO_NAME(FIRMWARE_VERSION, 255); FIX_ID_TO_NAME(DEVICE_IP_ADDR, 255); FIX_ID_TO_NAME(DEVICE_MAC_ADDR, 255); FIX_ID_TO_NAME(ROLLER_LIFE, sizeof(SANE_Int)); FIX_ID_TO_NAME(CUSTOM_GAMMA, sizeof(SANE_Gamma)); FIX_ID_TO_NAME(TRANSFORM_IMAGE_FORMAT, sizeof(SANE_ImageFormatConvert)); FIX_ID_TO_NAME(FREE_BUFFER, sizeof(void*)); //FIX_ID_TO_NAME(LANGUAGE, 128); return ""; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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) { sane_callback cb_ui = NULL; void* cb_ui_parm = NULL; SANE_Auth_Callback cb_auth = NULL; { 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); // 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 lck(cb_lock_); cb_ui_ = cb; cb_ui_parm_ = param; } void stop_work(void) { std::lock_guard lck(cb_lock_); cb_ui_ = NULL; cb_ui_parm_ = NULL; cb_auth_ = NULL; } static void trans_language_if_was_word_id(std::string& val) { size_t pos = val.find("."); if (pos != std::string::npos) { bool num = true; for (size_t i = pos + 1; i < val.length(); ++i) { if (val[i] != '0') { num = false; break; } } if (num && std::to_string(atoi(val.c_str())) == val.substr(0, pos)) { val = lang_load_string(atoi(val.c_str()), nullptr); } } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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), init_ok_(false) { char sane_ver[40] = { 0 }; init_ok_ = true; 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); register_language_changed_notify(&hg_sane_middleware::language_changed, true); #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() { register_language_changed_notify(&hg_sane_middleware::language_changed, false); for (size_t i = 0; i < openning_.size(); ++i) { hg_scanner_close(openning_[i]->dev, true); hg_sane_middleware::free_device_inst(openning_[i]); } hg_scanner_uninitialize(); if (opt_0_) local_utility::free_memory(opt_0_); } void hg_sane_middleware::language_changed(int cp, void* param) { hg_sane_middleware::instance()->reload_options(); //for (auto& v : hg_sane_middleware::instance()->openning_) //{ // hg_sane_middleware::free_device_inst(v, false); // // long count = 0; // hg_scanner_get_parameter(v->dev, nullptr, NULL, &count); // for (long ind = 1; ind < count; ++ind) // hg_sane_middleware::instance()->get_option_descriptor(hg_sane_middleware::scanner_handle_to_sane(v->dev), (void*)ind); //} } 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); } void hg_sane_middleware::set_value_to_var(void* val, size_t bytes, void* param) { memcpy(param, val, bytes); } void hg_sane_middleware::set_value_to_new(void* val, size_t bytes, void* param) { void** addr = (void**)param; *addr = local_utility::acquire_memory(bytes, "set_value_to_new"); memcpy(*addr, val, bytes); } 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; } 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); } SANE_Option_Descriptor* hg_sane_middleware::allocate_descriptor(const char* name, const char* title, const char* desc) { SANE_Option_Descriptor* opdesc = (SANE_Option_Descriptor*)local_utility::acquire_memory(sizeof(SANE_Option_Descriptor), "SANE_Option_Descriptor"); memset(opdesc, 0, sizeof(SANE_Option_Descriptor)); opdesc->name = (char*)local_utility::acquire_memory(strlen(name) + 1, "SANE_Option_Descriptor::name"); strcpy((char*)opdesc->name, name); opdesc->title = (char*)local_utility::acquire_memory(strlen(title) + 1, "SANE_Option_Descriptor::title"); strcpy((char*)opdesc->title, title); opdesc->desc = (char*)local_utility::acquire_memory(strlen(desc) + 1, "SANE_Option_Descriptor::desc"); strcpy((char*)opdesc->desc, desc); return opdesc; } void hg_sane_middleware::free_descriptor(SANE_Option_Descriptor* desc) { if (desc) { if (desc->name) local_utility::free_memory((void*)desc->name); desc->name = nullptr; if (desc->title) local_utility::free_memory((void*)desc->title); desc->title = nullptr; if (desc->desc) local_utility::free_memory((void*)desc->desc); desc->desc = nullptr; if (desc->constraint.range) local_utility::free_memory((void*)desc->constraint.range); desc->constraint.range = nullptr; local_utility::free_memory(desc); } } SANE_Option_Descriptor* hg_sane_middleware::string_option_to_SANE_descriptor(const char* name, const char* title, const char* desc , const std::vector& values) { int bytes = (values.size() + 1) * sizeof(SANE_String); SANE_Option_Descriptor *sod = hg_sane_middleware::allocate_descriptor(name, title, desc); for (size_t i = 0; i < values.size(); ++i) bytes += ALIGN_INT(values[i].length() + 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; // 硬件可设置默认�? if (values.size()) { SANE_String* buf = (SANE_String*)local_utility::acquire_memory(bytes, "string_list"); char* str = (char*)buf + (values.size() + 1) * sizeof(SANE_String); sod->constraint_type = SANE_CONSTRAINT_STRING_LIST; sod->constraint.string_list = buf; for (size_t i = 0; i < values.size(); ++i) { buf[i] = str; strcpy(str, values[i].c_str()); str += ALIGN_INT(values[i].length() + 1); } } 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, double* step) { int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range); SANE_Option_Descriptor *sod = hg_sane_middleware::allocate_descriptor(name, title, desc); 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; SANE_Range* range = (SANE_Range*)local_utility::acquire_memory(sizeof(SANE_Range), "constraint.range"); if (lower) { if (double_val) range->min = hg_sane_middleware::double_2_sane_fixed(*lower); else range->min = (SANE_Word)*lower; } if (upper) { if (double_val) range->max = hg_sane_middleware::double_2_sane_fixed(*upper); else range->max = (SANE_Word)*upper; } range->quant = 0; if (step) { if(double_val) range->quant = hg_sane_middleware::double_2_sane_fixed(*step); else range->quant = (SANE_Word)(*step); } sod->constraint.range = range; } 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& values) { int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range); SANE_Option_Descriptor* sod = hg_sane_middleware::allocate_descriptor(name, title, desc); 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; // 硬件可设置默认�? if (values.size()) { sod->constraint.word_list = (SANE_Word*)local_utility::acquire_memory(sizeof(SANE_Word) * (values.size() + 1), "word_list"); SANE_Word* val = (SANE_Word*)sod->constraint.word_list; sod->constraint_type = SANE_CONSTRAINT_WORD_LIST; *val++ = values.size(); for (size_t i = 0; i < values.size(); ++i) val[i] = values[i]; } //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& values) { int bytes = sizeof(SANE_Option_Descriptor) + sizeof(SANE_Range); SANE_Option_Descriptor* sod = hg_sane_middleware::allocate_descriptor(name, title, desc); 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; // 硬件可设置默认�? if (values.size()) { sod->constraint.word_list = (SANE_Word*)local_utility::acquire_memory(sizeof(SANE_Word) * (values.size() + 1), "word_list"); SANE_Word* val = (SANE_Word*)sod->constraint.word_list; 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]); } return sod; } std::string hg_sane_middleware::get_string_in_json(json* jsn, const char* key) { std::string str(""); int id = -1; if (jsn->get_value(key, id) && id != -1) { str = lang_load_string(id, &id); } else jsn->get_value(key, str); return std::move(str); } 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; } } void hg_sane_middleware::reload_options(scanner_handle dev) { for (auto& v : openning_) { if (dev && dev != v->dev) continue; std::vector opts(std::move(v->opts)); long count = 0; hg_sane_middleware::free_device_inst(v, false); hg_scanner_get_parameter(v->dev, nullptr, NULL, &count); for (long ind = 1; ind < count; ++ind) { get_option_descriptor(hg_sane_middleware::scanner_handle_to_sane(v->dev), (void*)ind); int n = v->opts.size() - 1; if (n >= 0) { for (int i = 0; i < opts.size(); ++i) { if (v->opts[n].opt_name == opts[i].opt_name) { local_utility::free_memory((void*)opts[i].desc->name); local_utility::free_memory((void*)opts[i].desc->title); local_utility::free_memory((void*)opts[i].desc->desc); local_utility::free_memory((void*)opts[i].desc->constraint.range); *opts[i].desc = *v->opts[n].desc; v->opts[n].desc->name = v->opts[n].desc->title = v->opts[n].desc->desc = nullptr; v->opts[n].desc->constraint.range = nullptr; hg_sane_middleware::free_descriptor(v->opts[n].desc); v->opts[n].desc = opts[i].desc; opts.erase(opts.begin() + i); break; } } } } // do depend logic opertion ... for (auto& d : v->slaves) { SANE_Option_Descriptor* desc = get_option_descriptor(hg_sane_middleware::scanner_handle_to_sane(v->dev), &d.name[0]); set_status_by_depends(v->dev, d, v->cur_vals, desc); } } } void hg_sane_middleware::set_status_by_depends(scanner_handle hdev, SLAVEOP& so, std::vector& vals, SANE_Option_Descriptor* desc) { if (so.master.size()) { so.enable_now = so.is_enable(hdev, so.master, vals); if (so.enable_now) desc->cap &= ~SANE_CAP_INACTIVE; else desc->cap |= SANE_CAP_INACTIVE; } } 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) { LPDEVINST inst = new DEVINST; inst->name = devicename; inst->dev = h; openning_.push_back(inst); *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); inst->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)err; // SANE_STATUS_UNSUPPORTED; } SANE_Option_Descriptor* hg_sane_middleware::from_json(scanner_handle h, const std::string& name, json* jsn) { std::string title(hg_sane_middleware::get_string_in_json(jsn, "title")), desc(hg_sane_middleware::get_string_in_json(jsn, "desc")), val(""); std::vector constraints; double lower = .0f, upper = .0f, step = .0f; bool db_val = false; int opt_val_size = 0; if (!jsn->get_value("type", val)) return NULL; SANE_Option_Descriptor* ret = NULL; if (val == "string") { json* range = NULL; std::vector constraints; jsn->get_value("range", range); if (range) { if (range->first_child(val)) { local_utility::trans_language_if_was_word_id(val); constraints.push_back(val); opt_val_size = val.length(); while (range->next_child(val)) { local_utility::trans_language_if_was_word_id(val); constraints.push_back(val); if (opt_val_size < val.length()) opt_val_size = val.length(); } } 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, s = 1; range->get_value("max", u); range->get_value("step", s); lower = l; upper = u; step = s; VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "%s range: [%d, +%d, %d]\n", name.c_str(), l, s, u); ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str() , false, &lower, &upper, &step); } else { std::vector 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); step = (upper - lower) / 10.0f; range->get_value("step", step); VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "%s range: (%f, +%f, %f)\n", name.c_str(), lower, step, upper); ret = hg_sane_middleware::number_option_to_SANE_descriptor(name.c_str(), title.c_str(), desc.c_str() , true, &lower, &upper, &step); } else { std::vector 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, 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, 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, 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, NULL); ret->type = SANE_TYPE_GROUP; } // fill the 'size' field, for SANE_ACTION_GET action ... if (ret) { int bytes = 0; bool bv = false; jsn->get_value("size", bytes); if (bytes < opt_val_size) { opt_val_size = ALIGN_INT(opt_val_size + 4); VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "Resize size of '%s' from %d to %d\n", name.c_str(), bytes, opt_val_size); bytes = opt_val_size; } ret->size = bytes; if (jsn->get_value("readonly", bv) && bv) SET_CAP_READONLY(ret->cap) val = ""; jsn->get_value("cat", val); if (val == "advanced") { ret->cap |= SANE_CAP_ADVANCED; } if (strcmp(ret->name, SANE_STD_OPT_NAME_RESOLUTION) == 0) { 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; // 关联? 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) { std::vector::iterator it = find_openning_device_in_que(h); if (it != openning_.end() && parse_depends(h, depend, so, (*it)->masters)) { so.enable_now = (ret->cap & SANE_CAP_INACTIVE) != SANE_CAP_INACTIVE; so.name = name; // initializing status ... move to set_status_by_depends (2023-06-21) //if (so.master.size()) //{ // //std::string master(get_option_json(h, (void *)so.master[0].name.c_str())); // //json* m = new json(); // //if (m->attach_text(&master[0])) // //{ // // bool integer = false, str = false; // // // master = ""; // // m->get_value("type", master); // // integer = master == "int"; // // str = master == "string"; // // master = ""; // // m->get_value_as_string("cur", master, integer); // // local_utility::trans_language_if_was_word_id(val); // so.enable_now = so.is_enable(h, so.master, (*it)->cur_vals); // if (!so.enable_now) // ret->cap |= SANE_CAP_INACTIVE; // //} // //delete m; //} (*it)->slaves.push_back(so); } delete depend; } } return ret; } void hg_sane_middleware::free_device_inst(LPDEVINST dev, bool del) { for (auto& v : dev->opts) hg_sane_middleware::free_descriptor(v.desc); if (del) { if (dev->std_opt) delete dev->std_opt; delete dev; } else { if (dev->std_opt) dev->std_opt->clear(); dev->opts.clear(); dev->cur_vals.clear(); dev->slaves.clear(); dev->masters.clear(); } } scanner_handle hg_sane_middleware::find_openning_device(SANE_Handle h, bool rmv, LPDEVINST* dev) { scanner_handle handle = hg_sane_middleware::sane_handle_to_scanner(h); std::vector::iterator it = find_openning_device_in_que(handle); if (it == openning_.end()) handle = NULL; else { if (dev) *dev = *it; if (rmv) { if (!dev) hg_sane_middleware::free_device_inst(*it); openning_.erase(it); } } return handle; } std::string hg_sane_middleware::get_option_json(scanner_handle handle, void *opt, std::string* key, SANE_Int* id) { char* json_txt = NULL; long length = 0; scanner_err err = hg_scanner_get_parameter(handle, (const char*)opt, 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, (const char*)opt, json_txt, &length, id); if (err == SCANNER_ERR_OK) { const char* head = json_txt; local_utility::skip_space(head); if (*head == '\"') { head++; while (*head != '\"' && *head) ret.append(1, *head++); if (*head) { head++; local_utility::skip_space(head); if (*head == ':') { head++; local_utility::skip_space(head); } } } if (key) *key = ret; ret = head; } free(json_txt); } return ret; } SANE_Option_Descriptor* hg_sane_middleware::find_stored_descriptor(scanner_handle handle, const void* option, SANE_Int* id, SANE_Int* fix_id) { std::vector::iterator it = find_openning_device_in_que(handle); if (it != openning_.end()) { if (IS_PTR_NUMBER(option)) { if ((SANE_Int)(long long)option >= SANE_OPT_ID_BASE) { for (const auto& v : (*it)->opts) { if (v.fixed_no == (SANE_Int)(long long)option) { if (id) *id = v.option_no; if (fix_id) *fix_id = v.fixed_no; return v.desc; } } } else { for (const auto& v : (*it)->opts) { if (v.option_no == (SANE_Int)(long long)option) { if (id) *id = v.option_no; if (fix_id) *fix_id = v.fixed_no; return v.desc; } } } } else { for (const auto& v : (*it)->opts) { if (v.opt_name == (const char*)option) { if (id) *id = v.option_no; if (fix_id) *fix_id = v.fixed_no; return v.desc; } } } } return NULL; } void hg_sane_middleware::reload_current_value(scanner_handle handle, std::vector* changed) { long count = 0; std::vector::iterator it = find_openning_device_in_que(handle); if (changed) changed->clear(); hg_scanner_get_parameter(handle, 0, NULL, &count); for (int i = 1; i < count; ++i) { std::string key(""), val(get_option_json(handle, (void *)i, &key)); json* jsn = new json(); if (jsn->attach_text(&val[0]) && jsn->get_value("type", val)) { if (refresh_current_value(*it, key.c_str(), jsn)) changed->push_back(key); } delete jsn; } } bool hg_sane_middleware::get_current_value(scanner_handle handle, const void* option, void(*setv)(void*, size_t, void*), void* value, SANE_Value_Type* type) { if (IS_PTR_NUMBER(option)) { int id = (int)(uint64_t)option, l = 0; std::string name(local_utility::un_json_option_name(id, &l)); if(!name.empty()) { char *buf = new char[l + 4]; long len = l; bool ret = false; memcpy(buf, value, l); buf[l] = 0; if (hg_scanner_get_parameter(handle, name.c_str(), buf, &len) == SCANNER_ERR_OK) { setv(buf, len, value); ret = true; } delete[] buf; return ret; } } std::string name(""), val(get_option_json(handle, (void *)option, &name)); 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; ret = true; if (val == "int") { int v = 0; jsn->get_value("cur", v); // *((SANE_Int*)value) = v; setv(&v, sizeof(v), value); t = SANE_TYPE_INT; } else if (val == "bool") { bool bv = false; SANE_Bool v = SANE_FALSE; jsn->get_value("cur", bv); // *(SANE_Bool*)value = v; v = bv; setv(&v, sizeof(v), value); t = SANE_TYPE_BOOL; } else if (val == "float") { double dv = .0f; SANE_Fixed v = 0; jsn->get_value("cur", dv); v = hg_sane_middleware::double_2_sane_fixed(dv); setv(&v, sizeof(v), value); t = SANE_TYPE_FIXED; } else { int size = 0; jsn->get_value("size", size); val = hg_sane_middleware::get_string_in_json(jsn, "cur"); if (size <= val.length()) size = val.length() + 1; //strcpy((char*)value, val.c_str()); setv(&val[0], size, value); estimate += val.length(); } if (type) *type = t; std::vector::iterator it = find_openning_device_in_que(handle); refresh_current_value(*it, name.c_str(), jsn); val = hg_sane_middleware::get_string_in_json(jsn, "title"); if (setv == &hg_sane_middleware::set_value_to_new) value = *(void**)value; 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, const void* option, int* bytes, bool log) { std::string val(get_option_json(handle, (void *)option)); void* data = nullptr; json* jsn = new json(); if (jsn->attach_text(&val[0]) && jsn->get_value("type", val)) { std::string title(hg_sane_middleware::get_string_in_json(jsn, "title")); if (val == "bool") { bool v = false; jsn->get_value("default", v); data = local_utility::acquire_memory(sizeof(SANE_Bool), ""); memcpy(data, &v, sizeof(v)); if (bytes) *bytes = sizeof(SANE_Bool); if (log) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "option %d(%s) default value is: %s\n", option, title.c_str(), 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)); if (bytes) *bytes = sizeof(v); if (log) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "option %d(%s) default value is: %d\n", option, title.c_str(), v); } } else if (val == "float") { double v = .0f; jsn->get_value("default", v); SANE_Fixed sd = hg_sane_middleware::double_2_sane_fixed(v); data = local_utility::acquire_memory(sizeof(sd), ""); if (bytes) *bytes = sizeof(sd); memcpy(data, &sd, sizeof(sd)); if (log) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "option %d(%s) default value is: %f\n", option, title.c_str(), v); } } else if (val == "string") { int size = 0; jsn->get_value("size", size); val = hg_sane_middleware::get_string_in_json(jsn, "default"); if (size < (int)val.length()) size = val.length(); data = local_utility::acquire_memory(size + 4, ""); strcpy((char*)data, val.c_str()); if (bytes) *bytes = val.length() + 1; if (log) { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "option %d(%s) default value is: %s\n", option, title.c_str(), (char*)data); } } else { VLOG_MINI_3(LOG_LEVEL_DEBUG_INFO, "option %d(%s) is '%s' and no value action.\n", option, title.c_str(), val.c_str()); } } delete jsn; if (!data) { std::vector::iterator it = find_openning_device_in_que(handle); if (it != openning_.end() && (*it)->std_opt) { SANE_Int id = -1; find_stored_descriptor(handle, option, &id); data = (*it)->std_opt->get_default_value(handle, id); } } 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间隙可能新增的设备预留空? 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) { local_utility::free_memory(dev); dev = NULL; } } if (hgerr == SCANNER_ERR_OK) { *device_list = hg_sane_middleware::to_sane_device(dev, count); if (dev) local_utility::free_memory(dev); } else ret = local_utility::scanner_err_2_sane_statu(hgerr); 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) { 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); } if (ret == SANE_STATUS_GOOD) { // 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 reload_options(hg_sane_middleware::sane_handle_to_scanner(*handle)); } 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)); 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) { LPDEVINST dev; scanner_handle hs = find_openning_device(h); scanner_err err = SCANNER_ERR_INVALID_PARAMETER; if(hs) err = hg_scanner_start(hs, 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) { 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, const void* option) { SANE_Option_Descriptor* ret = nullptr; scanner_handle handle = hg_sane_middleware::sane_handle_to_scanner(h); std::vector::iterator it = find_openning_device_in_que(handle); SANE_Int id = -1; if (!handle || it == openning_.end()) return nullptr; else 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(handle, option, &id); if (!ret) { std::string key(""), json_txt(get_option_json(handle, (void*)option, &key, &id)); if (json_txt.length()) { json* jsn = new json(); if (jsn->attach_text(&json_txt[0])) { ret = from_json(handle, key, jsn); if (ret) { DEVOPT devopt; devopt.option_no = id; devopt.fixed_no = 0; devopt.desc = ret; if (jsn->get_value("fix-id", devopt.fixed_no)) (*it)->fixed_id[(sane_option_id)devopt.fixed_no] = id; else local_utility::init_fixed_id(key.c_str(), id, (*it)->fixed_id, &devopt.fixed_no); devopt.opt_name = std::move(key); (*it)->opts.push_back(std::move(devopt)); if ((*it)->std_opt) (*it)->std_opt->init_known_opt(id, ret); refresh_current_value(*it, ret->name, jsn); } } delete jsn; } if(!ret && (*it)->std_opt) ret = (*it)->std_opt->get_option(id); } return ret; } SANE_Status hg_sane_middleware::set_option(SANE_Handle h, const void* option, SANE_Action action, void* value, SANE_Int* after_do) { if ((IS_PTR_NUMBER(option) && (int)(long)option == SANE_OPT_ID_DRIVER_LOG) || (!IS_PTR_NUMBER(option) && strcmp((const char*)option, SANE_STD_OPT_NAME_DRIVER_LOG) == 0)) { // omit value of 'h' ... long id = SANE_OPT_ID_DRIVER_LOG, l = 0; std::string name(local_utility::un_json_option_name(id, (int*)&l)); if (action == SANE_ACTION_GET_VALUE) return local_utility::scanner_err_2_sane_statu(hg_scanner_get_parameter(h, SANE_STD_OPT_NAME_DRIVER_LOG, (char*)value, &l)); else if (action == SANE_ACTION_SET_VALUE) return local_utility::scanner_err_2_sane_statu(hg_scanner_set_parameter(h, SANE_STD_OPT_NAME_DRIVER_LOG, (char*)value, &l)); else return SANE_STATUS_INVAL; } LPDEVINST dev = nullptr; scanner_handle handle = find_openning_device(h, false, &dev); if (!handle || (action == SANE_ACTION_GET_VALUE && !value)) return SANE_STATUS_INVAL; if (hg_scanner_get_status(handle, 0) == SCANNER_ERR_DEVICE_NOT_FOUND) return local_utility::scanner_err_2_sane_statu(SCANNER_ERR_DEVICE_NOT_FOUND); 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, (const char*)option, NULL, &count); *((SANE_Int*)value) = count; ret = SANE_STATUS_GOOD; VLOG_MINI_1(LOG_LEVEL_WARNING, "get option count = %d.\n", count); } else { SANE_Int id = -1; SANE_Option_Descriptor* desc = find_stored_descriptor(handle, option); if (desc && (desc->type == SANE_TYPE_BUTTON || desc->type == SANE_TYPE_GROUP)) return SANE_STATUS_UNSUPPORTED; if (dev->std_opt && dev->std_opt->is_known_option(id)) { dev->std_opt->get_value(h, id, value); ret = SANE_STATUS_GOOD; } else if(get_current_value(handle, option, &hg_sane_middleware::set_value_to_var, value)) ret = SANE_STATUS_GOOD; } return ret; } else if (action == SANE_ACTION_GET_DEFAULT_VALUE) { SANE_Option_Descriptor* desc = find_stored_descriptor(handle, option); if (desc && (desc->type == SANE_TYPE_BUTTON || desc->type == SANE_TYPE_GROUP)) return SANE_STATUS_UNSUPPORTED; int len = 0; void* val = get_default_value(handle, option, &len); if (!val) return SANE_STATUS_UNSUPPORTED; memcpy(value, val, len); local_utility::free_memory(val); return SANE_STATUS_GOOD; } else if (action == SANE_ACTION_GET_FIX_ID) { SANE_Int id = 0; find_stored_descriptor(handle, option, nullptr, &id); if (id > SANE_OPT_ID_BASE) { *(SANE_Int*)value = id; return SANE_STATUS_GOOD; } else return SANE_STATUS_UNSUPPORTED; } else if(action == SANE_ACTION_SET_AUTO || action == SANE_ACTION_SET_VALUE) { SANE_Int id = -1; SANE_Option_Descriptor* desc = find_stored_descriptor(handle, option, &id); bool release_value = false; scanner_err err = SCANNER_ERR_OK; SANE_Status status = SANE_STATUS_GOOD; std::string prev(""), v(""), desc_name(""), desc_title(""); SANE_Value_Type sane_type = SANE_TYPE_BUTTON; if (desc) { desc_name = desc->name; desc_title = desc->title; sane_type = desc->type; } if (action == SANE_ACTION_SET_AUTO && desc && desc->type != SANE_TYPE_BUTTON && desc->type != SANE_TYPE_GROUP) // 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); int len = 0; void* val = get_default_value(handle, option, &len); if (!val) return SANE_STATUS_UNSUPPORTED; if (value) { memcpy(value, val, len); local_utility::free_memory(val); } else { value = val; release_value = true; } } if (dev->std_opt && dev->std_opt->is_known_option(id, &desc)) { SANE_Option_Descriptor* known = dev->std_opt->get_option(id); unsigned char* cont = (unsigned char*)value; prev = hg_sane_middleware::option_value_2_string(known->type, value); VLOG_MINI_5(LOG_LEVEL_DEBUG_INFO, "$First 4-bytes of origin value for option %d is: %02X%02X%02X%02X\n", option, cont[0], cont[1], cont[2], cont[3]); err = dev->std_opt->set_value(handle, id, value); v = hg_sane_middleware::option_value_2_string(known->type, value); } else { if (!desc) { if (IS_PTR_NUMBER(option)) { int id = (int)(uint64_t)option, l = 0; std::string name(local_utility::un_json_option_name(id, &l)); if (!name.empty()) return local_utility::scanner_err_2_sane_statu(hg_scanner_set_parameter(handle, name.c_str(), value, 0)); } 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; long 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, (const char*)option, pass, &size); // NOTE: change language will lead 'desc' reallocated !!! if (sane_type == SANE_TYPE_BOOL) { *((SANE_Bool*)value) = bv ? SANE_TRUE : SANE_FALSE; } else if (sane_type == SANE_TYPE_FIXED) { *((SANE_Fixed*)value) = hg_sane_middleware::double_2_sane_fixed(dv); } v = hg_sane_middleware::option_value_2_string(sane_type, value); } if (prev == v) { VLOG_MINI_3(LOG_LEVEL_ALL, "-->Set option(%d - %s) value: %s\n", option, desc_title.c_str(), v.c_str()); } else { VLOG_4(LOG_LEVEL_ALL, 512, "-->Set option(%d - %s) value: %s(Applied: %s)\n", option, desc_title.c_str(), prev.c_str(), v.c_str()); } if (err == SCANNER_ERR_OK) { err = (scanner_err)something_after_do(dev, desc_name.c_str(), v.c_str()); } else if (err == SCANNER_ERR_NOT_EXACT) { err = (scanner_err)(something_after_do(dev, desc_name.c_str(), 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.c_str()); //on_SCANNER_ERR_CONFIGURATION_CHANGED(dev); if(dev->fixed_id.count(SANE_OPT_ID_LANGUAGE) == 0 || dev->fixed_id[SANE_OPT_ID_LANGUAGE] != id) // language reload by callback already reload_options(handle); err = (scanner_err)SANE_INFO_RELOAD_OPTIONS; } else if(err == SCANNER_ERR_RELOAD_IMAGE_PARAM) { VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "the setting '%s' affects image parameter, APP should re-get ...\n", desc_title.c_str()); err = (scanner_err)SANE_INFO_RELOAD_PARAMS; } else if(err == SCANNER_ERR_RELOAD_OPT_PARAM) { VLOG_MINI_1(LOG_LEVEL_DEBUG_INFO, "the setting '%s' affects image parameter and options, APP should re-get image info and reload options...\n", desc_title.c_str()); //on_SCANNER_ERR_CONFIGURATION_CHANGED(dev); if (dev->fixed_id.count(SANE_OPT_ID_LANGUAGE) == 0 || dev->fixed_id[SANE_OPT_ID_LANGUAGE] != id) // language reload by callback already reload_options(handle); err = (scanner_err)(SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS); } else if (err == SCANNER_ERR_ACCESS_DENIED) { status = SANE_STATUS_ACCESS_DENIED; err = (scanner_err)0; } else { status = local_utility::scanner_err_2_sane_statu(err); err = (scanner_err)0; } if (after_do) *after_do = err; if (release_value) local_utility::free_memory(value); return status; } return SANE_STATUS_INVAL; } bool hg_sane_middleware::get_cur_value(SANE_Handle handle, void* option, void* value, SANE_Value_Type* type) { scanner_handle h = find_openning_device(handle); if (!h) return false; return get_current_value(h, option, &hg_sane_middleware::set_value_to_var, value, type); } void* hg_sane_middleware::get_cur_value(SANE_Handle handle, void* option, SANE_Value_Type* type) { scanner_handle h = find_openning_device(handle); void* buf = nullptr; if (!h) return NULL; get_current_value(h, option, &hg_sane_middleware::set_value_to_new, &buf, type); return buf; } void* hg_sane_middleware::get_def_value(SANE_Handle handle, void* option, int* bytes, bool log) { scanner_handle h = find_openning_device(handle); if (!h) return NULL; return get_default_value(h, option, bytes, log); } SANE_Status hg_sane_middleware::io_control(SANE_Handle h, unsigned long code, void* data, unsigned* len) { LPDEVINST dev; scanner_handle handle = find_openning_device(h, false, &dev); 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(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(dev); } return local_utility::scanner_err_2_sane_statu(ret); } bool hg_sane_middleware::is_ready(void) { return init_ok_; } /// /// 关联项处? 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(scanner_handle hdev, const std::vector& master, std::vector& 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::iterator it = std::find(curvals.begin(), curvals.end(), master[i].name); if (it == curvals.end()) { VLOG_MINI_1(LOG_LEVEL_WARNING, "option %s's current value is not found, other options depend it maybe in wrong status.\n", master[i].name.c_str()); continue; } const SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->find_stored_descriptor(hdev, master[i].name.c_str()); if (desc && (desc->cap & SANE_CAP_INACTIVE)) enabled = false; else 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(scanner_handle hdev, const std::vector& master, std::vector& curvals) { bool enabled = false; for (size_t i = 0; !enabled && i < master.size(); ++i) { std::vector::iterator it = std::find(curvals.begin(), curvals.end(), master[i].name); if (it == curvals.end()) { VLOG_MINI_1(LOG_LEVEL_WARNING, "option %s's current value is not found, other options depend it maybe in wrong status.\n", master[i].name.c_str()); continue; } const SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->find_stored_descriptor(hdev, master[i].name.c_str()); if (desc && (desc->cap & SANE_CAP_INACTIVE)) enabled = false; else 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; std::string v(""); mo.compare_val = &hg_sane_middleware::compare_val_equal; mo.limit_l = mo.limit_r = ""; local_utility::skip_space(depend_str); while ((*depend_str >= 'a' && *depend_str <= 'z') || *depend_str == '-') v.push_back(*depend_str++); if (!v.empty()) mo.name = v; if (ret) { 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(scanner_handle h, json* jsn, SLAVEOP& so, std::vector& master) { std::string val(""), mn(""); bool ret = jsn->first_child(val); while(ret) { MASTEROP mo; ret = parse_master_option(val.c_str(), mo); if (!ret) break; if (mo.name.empty()) mo.name = mn; else mn = mo.name; SANE_Option_Descriptor* m = find_stored_descriptor(h, mo.name.c_str()); if (m && m->type == SANE_TYPE_STRING) mo.limit_l = from_default_language(mo.limit_l.c_str(), nullptr); so.master.push_back(mo); if (std::find(master.begin(), master.end(), mo.name) == master.end()) { master.push_back(mo.name); std::sort(master.begin(), master.end()); } ret = jsn->next_child(val); } return so.master.size() > 0; } bool hg_sane_middleware::is_associatived(const SLAVEOP& slave, const char* master_name) { bool result = false; for (const auto& v: slave.master) { if (v.name == master_name) { result = true; break; } } return result; } bool hg_sane_middleware::set_stored_option_enabled(scanner_handle h, const void* option, bool enable, int* size) { SANE_Option_Descriptor* opt = find_stored_descriptor(h, 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(LPDEVINST dev, const char* master_name, const char* cur_val) { int after = 0; OPTENABLE oe; std::vector changed_options; refresh_current_value(dev, master_name, cur_val); if (std::find(dev->masters.begin(), dev->masters.end(), master_name) == dev->masters.end()) { return after; } oe.name = master_name; oe.enable = true; changed_options.push_back(oe); for (size_t i = 0; i < changed_options.size(); ++i) { for (size_t slave = 0; slave < dev->slaves.size(); ++slave) { if (dev->slaves[slave].name == changed_options[i].name || !is_associatived(dev->slaves[slave], changed_options[i].name.c_str())) continue; bool enable = changed_options[i].enable; int bytes = 0; // if (enable) enable = dev->slaves[slave].is_enable(dev->dev, dev->slaves[slave].master, dev->cur_vals); if (enable == dev->slaves[slave].enable_now) continue; dev->slaves[slave].enable_now = enable; if (!set_stored_option_enabled(dev->dev, dev->slaves[slave].name.c_str(), enable, &bytes)) continue; OPTEN* op = get_control_enalbe_data(dev, dev->slaves[slave]); hg_scanner_control(dev->dev, HG_CONTROL_CODE_OPTION_ENABLE, op, NULL); free_control_enable_data(op); if (std::find(changed_options.begin(), changed_options.end(), dev->slaves[slave].name) != changed_options.end()) continue; oe.name = dev->slaves[slave].name; oe.enable = dev->slaves[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(LPDEVINST dev, const char* name, json* jsn) { std::vector::iterator it = std::find(dev->cur_vals.begin(), dev->cur_vals.end(), name); if (it == dev->cur_vals.end()) { CURVAL cv; jsn->get_value("type", cv.type); cv.name = name; jsn->get_value_as_string("cur", cv.val, cv.type == "int"); if (cv.type == "string") local_utility::trans_language_if_was_word_id(cv.val); dev->cur_vals.push_back(cv); return false; } else { std::string old(it->val); jsn->get_value_as_string("cur", it->val, it->type == "int"); if (it->type == "string") local_utility::trans_language_if_was_word_id(it->val); return old != it->val; } } bool hg_sane_middleware::refresh_current_value(LPDEVINST dev, const char* name, const char* val) { std::vector::iterator it = std::find(dev->cur_vals.begin(), dev->cur_vals.end(), name); if (it != dev->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(LPDEVINST dev, const SLAVEOP& slave) { std::vector 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].name) == master.end()) master.push_back(slave.master[i].name); } size += master.size() * sizeof(OPTVAL); opt = (OPTEN*)malloc(size); bzero(opt, size); opt->enabled = slave.enable_now; strcpy(opt->name, slave.name.c_str()); opt->master_count = 0; for (size_t i = 0; i < master.size(); ++i) { std::vector::iterator m = std::find(dev->cur_vals.begin(), dev->cur_vals.end(), master[i]); if (m == dev->cur_vals.end()) continue; strcpy(opt->master[opt->master_count].name, master[i].c_str()); 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(LPDEVINST dev) { std::vector changed; reload_current_value(dev->dev, &changed); if (changed.size()) { for (size_t i = 0; i < changed.size(); ++i) { std::vector::iterator it = std::find(dev->cur_vals.begin(), dev->cur_vals.end(), changed[i]); if (it != dev->cur_vals.end()) something_after_do(dev, it->name.c_str(), it->val.c_str()); } } } std::vector::iterator hg_sane_middleware::find_openning_device_in_que(scanner_handle h) { for (size_t i = 0; i < openning_.size(); ++i) { if (openning_[i]->dev == h) return openning_.begin() + i; } return openning_.end(); } std::vector::iterator hg_sane_middleware::find_openning_device_in_que(const char* name) { for (size_t i = 0; i < openning_.size(); ++i) { if (openning_[i]->name == name) return openning_.begin() + i; } return openning_.end(); } /// /// /// 导出接口 /// extern "C" { // avoid compiler exporting name in C++ style !!! const char* inner_sane_err_desc(SANE_Status err) { return hg_scanner_err_description(local_utility::sane_statu_2_scanner_err(err)); } SANE_Status inner_sane_init(SANE_Int* version_code, SANE_Auth_Callback authorize) { local_utility::cb_auth_ = authorize; if (!hg_sane_middleware::instance()->is_ready()) return (SANE_Status)SCANNER_ERR_LANG_PAK_LOST; local_utility::get_version(version_code); std::this_thread::sleep_for(std::chrono::milliseconds(500)); 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, const void* option) { return hg_sane_middleware::instance()->get_option_descriptor(handle, option); } SANE_Status inner_sane_control_option(SANE_Handle handle, const void* 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) { LOG_INFO(LOG_LEVEL_ALL, "sane_cancel\n"); 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); return inner_sane_err_desc(status); } SANE_Status inner_sane_init_ex(SANE_Int* version_code, sane_callback cb, void* param) { local_utility::set_callback(cb, param); if (!hg_sane_middleware::instance()->is_ready()) return (SANE_Status)SCANNER_ERR_LANG_PAK_LOST; local_utility::get_version(version_code); std::this_thread::sleep_for(std::chrono::milliseconds(500)); 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); } SANE_Status inner_sane_read_ext(SANE_Img_Ext_Info* ext_info, SANE_Int* len) { return SANE_STATUS_UNSUPPORTED; } 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