TWAIN升级老版本配置文件

This commit is contained in:
gb 2022-10-08 14:13:09 +08:00
parent 322171a25c
commit fdb5649ed2
4 changed files with 260 additions and 97 deletions

View File

@ -9,6 +9,7 @@
#define bzero(b, s) memset(b, 0, s)
#endif
namespace gb
{
static std::vector<std::string> split_with(const char* str, const char* splitor = "/")
@ -563,6 +564,28 @@ namespace gb
return true;
}
bool json::change_key(const char* old_key, const char* new_key)
{
if (!obj_ || !new_key || *new_key == 0 || !old_key || *old_key == 0)
return false;
cJSON** addr = NULL,
*ele = find(old_key, false, &addr);
if (!ele)
return false;
if (strlen(ele->string) < strlen(new_key))
{
int l = strlen(new_key) + 4;
free(ele->string);
ele->string = (char*)malloc(l);
memset(ele->string, 0, l);
}
strcpy(ele->string, new_key);
return true;
}
bool json::remove(const char* key)
{
if(!obj_)
@ -927,24 +950,8 @@ namespace gb
memset(buf, 0, size + 4);
fread(buf, 1, size, src);
fclose(src);
std::string raw(b64.decode(buf, size));
ret = load_from_mem(buf);
delete[] buf;
if (raw.length())
{
jsn_ = new gb::json();
if (jsn_->attach_text(&raw[0]))
{
ret = true;
}
else
{
delete jsn_;
jsn_ = NULL;
}
}
}
file_ = file;
@ -989,21 +996,18 @@ namespace gb
return ret;
}
void sane_config::set_default_value(int sn, const char* title, const char* val, size_t bytes)
void sane_config::set_default_value(int sn, const char* name, const char* val, size_t bytes)
{
std::string hex_t(to_hex_letter(title, lstrlenA(title)));
id_title_[sn] = hex_t;
def_val_->set_value(hex_t.c_str(), to_hex_letter(val, bytes).c_str());
id_name_[sn] = name;
def_val_->set_value(name, to_hex_letter(val, bytes).c_str());
}
bool sane_config::first_config(std::string& title, std::string& val)
bool sane_config::first_config(std::string& name, std::string& val)
{
bool ret = false;
std::string raw_n(""), raw_v("");
std::string raw_v("");
if (jsn_ && jsn_->first_child(raw_v, &raw_n))
if (jsn_ && jsn_->first_child(raw_v, &name))
{
title = sane_config::from_hex_letter(raw_n.c_str(), raw_n.length());
val = sane_config::from_hex_letter(raw_v.c_str(), raw_v.length());
ret = true;
@ -1011,14 +1015,13 @@ namespace gb
return ret;
}
bool sane_config::next_config(std::string& title, std::string& val)
bool sane_config::next_config(std::string& name, std::string& val)
{
bool ret = false;
std::string raw_n(""), raw_v("");
std::string raw_v("");
if (jsn_ && jsn_->next_child(raw_v, &raw_n))
if (jsn_ && jsn_->next_child(raw_v, &name))
{
title = sane_config::from_hex_letter(raw_n.c_str(), raw_n.length());
val = sane_config::from_hex_letter(raw_v.c_str(), raw_v.length());
ret = true;
@ -1040,38 +1043,36 @@ namespace gb
jsn_->attach_text(&stream[0]);
}
}
void sane_config::config_changed(const char* title, const char* val, size_t bytes)
void sane_config::config_changed(const char* name, const char* val, size_t bytes)
{
std::string hex_t(to_hex_letter(title, lstrlenA(title))),
hex_v(to_hex_letter(val, bytes)),
def(default_value(hex_t.c_str()));
std::string hex_v(to_hex_letter(val, bytes)),
def(default_value(name));
if (hex_v == def)
jsn_->remove(hex_t.c_str());
jsn_->remove(name);
else
jsn_->set_value(hex_t.c_str(), hex_v.c_str());
jsn_->set_value(name, hex_v.c_str());
}
void sane_config::config_changed(int sn, const char* val, size_t bytes)
{
std::string hex_t(""),
std::string name(""),
hex_v(to_hex_letter(val, bytes)),
def("");
if (id_title_.count(sn))
if (id_name_.count(sn))
{
hex_t = id_title_[sn];
def = default_value(hex_t.c_str());
name = id_name_[sn];
def = default_value(name.c_str());
if (hex_v == def)
jsn_->remove(hex_t.c_str());
jsn_->remove(name.c_str());
else
jsn_->set_value(hex_t.c_str(), hex_v.c_str());
jsn_->set_value(name.c_str(), hex_v.c_str());
}
}
void sane_config::remove_config(const char* title)
void sane_config::remove_config(const char* name)
{
std::string hex_t(to_hex_letter(title, lstrlenA(title)));
if (jsn_)
jsn_->remove(hex_t.c_str());
jsn_->remove(name);
}
void sane_config::end_setting(bool cancel)
{
@ -1091,13 +1092,11 @@ namespace gb
}
in_setting_ = false;
}
int sane_config::id_from_title(const char* title)
int sane_config::id_from_name(const char* name)
{
std::string hex_t(to_hex_letter(title, lstrlenA(title)));
for (const auto& v : id_title_)
for (const auto& v : id_name_)
{
if (v.second == hex_t)
if (v.second == name)
return v.first;
}
@ -1132,4 +1131,54 @@ namespace gb
return ver;
}
void sane_config::update(bool(__stdcall* is_float)(int, void*), void* param, const char* (__stdcall* t2n)(const char*), std::string* discard)
{
std::string ver(get_version()),
name(""),
val("");
int mv = atoi(ver.c_str()),
sv = ver.find(".");
bool changed = false;
char vs[40] = { 0 };
if (sv++ != -1)
sv = atoi(ver.c_str() + sv);
// change title to name ...
if (mv <= 4 && sv < 30)
{
if (jsn_->first_child(val, &name))
{
changed = true;
do
{
jsn_->change_key(name.c_str(), t2n(sane_config::from_hex_letter(name.c_str(), name.length()).c_str()));
} while (jsn_->next_child(val, &name));
}
}
// fix float does not convert to SANE_Fixed bug in eldest version .... (discard them)
if (ver.empty())
{
if (jsn_->first_child(val, &name))
{
do
{
int id = id_from_name(name.c_str());
if (id == -1 || is_float(id, param))
{
jsn_->remove(name.c_str());
if (discard)
*discard += name + "\r\n";
changed = true;
}
} while (jsn_->next_child(val, &name));
}
}
sprintf_s(vs, _countof(vs) - 1, "%u.%u", VERSION_MAIN, VERSION_SUB);
jsn_->set_value("ver", vs);
if (changed)
save_to(NULL);
}
}

