diff --git a/hgsane/sane_hg_mdw.cpp b/hgsane/sane_hg_mdw.cpp index 2099eed..c1b2f3a 100644 --- a/hgsane/sane_hg_mdw.cpp +++ b/hgsane/sane_hg_mdw.cpp @@ -231,7 +231,7 @@ hg_sane_middleware::hg_sane_middleware(void) : init_ok_(false), offline_(nullptr { offline_ = new DEVINST; offline_->opts = new sane_options(); - reload_options(offline_); + reload_options(offline_, RELOAD_FOR_DEVICE_OPEN); } std::this_thread::sleep_for(std::chrono::milliseconds(500)); // wait for device OK @@ -390,7 +390,7 @@ hg_sane_middleware::LPDEVINST hg_sane_middleware::find_openning_device(const cha return ret; } -bool hg_sane_middleware::reload_options(LPDEVINST inst) +bool hg_sane_middleware::reload_options(LPDEVINST inst, int reason) { long len = 0; char *buf = nullptr; @@ -404,7 +404,7 @@ bool hg_sane_middleware::reload_options(LPDEVINST inst) if (err == SCANNER_ERR_OK && len) { - if (!inst->opts->init_from(buf, local_utility::dump_msg)) + if (!inst->opts->init_from(buf, local_utility::dump_msg, reason == RELOAD_FOR_DEVICE_OPEN)) err = SCANNER_ERR_DATA_DAMAGED; } if (buf) @@ -485,7 +485,7 @@ scanner_err hg_sane_middleware::write_value(scanner_handle h, const char* name, if (err == SCANNER_ERR_RELOAD_OPT_PARAM || err == SCANNER_ERR_CONFIGURATION_CHANGED) { if(optinst) - reload_options(optinst); + reload_options(optinst, RELOAD_FOR_OPT_CHANGED); if (affect) *affect = SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; err = SCANNER_ERR_OK; @@ -668,7 +668,7 @@ SANE_Status hg_sane_middleware::open_device(SANE_String_Const devicename, SANE_H inst->dev = h; inst->name = devicename; inst->opts = new sane_options(); - if(reload_options(inst)) + if(reload_options(inst, RELOAD_FOR_DEVICE_OPEN)) { openning_.push_back(inst); *handle = hg_sane_middleware::scanner_handle_to_sane(h); @@ -850,7 +850,7 @@ SANE_Status hg_sane_middleware::ex_io_control(SANE_Handle h, unsigned long code, { 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_options(dev, RELOAD_FOR_OPT_CHANGED); } return local_utility::scanner_err_2_sane_statu(ret); diff --git a/hgsane/sane_hg_mdw.h b/hgsane/sane_hg_mdw.h index 63a51d3..a6c5408 100644 --- a/hgsane/sane_hg_mdw.h +++ b/hgsane/sane_hg_mdw.h @@ -48,7 +48,12 @@ class hg_sane_middleware LPDEVINST find_openning_device(SANE_Handle h, bool rmv = false); LPDEVINST find_openning_device(const char* name, bool rmv = false); - bool reload_options(LPDEVINST inst); + enum + { + RELOAD_FOR_DEVICE_OPEN = 0, + RELOAD_FOR_OPT_CHANGED, + }; + bool reload_options(LPDEVINST inst, int reason); scanner_err read_value(scanner_handle h, const char* name, SANE_Value_Type type, size_t len, void* value, bool to_default); scanner_err write_value(scanner_handle h, const char* name, SANE_Value_Type type, void* value, bool to_default, LPDEVINST optinst, SANE_Int* affect); diff --git a/hgsane/sane_opt/sane_opts.cpp b/hgsane/sane_opt/sane_opts.cpp index e990d6c..ea1e68a 100644 --- a/hgsane/sane_opt/sane_opts.cpp +++ b/hgsane/sane_opt/sane_opts.cpp @@ -248,17 +248,30 @@ bool sane_opt::from_json_text(const char* key, const char* json, void(*err_msg)( bool ret = false; std::string text(json); gb_json *jsn = new gb_json(); - char *buf = nullptr; + + if (jsn->attach_text(&text[0])) + { + jsn->key() = key; + ret = from_json_object(jsn, err_msg); + } + jsn->release(); + + return ret; +} +bool sane_opt::from_json_object(gb_json* jsn, void(*err_msg)(const char*)) +{ + bool ret = false; + std::string text(""); clear(); - while (jsn->attach_text(&text[0])) + while (1) { if (!jsn->get_value("fix-id", fix_id_)) fix_id_ = -1; - if(!jsn->get_value("enabled", enabled_)) + if (!jsn->get_value("enabled", enabled_)) enabled_ = true; - set_opt_desc_string_value((char**)&opt_desc_.name, key); + set_opt_desc_string_value((char**)&opt_desc_.name, jsn->key().c_str()); if (jsn->get_value("title", text)) { set_opt_desc_string_value((char**)&opt_desc_.title, text.c_str()); @@ -323,7 +336,6 @@ bool sane_opt::from_json_text(const char* key, const char* json, void(*err_msg)( ret = true; break; } - jsn->release(); return ret; } @@ -369,14 +381,15 @@ void sane_options::clear(void) opt_cnt_ = 0; } -bool sane_options::init_from(const char* jsn_text/*all options*/, void(*err_msg)(const char*)) +bool sane_options::init_from(const char* jsn_text/*all options*/, void(*err_msg)(const char*), bool clear_prev) { bool ret = false; gb_json* jsn = new gb_json(); std::string str(jsn_text); int sn = 0; - // clear(); // keep the SANE_Option_Descriptor* + if(clear_prev) + clear(); // keep the SANE_Option_Descriptor* if (jsn->attach_text(&str[0])) { gb_json* child = jsn->first_child(); @@ -386,14 +399,15 @@ bool sane_options::init_from(const char* jsn_text/*all options*/, void(*err_msg) { str = std::move(child->to_string()); sn++; - ret = add_or_replace_opt(sn, child->key().c_str(), str.c_str(), err_msg); + ret = add_or_replace_opt(sn, child, err_msg); + child->release(); + if (!ret) { - child->release(); - clear(); + if (clear_prev) + clear(); break; } - child->release(); child = jsn->next_child(); } } @@ -403,17 +417,33 @@ bool sane_options::init_from(const char* jsn_text/*all options*/, void(*err_msg) } bool sane_options::add_or_replace_opt(int& sn, const char* name, const char* jsn_text, void(*err_msg)(const char*)) { - if (opts_.count(sn)) - { - bool en = opts_[sn]->is_enabled(), - ret = opts_[sn]->from_json_text(name, jsn_text, err_msg); + bool ret = false; + std::string text(jsn_text); + gb_json *jsn = new gb_json(); - return ret; + if (jsn->attach_text(&text[0])) + { + jsn->key() = name; + ret = add_or_replace_opt(sn, jsn, err_msg); + } + jsn->release(); + + return ret; +} +bool sane_options::add_or_replace_opt(int& sn, gb_json* jsn, void(*err_msg)(const char*)) +{ + int id = sn; + if (!jsn->get_value("fix-id", id)) + id = sn; + + if (opts_.count(id)) + { + return opts_[id]->from_json_object(jsn, err_msg); } sane_opt* opt = new sane_opt(); - if (opt->from_json_text(name, jsn_text, err_msg)) + if (opt->from_json_object(jsn, err_msg)) { if (opt->is_visible()) { diff --git a/hgsane/sane_opt/sane_opts.h b/hgsane/sane_opt/sane_opts.h index 09b4aee..796009a 100644 --- a/hgsane/sane_opt/sane_opts.h +++ b/hgsane/sane_opt/sane_opts.h @@ -45,6 +45,7 @@ public: bool is_visible(void); bool from_json_text(const char* key, const char* json, void(*err_msg)(const char*) = nullptr); + bool from_json_object(gb_json* jsn, void(*err_msg)(const char*) = nullptr); }; @@ -57,13 +58,15 @@ class sane_options void clear(void); bool add_or_replace_opt(int& sn, const char* name, const char* jsn_text, void(*err_msg)(const char*)); + bool add_or_replace_opt(int& sn, gb_json* jsn, void(*err_msg)(const char*)); public: sane_options(); ~sane_options(); public: - bool init_from(const char* jsn_text/*all options*/, void(*err_msg)(const char*)); + // clear_prev: call from device openned or closed, should clear all options; call from SANE_RELOAD_xxx should keep the SANE_Option_Descriptor* stable + bool init_from(const char* jsn_text/*all options*/, void(*err_msg)(const char*), bool clear_prev); SANE_Option_Descriptor* get_opt_descriptor(const void* opt, int* fix_id = nullptr, int ind_base = 0); int get_option_count(void); bool enum_invisible_fix_ids(struct _fix_id_cb* fcb); // return whether the callback stopped the enumeration