修改JSON以兼容APP配置

This commit is contained in:
gb 2022-10-26 14:41:18 +08:00
parent 93ad04eb6a
commit 6c350e3b05
3 changed files with 609 additions and 48 deletions

View File

@ -30,6 +30,29 @@ namespace gb
return ret; return ret;
} }
static int load_mini_file(const char* file, std::string& cont)
{
FILE* src = fopen(file, "rb");
if (src)
{
size_t size = 0;
char *buf = NULL;
fseek(src, 0, SEEK_END);
size = ftell(src);
fseek(src, 0, SEEK_SET);
buf = new char[size + 4];
memset(buf, 0, size + 4);
fread(buf, 1, size, src);
fclose(src);
cont = std::string(buf, size);
delete[] buf;
return 0;
}
else
return errno;
}
refer::refer() : ref_(1) refer::refer() : ref_(1)
{} {}
@ -856,19 +879,209 @@ namespace gb
} }
} }
namespace updater
{
static std::string hg_model_from_pid(const char* pid)
{
if (strcmp(pid, "7823") == 0)
return "G200";
char m[] = { 'G', pid[0], '0', '0', 0};
return std::string(m) + " - " + pid;
}
static std::string hv_model_from_pid(const char* pid)
{
std::string m("");
if (strcmp(pid, "1000") == 0)
m = "HW-1000NS";
else if (strcmp(pid, "1002") == 0)
m = "HW-1000";
else if (strcmp(pid, "7000") == 0)
m = "HW-7000NS";
else if (strcmp(pid, "7002") == 0)
m = "HW-7000";
else if (strcmp(pid, "7039") == 0)
m = "HW-7000NS";
else
m = std::string("HW-") + pid;
return m + " - " + pid;
}
static std::string lsc_model_from_pid(const char* pid)
{
if (strcmp(pid, "8200") == 0)
return "G42S - 8200";
else
{
char m[] = {'G', pid[1], pid[2], 'S', 0};
return std::string(m) + " - " + pid;
}
}
static std::string scanner_chinese_name_2_model(const char* cn)
{
static const char* hg = "\345\215\216\351\253\230",
* hw = "\346\261\211\347\216\213",
* lsc = "\347\253\213\346\200\235\350\276\260",
* smy = "\346\211\253\346\217\217\344\273\252\342\200\224G",
* f = strstr(cn, hg);
std::string model("");
std::string(* model_from_pid)(const char* pid) = nullptr;
if (f == cn)
{
model = "HUAGOSCAN ";
model_from_pid = hg_model_from_pid;;
}
else if (strstr(cn, hw) == cn)
{
model = "Hanvon ";
model_from_pid = hv_model_from_pid;;
}
else if (strstr(cn, lsc) == cn)
{
model = "LANXUMSCAN ";
model_from_pid = lsc_model_from_pid;;
}
else
return "";
f = strstr(cn, smy);
if (!f)
return "";
f += strlen(smy);
model += model_from_pid(f);
return model;
}
static int update_app_config(const char* scanner_name, const char* jsn_txt, const char* path, gb::scanner_cfg::LPUDF lpfunc)
{
std::string scanner(""), jsn_str(jsn_txt);
std::vector<std::string> efiles;
if ((unsigned char)scanner_name[0] > 0x7f)
scanner = scanner_chinese_name_2_model(scanner_name);
else
scanner = scanner_name;
gb::json* jsn = new gb::json();
int cur_sel = -1, ret = 0;
gb::scanner_cfg* cfg = nullptr;
if (!jsn->attach_text(&jsn_str[0]))
{
jsn->release();
return EINVAL;
}
if (jsn->first_child(jsn_str))
{
gb::json* child = new gb::json();
if (child->attach_text(&jsn_str[0]))
{
if (!child->get_value("cur_sel", cur_sel))
ret = EINVAL;
}
if (ret == 0)
{
cfg = new gb::scanner_cfg();
int ind = 0;
while (jsn->next_child(jsn_str))
{
if (!child->attach_text(&jsn_str[0]))
{
ret = EINVAL;
break;
}
std::string schm_name("");
if (!child->get_value("scheme", schm_name))
{
ret = EINVAL;
break;
}
gb::json* items = nullptr;
if (!child->get_value("opts", items) || !items)
{
ret = EINVAL;
break;
}
gb::sane_config_schm* schm = new gb::sane_config_schm();
if (items->first_child(jsn_str))
{
do
{
std::string name(""), val("");
gb::json* item = new gb::json();
if (item->attach_text(&jsn_str[0]))
{
if (item->get_value("name", name) && item->get_value("value", val))
{
name = lpfunc->title2name(name.c_str(), lpfunc->func_param);
lpfunc->trans_number(name.c_str(), val, lpfunc->func_param);
schm->set_value(name.c_str(), val.c_str(), val.length());
val = "";
item->get_value("extra", val);
if (val.length() && gb::load_mini_file(val.c_str(), val) == 0)
{
schm->set_value(name.c_str(), val.c_str(), val.length(), true);
item->get_value("extra", val);
efiles.push_back(val);
}
}
}
item->release();
} while (items->next_child(jsn_str));
}
items->release();
cfg->add_scheme(schm, schm_name.c_str());
schm->release();
if (ind++ == cur_sel)
cfg->select_scheme(schm_name.c_str());
}
}
child->release();
}
jsn->release();
if (cfg)
{
if (ret == 0)
{
cfg->save((path + scanner + ".cfg").c_str());
for (auto& v : efiles)
rename(v.c_str(), (v + "_bk").c_str());
}
cfg->release();
}
return ret;
}
}
namespace gb namespace gb
{ {
std::string sane_config_schm::opt_data_appendix_("_data"); std::string sane_config_schm::opt_data_appendix_("_data");
sane_config_schm::sane_config_schm() : jsn_(NULL), bkp_(NULL), in_setting_(false), scheme_name_("") sane_config_schm::sane_config_schm(scanner_cfg* scanner) : jsn_(NULL), bkp_(NULL), in_setting_(false), scheme_name_("")
, scanner_(scanner)
{ {
char empty[8] = { "{}" };
jsn_ = new gb::json();
jsn_->attach_text(empty);
def_val_ = new gb::json(); def_val_ = new gb::json();
if (scanner_)
scanner_->add_ref();
} }
sane_config_schm::~sane_config_schm() sane_config_schm::~sane_config_schm()
{ {
clear(); clear();
def_val_->release(); def_val_->release();
if (scanner_)
scanner_->release();
} }
bool sane_config_schm::hex(unsigned char ch, unsigned char* val) bool sane_config_schm::hex(unsigned char ch, unsigned char* val)
@ -936,7 +1149,7 @@ namespace gb
if (bkp_) if (bkp_)
bkp_->release(); bkp_->release();
bkp_ = NULL; bkp_ = NULL;
file_ = L""; // file_ = "";
} }
std::string sane_config_schm::to_hex_letter(const char* data, size_t bytes) std::string sane_config_schm::to_hex_letter(const char* data, size_t bytes)
{ {
@ -977,36 +1190,22 @@ namespace gb
return val; return val;
} }
bool sane_config_schm::load_from_file(const wchar_t* file) bool sane_config_schm::load_from_file(const char* file)
{ {
clear(); clear();
bool ret = false; std::string cont("");
FILE* src = _wfopen(file, L"rb");
if (src)
{
size_t size = 0;
char* buf = NULL;
gb::base64 b64;
fseek(src, 0, SEEK_END);
size = ftell(src);
fseek(src, 0, SEEK_SET);
buf = new char[size + 4];
memset(buf, 0, size + 4);
fread(buf, 1, size, src);
fclose(src);
ret = load_from_mem(buf);
delete[] buf;
}
file_ = file; file_ = file;
if (gb::load_mini_file(file, cont))
return false;
return ret; return load_from_mem(cont.c_str());
} }
bool sane_config_schm::load_from_mem(const char* mem) bool sane_config_schm::load_from_mem(const char* mem, bool in_b64)
{ {
gb::base64 b64; gb::base64 b64;
std::string stream(b64.decode(mem, lstrlenA(mem))); std::string stream(in_b64 ? b64.decode(mem, lstrlenA(mem)) : mem);
clear(); clear();
jsn_ = new gb::json(); jsn_ = new gb::json();
@ -1020,7 +1219,7 @@ namespace gb
return true; return true;
} }
bool sane_config_schm::save_to(const wchar_t* file) bool sane_config_schm::save_to(const char* file)
{ {
bool ret = false; bool ret = false;
std::string encode(to_text_stream()); std::string encode(to_text_stream());
@ -1030,7 +1229,7 @@ namespace gb
if (encode.length()) if (encode.length())
{ {
FILE* dst = _wfopen(file, L"wb"); FILE* dst = fopen(file, "wb");
if (dst) if (dst)
{ {
@ -1091,13 +1290,7 @@ namespace gb
} }
void sane_config_schm::config_changed(const char* name, const char* val, size_t bytes, bool extra) void sane_config_schm::config_changed(const char* name, const char* val, size_t bytes, bool extra)
{ {
std::string hex_v(to_hex_letter(val, bytes)), std::string hex_v(to_hex_letter(val, bytes));
def(default_value(name));
if (hex_v == def)
jsn_->remove(name);
else
jsn_->set_value(name, hex_v.c_str());
if (extra) if (extra)
{ {
@ -1105,7 +1298,7 @@ namespace gb
} }
else else
{ {
def = default_value(name); std::string def = default_value(name);
if (hex_v == def) if (hex_v == def)
{ {
jsn_->remove(name); jsn_->remove(name);
@ -1130,6 +1323,15 @@ namespace gb
if (jsn_) if (jsn_)
jsn_->remove(name); jsn_->remove(name);
} }
void sane_config_schm::set_value(const char* name, const char* val, size_t bytes, bool extra)
{
std::string hex_v(to_hex_letter(val, bytes));
if (extra)
jsn_->set_value((name + sane_config_schm::opt_data_appendix_).c_str(), hex_v.c_str());
else
jsn_->set_value(name, hex_v.c_str());
}
void sane_config_schm::end_setting(bool cancel) void sane_config_schm::end_setting(bool cancel)
{ {
if (in_setting_) if (in_setting_)
@ -1158,22 +1360,26 @@ namespace gb
return -1; return -1;
} }
std::string sane_config_schm::to_text_stream(void) std::string sane_config_schm::to_text_stream(bool b64, bool with_ver)
{ {
if (jsn_) if (jsn_)
{ {
if(with_ver)
{ {
char ver[40] = { 0 }; char ver[40] = { 0 };
sprintf_s(ver, "%u.%u", VERSION_MAIN, VERSION_SUB); sprintf_s(ver, "%u.%u", VERSION_MAIN, VERSION_SUB);
jsn_->set_value("ver", ver); jsn_->set_value("ver", ver);
} }
std::string cont(jsn_->to_string(false)), encode(""); std::string cont(jsn_->to_string(false));
if (b64)
{
gb::base64 b64; gb::base64 b64;
encode = b64.encode(cont.c_str(), cont.length()); cont = b64.encode(cont.c_str(), cont.length());
}
return encode; return cont;
} }
else else
return ""; return "";
@ -1254,4 +1460,284 @@ namespace gb
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// scanner_cfg // scanner_cfg
std::string scanner_cfg::global_name_ = "global";
std::string scanner_cfg::cur_sel_ = "cur";
std::string scanner_cfg::default_setting_name_ = "\351\273\230\350\256\244\350\256\276\347\275\256"; // utf-8: 默认设置
scanner_cfg::scanner_cfg() : path_(""), scanner_name_(""), global_(new json())
{
init_version();
init_select();
}
scanner_cfg::~scanner_cfg()
{
clear();
global_->release();
}
bool scanner_cfg::update(const char* file, LPUDF func)
{
std::string cont(""), name(""), path(file);
int ret = gb::load_mini_file(file, cont);
base64 b64;
json *jsn = nullptr;
bool ok = true;
if (ret)
return false;
else if (cont.empty())
return true;
cont = b64.decode(cont.c_str(), cont.length());
jsn = new json();
if (!jsn->attach_text(&cont[0]))
{
jsn->release();
return false;
}
cont = "";
ret = path.rfind(PATH_SYMBOL[0]);
if (ret++ != std::string::npos)
path.erase(ret);
if (jsn->first_child(cont, &name))
{
do
{
ok &= updater::update_app_config(name.c_str(), cont.c_str(), path.c_str(), func) == 0;
} while (jsn->next_child(cont, &name));
}
jsn->release();
if (ok)
rename(file, (std::string(file) + "_bk").c_str());
return true;
}
void scanner_cfg::clear(void)
{
global_->set_value("ver", "");
global_->set_value(scanner_cfg::cur_sel_.c_str(), -1);
for (size_t i = 0; i < schemes_.size(); ++i)
schemes_[i].schm->release();
schemes_.clear();
scanner_name_ = "";
}
void scanner_cfg::init_version(void)
{
char vstr[40] = { 0 };
sprintf(vstr, "%u.%u", VERSION_MAIN, VERSION_SUB);
global_->set_value("ver", vstr);
}
void scanner_cfg::init_select(void)
{
global_->set_value(scanner_cfg::cur_sel_.c_str(), -1);
}
void scanner_cfg::walk_sibling_schemes(cJSON* first)
{
if (!first)
return;
cJSON* next = first->next;
std::string name(first->string ? "" : first->string),
cont("");
CFGSCHM sch;
first->next = nullptr;
cont = json::to_string(first, false);
if (name == scanner_cfg::global_name_)
{
global_->attach_text(&cont[0]);
}
else
{
sch.schm = new sane_config_schm();
if (sch.schm->load_from_mem(cont.c_str(), false))
{
sch.name = sane_config_schm::from_hex_letter(name.c_str(), name.length());
sch.schm->set_scheme_name(sch.name.c_str());
schemes_.push_back(sch);
}
else
sch.schm->release();
}
first->next = next;
walk_sibling_schemes(next);
}
int scanner_cfg::load_file(const char* file)
{
std::string cont("");
int ret = gb::load_mini_file(file, cont);
if (ret == 0)
ret = load_mem(cont.c_str());
if (ret == 0 && scanner_name_.empty())
{
const char* name = strrchr(file, PATH_SYMBOL[0]);
if (name++ == nullptr)
name = file;
scanner_name_ = name;
ret = scanner_name_.rfind('.');
if (ret != std::string::npos)
scanner_name_.erase(ret);
ret = 0;
}
return ret;
}
int scanner_cfg::load_mem(const char* mem)
{
cJSON* root = cJSON_Parse(mem);
if (!root)
return EINVAL;
clear();
walk_sibling_schemes(root->child);
cJSON_Delete(root);
return 0;
}
int scanner_cfg::save(const char* file)
{
if (!file && path_.empty() && scanner_name_.empty())
return EINVAL;
std::string cont("{\"" + scanner_cfg::global_name_ + "\":"),
f(file ? file : path_ + scanner_name_),
v("");
int sel = -1;
if (!global_->get_value("ver", v) || v.empty())
init_version();
if (!global_->get_value(scanner_cfg::cur_sel_.c_str(), sel) || sel >= schemes_.size())
init_select();
cont += global_->to_string(false);
for (auto& v: schemes_)
{
cont += ",\"" + sane_config_schm::to_hex_letter(v.name.c_str(), v.name.length()) + "\":";
cont += v.schm->to_text_stream(false, false);
}
cont += "}";
base64 b64;
FILE* dst = fopen(f.c_str(), "wb");
if (!dst)
return errno;
f = b64.encode(cont.c_str(), cont.length());
fwrite(f.c_str(), 1, f.length(), dst);
fclose(dst);
return 0;
}
void scanner_cfg::get_all_schemes(std::vector<std::string>& schemes)
{
schemes.push_back(scanner_cfg::default_setting_name_);
for (auto& v : schemes_)
schemes.push_back(v.name);
}
sane_config_schm* scanner_cfg::get_scheme(const char* scheme_name)
{
sane_config_schm* found = nullptr;
if (scheme_name)
{
std::vector<CFGSCHM>::iterator it = std::find(schemes_.begin(), schemes_.end(), scheme_name);
if (it != schemes_.end())
found = it->schm;
}
else
{
int ind = -1;
global_->get_value(scanner_cfg::cur_sel_.c_str(), ind);
if (ind >= 0 && ind < schemes_.size())
found = schemes_[ind].schm;
}
if (found)
found->add_ref();
return found;
}
bool scanner_cfg::remove_scheme(const char* scheme_name)
{
std::vector<CFGSCHM>::iterator it = std::find(schemes_.begin(), schemes_.end(), scheme_name);
if (it != schemes_.end())
{
int id = it - schemes_.begin(),
ind = -1;
it->schm->release();
schemes_.erase(it);
global_->get_value(scanner_cfg::cur_sel_.c_str(), ind);
if (ind == id)
global_->set_value(scanner_cfg::cur_sel_.c_str(), -1);
else if (ind > id)
global_->set_value(scanner_cfg::cur_sel_.c_str(), ind - 1);
return true;
}
return false;
}
bool scanner_cfg::select_scheme(const char* scheme_name)
{
std::vector<CFGSCHM>::iterator it = std::find(schemes_.begin(), schemes_.end(), scheme_name);
if (it == schemes_.end())
global_->set_value(scanner_cfg::cur_sel_.c_str(), -1);
else
global_->set_value(scanner_cfg::cur_sel_.c_str(), it - schemes_.begin());
return true;
}
sane_config_schm* scanner_cfg::copy_scheme(const char* cp_from_name) // for UI setting, call release() if not use anymore
{
if (!cp_from_name)
return nullptr;
else if (scanner_cfg::default_setting_name_ == cp_from_name)
return new sane_config_schm();
else
{
std::vector<CFGSCHM>::iterator it = std::find(schemes_.begin(), schemes_.end(), cp_from_name);
if (it == schemes_.end())
return nullptr;
std::string cont(it->schm->to_text_stream());
sane_config_schm* schm = new sane_config_schm();
schm->load_from_mem(cont.c_str());
return schm;
}
}
bool scanner_cfg::add_scheme(sane_config_schm* schm, const char* name)
{
if (name && std::find(schemes_.begin(), schemes_.end(), name) != schemes_.end())
return false;
CFGSCHM cs;
cs.name = name ? name : schm->get_scheme_name();
cs.schm = schm;
if (cs.name == scanner_cfg::global_name_)
return false;
schemes_.push_back(cs);
schm->set_scheme_name(cs.name.c_str());
schm->add_ref();
return true;
}
} }

View File

@ -2,6 +2,9 @@
#if defined(WIN32) || defined(_WIN64) #if defined(WIN32) || defined(_WIN64)
#include <Windows.h> #include <Windows.h>
#define PATH_SYMBOL "\\"
#else
#define PATH_SYMBOL "/"
#endif #endif
// #include "cJSON.h" // #include "cJSON.h"
@ -12,6 +15,7 @@
namespace gb namespace gb
{ {
class scanner_cfg;
class refer class refer
{ {
volatile long ref_; volatile long ref_;
@ -101,7 +105,8 @@ namespace gb
class sane_config_schm : public refer class sane_config_schm : public refer
{ {
std::string scheme_name_; std::string scheme_name_;
std::wstring file_; scanner_cfg *scanner_;
std::string file_;
json* jsn_; json* jsn_;
json* bkp_; json* bkp_;
json* def_val_; json* def_val_;
@ -109,25 +114,25 @@ namespace gb
std::map<int, std::string> id_name_; // (id, default-val) std::map<int, std::string> id_name_; // (id, default-val)
void clear(); 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* name); std::string default_value(const char* name);
protected: protected:
~sane_config_schm(); ~sane_config_schm();
public: public:
sane_config_schm(); sane_config_schm(scanner_cfg* scanner = nullptr);
static std::string opt_data_appendix_; static std::string opt_data_appendix_;
static bool hex(unsigned char ch, unsigned char* val); static bool hex(unsigned char ch, unsigned char* val);
static bool hex_char(const char* data, unsigned char* val); static bool hex_char(const char* data, unsigned char* val);
static std::string to_hex_letter(const char* data, size_t bytes);
static std::string from_hex_letter(const char* data, size_t bytes);
static bool is_option_data(std::string& name); // reset baase option name into 'name' if name was option data, and return true static bool is_option_data(std::string& name); // reset baase option name into 'name' if name was option data, and return true
public: public:
bool load_from_file(const wchar_t* file); bool load_from_file(const char* file);
bool load_from_mem(const char* mem); bool load_from_mem(const char* mem, bool in_b64 = true);
bool save_to(const wchar_t* file); bool save_to(const char* file);
void set_default_value(int sn, const char* name, const char* val, size_t bytes); 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 first_config(std::string& name, std::string& val);
bool next_config(std::string& name, std::string& val); bool next_config(std::string& name, std::string& val);
@ -135,12 +140,82 @@ namespace gb
void config_changed(const char* name, const char* val, size_t bytes, bool extra = false); void config_changed(const char* name, const char* val, size_t bytes, bool extra = false);
void config_changed(int sn, const char* val, size_t bytes, bool extra = false); void config_changed(int sn, const char* val, size_t bytes, bool extra = false);
void remove_config(const char* name); void remove_config(const char* name);
void set_value(const char* name, const char* val, size_t bytes, bool extra = false);
void end_setting(bool cancel); void end_setting(bool cancel);
int id_from_name(const char* name); int id_from_name(const char* name);
std::string to_text_stream(void); std::string to_text_stream(bool b64 = true, bool with_ver = true);
std::string get_version(void); std::string get_version(void);
std::string get_scheme_name(void); std::string get_scheme_name(void);
void set_scheme_name(const char* name); void set_scheme_name(const char* name);
void update(bool(__stdcall* is_float)(int, void*), void* param, const char*(__stdcall* t2n)(const char*), std::string* discard = NULL); void update(bool(__stdcall* is_float)(int, void*), void* param, const char*(__stdcall* t2n)(const char*), std::string* discard = NULL);
}; };
class scanner_cfg : public refer
{
// format: in base64
//
// {
// "global": {
// "ver": "4.33",
// "cur": -1
// },
// "scheme_1": sane_config_schm*,
// "scheme_2": sane_config_schm*,
// "scheme_3": sane_config_schm*,
// ...
// }
//
std::string path_;
std::string scanner_name_; // scanner type: HUAGOSCAN G100 - 0100
json *global_; // version, current scheme, ...
typedef struct _cfg_schm
{
std::string name;
sane_config_schm* schm;
bool operator==(const char* n)
{
return name == n;
}
}CFGSCHM;
std::vector<CFGSCHM> schemes_;
static std::string global_name_;
static std::string cur_sel_;
static std::string default_setting_name_;
void clear(void);
void init_version(void);
void init_select(void);
void walk_sibling_schemes(cJSON* first);
protected:
~scanner_cfg();
public:
scanner_cfg();
typedef struct _update_func
{
void(__stdcall* trans_number)(const char* name, std::string& val, void* param);
const char* (__stdcall* title2name)(const char* title, void* param);
std::string discard_msg; // update failed items ...
void* func_param;
}UDF, *LPUDF;
static bool update(const char* file, LPUDF func);
public:
int load_file(const char* file);
int load_mem(const char* mem);
int save(const char* file = nullptr);
void get_all_schemes(std::vector<std::string>& schemes); // return all schemes name queue, the first is always be 'Default settings'
sane_config_schm* get_scheme(const char* scheme_name = nullptr/*return current scheme if was null*/); // call sane_config_schm::release() if not use anymore
bool remove_scheme(const char* scheme_name);
bool select_scheme(const char* scheme_name);
sane_config_schm* copy_scheme(const char* cp_from_name); // for UI setting, call release() if not use anymore
bool add_scheme(sane_config_schm* schm, const char* name = nullptr);
};
} }

View File

@ -559,12 +559,12 @@ void scanner::update_config(void)
} }
void scanner::load_config(const wchar_t* file) void scanner::load_config(const wchar_t* file)
{ {
cfg_->load_from_file(file); cfg_->load_from_file(local_trans::u2a(file).c_str());
update_config(); update_config();
} }
void scanner::save_config(const wchar_t* file) void scanner::save_config(const wchar_t* file)
{ {
cfg_->save_to(file); cfg_->save_to(local_trans::u2a(file).c_str());
} }
void scanner::apply_config(void) void scanner::apply_config(void)
{ {