View File

@ -59,6 +59,7 @@ namespace gb
bool set_value(const char* key, const char* val);
bool set_value(const char* key, json* obj);
bool change_key(const char* old_key, const char* new_key);
bool remove(const char* key);
};
@ -88,12 +89,12 @@ namespace gb
json* bkp_;
json* def_val_;
bool in_setting_;
std::map<int, std::string> id_title_;
std::map<int, std::string> id_name_;
void clear();
std::string to_hex_letter(const char* data, size_t bytes);
std::string from_hex_letter(const char* data, size_t bytes);
std::string default_value(const char* hex_title);
std::string default_value(const char* name);
public:
sane_config();
@ -106,16 +107,17 @@ namespace gb
bool load_from_file(const wchar_t* file);
bool load_from_mem(const char* mem);
bool save_to(const wchar_t* file);
void set_default_value(int sn, const char* title, const char* val, size_t bytes);
bool first_config(std::string& title, std::string& val);
bool next_config(std::string& title, std::string& val);
void set_default_value(int sn, const char* name, const char* val, size_t bytes);
bool first_config(std::string& name, std::string& val);
bool next_config(std::string& name, std::string& val);
void begin_setting(bool restore = false);
void config_changed(const char* title, const char* val, size_t bytes);
void config_changed(const char* name, const char* val, size_t bytes);
void config_changed(int sn, const char* val, size_t bytes);
void remove_config(const char* title);
void remove_config(const char* name);
void end_setting(bool cancel);
int id_from_title(const char* title);
int id_from_name(const char* name);
std::string to_text_stream(void);
std::string get_version(void);
void update(bool(__stdcall* is_float)(int, void*), void* param, const char*(__stdcall* t2n)(const char*), std::string* discard = NULL);
};
}

View File

@ -115,6 +115,115 @@ namespace callback
if (it != g_scanner_instances.end())
g_scanner_instances.erase(it);
}
struct
{
const char* name;
const char* title;
}g_opts[] = { {SANE_STD_OPT_NAME_RESTORE , OPTION_TITLE_HFMRSZ}
, {SANE_STD_OPT_NAME_HELP , OPTION_TITLE_BZ}
, {SANE_STD_OPT_NAME_IS_MULTI_OUT , OPTION_TITLE_DLSC}
, {SANE_STD_OPT_NAME_MULTI_OUT_TYPE , OPTION_TITLE_DLSCLX}
, {SANE_STD_OPT_NAME_COLOR_MODE , OPTION_TITLE_YSMS}
, {SANE_STD_OPT_NAME_BINARY_THRESHOLD , OPTION_TITLE_HBTXYZ}
, {SANE_STD_OPT_NAME_REVERSE_01 , OPTION_TITLE_HBTXFSSC}
, {SANE_STD_OPT_NAME_FILTER , OPTION_TITLE_HDHHBTX_CSYZQ}
, {SANE_STD_OPT_NAME_RID_MULTIOUT_RED , OPTION_TITLE_24WCSTX_DLSCCH}
, {SANE_STD_OPT_NAME_RID_ANSWER_SHEET_RED , OPTION_TITLE_24WCSTX_DTKCH}
, {SANE_STD_OPT_NAME_ERASE_BACKGROUND , OPTION_TITLE_BJYC}
, {SANE_STD_OPT_NAME_BKG_COLOR_RANGE , OPTION_TITLE_BJSCFDFW}
, {SANE_STD_OPT_NAME_SHARPEN , OPTION_TITLE_RHYMH}
, {SANE_STD_OPT_NAME_RID_MORR , OPTION_TITLE_QCMW}
, {SANE_STD_OPT_NAME_RID_GRID , OPTION_TITLE_CWW}
, {SANE_STD_OPT_NAME_ERROR_EXTENSION , OPTION_TITLE_CWKS}
, {SANE_STD_OPT_NAME_NOISE_OPTIMIZE , OPTION_TITLE_HBTXZDYH}
, {SANE_STD_OPT_NAME_NOISE_SIZE , OPTION_TITLE_ZDYHCC}
, {SANE_STD_OPT_NAME_PAPER , OPTION_TITLE_ZZCC}
, {SANE_STD_OPT_NAME_CUSTOM_AREA , OPTION_TITLE_ZDYSMQY}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_LEFT , OPTION_TITLE_SMQYZCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_RIGHT , OPTION_TITLE_SMQYYCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_TOP , OPTION_TITLE_SMQYSCmm}
, {SANE_STD_OPT_NAME_CUSTOM_AREA_BOTTOM , OPTION_TITLE_SMQYXCmm}
, {SANE_STD_OPT_NAME_SIZE_CHECK , OPTION_TITLE_CCJC}
, {SANE_STD_OPT_NAME_PAGE , OPTION_TITLE_SMYM}
, {SANE_STD_OPT_NAME_DISCARD_BLANK_SENS , OPTION_TITLE_TGKBYLMD}
, {SANE_STD_OPT_NAME_RESOLUTION , OPTION_TITLE_FBL}
, {SANE_STD_OPT_NAME_TIME_TO_SLEEP , OPTION_TITLE_XMSJ}
, {SANE_STD_OPT_NAME_IMAGE_QUALITY , OPTION_TITLE_HZ}
, {SANE_STD_OPT_NAME_EXCHANGE ,OPTION_TITLE_JHZFM}
, {SANE_STD_OPT_NAME_SPLIT ,OPTION_TITLE_TXCF }
, {SANE_STD_OPT_NAME_ANTI_SKEW , OPTION_TITLE_ZDJP}
, {SANE_STD_OPT_NAME_IS_CUSTOM_GAMMA , OPTION_TITLE_QYSDQX}
, {SANE_STD_OPT_NAME_GAMMA , OPTION_TITLE_JMZ}
, {SANE_STD_OPT_NAME_BRIGHTNESS , OPTION_TITLE_LDZ}
, {SANE_STD_OPT_NAME_CONTRAST , OPTION_TITLE_DBD}
, {SANE_STD_OPT_NAME_IS_PHOTO_MODE , OPTION_TITLE_ZPMS}
, {SANE_STD_OPT_NAME_ERASE_BLACK_FRAME , OPTION_TITLE_XCHK}
, {SANE_STD_OPT_NAME_DARK_SAMPLE , OPTION_TITLE_SSYZ}
, {SANE_STD_OPT_NAME_THRESHOLD , OPTION_TITLE_YZ}
, {SANE_STD_OPT_NAME_ANTI_NOISE_LEVEL , OPTION_TITLE_BJKZDJ}
, {SANE_STD_OPT_NAME_MARGIN , OPTION_TITLE_BYSJ}
, {SANE_STD_OPT_NAME_FILL_BKG_MODE , OPTION_TITLE_BJTCFS}
, {SANE_STD_OPT_NAME_IS_ANTI_PERMEATE , OPTION_TITLE_FZST}
, {SANE_STD_OPT_NAME_ANTI_PERMEATE_LEVEL , OPTION_TITLE_FZSTDJ}
, {SANE_STD_OPT_NAME_RID_HOLE_L , OPTION_TITLE_CKYCZC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_L , OPTION_TITLE_ZCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_R , OPTION_TITLE_CKYCYC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_R , OPTION_TITLE_YCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_T , OPTION_TITLE_CKYCSC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_T , OPTION_TITLE_SCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_RID_HOLE_B , OPTION_TITLE_CKYCXC}
, {SANE_STD_OPT_NAME_SEARCH_HOLE_RANGE_B , OPTION_TITLE_XCCKSSFWZFMBL}
, {SANE_STD_OPT_NAME_IS_FILL_COLOR , OPTION_TITLE_SCTC}
, {SANE_STD_OPT_NAME_IS_ULTROSONIC_CHECK , OPTION_TITLE_CSBJC}
, {SANE_STD_OPT_NAME_DOUBLE_FEED_HANDLE , OPTION_TITLE_SZTPCL}
, {SANE_STD_OPT_NAME_IS_CHECK_STAPLE , OPTION_TITLE_ZDJC}
, {SANE_STD_OPT_NAME_SCAN_MODE , OPTION_TITLE_SMZS}
, {SANE_STD_OPT_NAME_SCAN_COUNT , OPTION_TITLE_SMSL}
, {SANE_STD_OPT_NAME_TEXT_DIRECTION , OPTION_TITLE_WGFX}
, {SANE_STD_OPT_NAME_IS_ROTATE_BKG_180 , OPTION_TITLE_BMXZ180}
, {SANE_STD_OPT_NAME_IS_CHECK_DOG_EAR , OPTION_TITLE_ZJJC}
, {SANE_STD_OPT_NAME_DOG_EAR_SIZE , OPTION_TITLE_ZJDX}
, {SANE_STD_OPT_NAME_IS_CHECK_ASKEW , OPTION_TITLE_WXJC}
, {SANE_STD_OPT_NAME_ASKEW_RANGE , OPTION_TITLE_WXRRD}
, {SANE_STD_OPT_NAME_FEED_STRENGTH , OPTION_TITLE_FZQD}
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , OPTION_TITLE_ZDFZQD}
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , OPTION_TITLE_JZSBL}
, {SANE_STD_OPT_NAME_WAIT_TO_SCAN , OPTION_TITLE_DZSM}
},
g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 黑白图像反色输出正常颜色为0-黑色1-白色)
, {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 灰度或黑白图像 - 除色
, {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 自动搓纸强度
, {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , "\346\220\223\347\272\270\351\230\210\345\200\274"} // " 搓纸阈值"
};
const char* __stdcall option_title_2_name(const char* title)
{
while (*title == ' ')
title++;
for (size_t i = 0; i < _countof(g_discard); ++i)
{
if (strcmp(title, g_discard[i].title) == 0)
return g_discard[i].name;
}
for (size_t i = 0; i < _countof(g_opts); ++i)
{
if (strcmp(title, g_opts[i].title) == 0)
return g_opts[i].name;
}
return "";
}
const char* __stdcall option_name_2_title(const char* name)
{
for (size_t i = 0; i < _countof(g_opts); ++i)
{
if (strcmp(name, g_opts[i].name) == 0)
return g_opts[i].title;
}
return "";
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -215,6 +324,15 @@ void __stdcall scanner::ui_callback(int uev, void* sender, void* param)
{
((scanner*)param)->on_ui_event(uev, sender);
}
bool __stdcall scanner::is_option_float(int sn, void* param)
{
SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor((SANE_Handle)param, sn);
if (desc)
return desc->type == SANE_TYPE_FIXED;
else
return false;
}
// IRef
COM_API_IMPLEMENT(scanner, long, add_ref(void))
@ -226,9 +344,28 @@ COM_API_IMPLEMENT(scanner, long, release(void))
return refer::release();
}
void scanner::update_config(void)
{
std::string notice("");
cfg_->update(&scanner::is_option_float, handle_, &callback::option_title_2_name, &notice);
if (notice.length())
{
std::wstring msg(L"\u4E0B\u5217\u914D\u7F6E\u6570\u636E\u9519\u8BEF\uFF0C\u5DF2\u7ECF\u6062\u590D\u5230\u9ED8\u8BA4\u503C\u3002\u5982\u679C\u9700\u8981\uFF0C\u8BF7\u91CD\u65B0\u8BBE\u7F6E\uFF1A\r\n\r\n");
size_t pos = notice.find("\r\n");
while (pos != std::string::npos)
{
msg += local_trans::a2u(callback::option_name_2_title(notice.substr(0, pos).c_str()), CP_UTF8) + L"\r\n";
notice.erase(0, pos + 2);
pos = notice.find("\r\n");
}
MessageBoxW(NULL, msg.c_str(), L"\u52A0\u8F7D\u914D\u7F6E", MB_OK | MB_ICONINFORMATION);
}
}
void scanner::load_config(const wchar_t* file)
{
cfg_->load_from_file(file);
update_config();
}
void scanner::save_config(const wchar_t* file)
{
@ -236,14 +373,13 @@ void scanner::save_config(const wchar_t* file)
}
void scanner::apply_config(void)
{
std::string t(""), v(""), ver(cfg_->get_version());
std::string n(""), v(""), ver(cfg_->get_version());
std::wstring notice(L"");
if (cfg_->first_config(t, v))
if (cfg_->first_config(n, v))
{
bool rewrite = false;
do
{
int id = cfg_->id_from_title(t.c_str());
int id = cfg_->id_from_name(n.c_str());
if (id != -1)
{
void* data = &v[0];
@ -251,8 +387,9 @@ void scanner::apply_config(void)
const SANE_Option_Descriptor* desc = hg_sane_middleware::instance()->get_option_descriptor(handle_, id);
if (desc)
{
char* buf = NULL;
bool omit = false;
char* buf = NULL;
SANE_Int after = 0;
if (desc->type == SANE_TYPE_STRING)
{
buf = new char[desc->size + 4];
@ -260,42 +397,13 @@ void scanner::apply_config(void)
strcpy(buf, v.c_str());
data = buf;
}
else if (ver.empty() && desc->type == SANE_TYPE_FIXED) // 升级早期版本没将float转为SANE_Fixed的BUG
{
cfg_->remove_config(t.c_str());
rewrite = true;
omit = true;
hg_sane_middleware::instance()->set_option(handle_, id, SANE_ACTION_SET_VALUE, data, &after);
{
wchar_t msg[128] = { 0 };
std::wstring name(local_trans::a2u(t.c_str(), CP_UTF8));
unsigned char* f = (unsigned char*)&v[0];
notice += name + L"\r\n";
name.insert(0, L"Discard old configuration '");
swprintf_s(msg, _countof(msg) - 1, L"' of value '%02X%02X%02X%02X'\r\n", f[0], f[1], f[2], f[3]);
log_info((name + msg).c_str(), 0);
}
}
if (!omit)
{
SANE_Int after = 0;
hg_sane_middleware::instance()->set_option(handle_, id, SANE_ACTION_SET_VALUE, data, &after);
}
if (buf)
delete[] buf;
}
}
} while (cfg_->next_config(t, v));
if (rewrite)
{
cfg_->save_to(NULL);
if (notice.length())
{
notice.insert(0, L"\u4E0B\u5217\u914D\u7F6E\u6570\u636E\u9519\u8BEF\uFF0C\u5DF2\u7ECF\u6062\u590D\u5230\u9ED8\u8BA4\u503C\u3002\u5982\u679C\u9700\u8981\uFF0C\u8BF7\u91CD\u65B0\u8BBE\u7F6E\uFF1A\r\n\r\n");
MessageBoxW(NULL, notice.c_str(), L"\u52A0\u8F7D\u914D\u7F6E", MB_OK | MB_ICONINFORMATION);
}
}
} while (cfg_->next_config(n, v));
}
}
void scanner::on_ui_event(int uev, void* sender)
@ -391,7 +499,7 @@ int scanner::init_options_id(void)
break;
}
if (len)
cfg_->set_default_value(op_id, desc->title, (char*)val, len);
cfg_->set_default_value(op_id, desc->name, (char*)val, len);
local_utility::free_memory(val);
}
@ -501,6 +609,7 @@ int scanner::init_options_id(void)
ea.ex_api = &scanner::handle_ex_search_hole_range;
ex_opts_.push_back(ea);
}
return ret;
}
int scanner::control_read_string(int code, std::string& ret)
@ -2205,6 +2314,7 @@ COM_API_IMPLEMENT(scanner, int, twain_set_config(char* buf, size_t len))
{
if(cfg_->load_from_mem(buf))
{
update_config();
apply_config();
return SCANNER_ERR_OK;

View File

@ -53,6 +53,7 @@ class scanner : public ISaneInvoker, virtual public refer
std::unique_ptr<dlg_setting> setting_;
gb::sane_config* cfg_;
void update_config(void);
void load_config(const wchar_t* file);
void save_config(const wchar_t* file);
void apply_config(void);
@ -177,6 +178,7 @@ class scanner : public ISaneInvoker, virtual public refer
static int __stdcall to_int(SANE_Int v);
static float __stdcall to_float(SANE_Fixed v);
static void __stdcall ui_callback(int uev, void* sender, void* param);
static bool __stdcall is_option_float(int sn, void* param);
public:
scanner(SCANNERID id);