#include "gb_json.h" #include #include #include "../../sdk/include/huagao/brand.h" #include "../../sdk/include/sane/sane_ex.h" #if defined(WIN32) || defined(_WIN64) #define bzero(b, s) memset(b, 0, s) #endif namespace special_char_trans { struct { const char* writedown_text; char readable_char; }transferred_chars[] = { { "\\\"", '\"' } , { "\\'", '\'' } , { "\\a", '\a' } , { "\\b", '\b' } , { "\\f", '\f' } , { "\\n", '\n' } , { "\\r", '\r' } , { "\\t", '\t' } , { "\\v", '\v' } // , { "\\?", '\?' } , { "\\\\", '\\' } , { "\\/", '/' } // , { "\\0", '\0' } }; void to_writedown(std::string& str) { std::string trans(str); const char* ptr = trans.c_str(); str.clear(); while (*ptr) { bool rep = false; if (*ptr == '\\') { if (ptr[1] == '\\') { str += "\\\\"; ptr++; rep = true; } else if (ptr[1] == '/' || ptr[1] == 'a' || ptr[1] == 'b' || ptr[1] == 'f' || ptr[1] == 'n' || ptr[1] == 'r' || ptr[1] == 't' || ptr[1] == 'u' || ptr[1] == 'v') { str += "\\"; ptr++; } else { str += "\\\\"; rep = true; } } else { for (size_t i = 0; i < sizeof(transferred_chars) / sizeof(transferred_chars[0]); ++i) { if (*ptr == transferred_chars[i].readable_char) { str += transferred_chars[i].writedown_text; rep = true; break; } } } if (!rep) str.append(1, *ptr); ptr++; } } } namespace gb { static std::vector split_with(const char* str, const char* splitor = "/") { std::vector ret; std::string src(str); size_t pos = src.find(splitor); while(pos != std::string::npos) { if(pos++) ret.push_back(src.substr(0, pos - 1)); src.erase(0, pos + strlen(splitor)); pos = src.find(splitor); } if(src.length()) ret.push_back(src); 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() {} long refer::add_ref(void) { #if defined(WIN32) || defined(_WIN64) return InterlockedIncrement(&ref_); #else return ++ref_; #endif } long refer::release(void) { #if defined(WIN32) || defined(_WIN64) long ref = InterlockedDecrement(&ref_); #else long ref = --ref_; #endif if (ref == 0) delete this; return ref; } json::json(char* json_txt) : type_(VAL_TYPE_OBJECT), key_(""), strval_(""), cur_child_(-1) { simple_val_.dval = .0f; if (json_txt) attach_text(json_txt); } json::json(const char* key, bool val) : type_(VAL_TYPE_BOOL), key_(key ? key : ""), strval_(""), cur_child_(-1) { simple_val_.bval = val; } json::json(const char* key, int val) : type_(VAL_TYPE_INT), key_(key ? key : ""), strval_(""), cur_child_(-1) { simple_val_.nval = val; } json::json(const char* key, double val) : type_(VAL_TYPE_FLOAT), key_(key ? key : ""), strval_(""), cur_child_(-1) { simple_val_.dval = val; } json::json(const char* key, const char* val) : type_(VAL_TYPE_STRING), key_(key ? key : ""), strval_(val ? val : ""), cur_child_(-1) { } json::json(json& r) { copy_from(r); } json::~json() { clear(); } std::string json::object_key(json* jsn) { return "\"" + jsn->key() + "\":"; } std::string json::array_key(json* jsn) { return ""; } void json::from_cjson(cJSON* cj) { key_ = cj && cj->string ? cj->string : ""; while (cj) { json* child = nullptr; if (cj->type == cJSON_True) { child = new json(cj->string, true); } else if (cj->type == cJSON_False) { child = new json(cj->string, false); } else if (cj->type == cJSON_Number) { if (cj->valuedouble - (int)cj->valuedouble < .00001) { child = new json(cj->string, cj->valueint); } else { child = new json(cj->string, cj->valuedouble); } } else if (cj->type == cJSON_String) { child = new json(cj->string, cj->valuestring); } else if (cj->type == cJSON_Object || cj->type == cJSON_Array) { child = new json(); child->from_cjson(cj->child); child->key_ = cj->string ? cj->string : ""; } arr_val_.push_back(child); cj = cj->next; } //if (arr_val_.size() == 1 && arr_val_[0]->arr_val_.size() == 0) //{ // json* child = arr_val_[0]; // // if (!child->key_.empty()) // array // { // arr_val_.clear(); // type_ = child->type_; // key_ = child->key_; // simple_val_.dval = child->simple_val_.dval; // strval_ = child->strval_; // for (auto& v : child->arr_val_) // arr_val_.push_back(v); // child->arr_val_.clear(); // child->release(); // } //} if (arr_val_.size()) { type_ = arr_val_[0]->key().empty() ? VAL_TYPE_ARRAY : VAL_TYPE_OBJECT; } } json* json::find_child(const char* key, bool remove) { json* ret = nullptr; if (type_ == VAL_TYPE_OBJECT) { for (size_t i = 0; i < arr_val_.size(); ++i) { if (arr_val_[i]->key() == key) { ret = arr_val_[i]; if (remove) arr_val_.erase(arr_val_.begin() + i); else ret->add_ref(); break; } } } return ret; } void json::copy_from(json& r) { clear(); type_ = r.type_; key_ = r.key_; simple_val_.dval = r.simple_val_.dval; strval_ = r.strval_; for (auto& v : r.arr_val_) arr_val_.push_back(new json(*v)); } bool json::attach_text(char* json_txt) { clear(); cJSON* jsn = cJSON_Parse(json_txt); if (jsn) { char* text = cJSON_Print(jsn); if (text) free(text); from_cjson(jsn->child); cJSON_Delete(jsn); return true; } return false; } void json::clear(bool as_array) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { for (auto& v : arr_val_) v->release(); } type_ = as_array ? VAL_TYPE_ARRAY : VAL_TYPE_OBJECT; simple_val_.dval = .0f; key_ = ""; strval_ = ""; arr_val_.clear(); cur_child_ = -1; } std::string json::to_string(void) { if (type_ == VAL_TYPE_NULL) return ""; if (type_ == VAL_TYPE_BOOL) return (simple_val_.bval ? "true" : "false"); if (type_ == VAL_TYPE_INT) return std::to_string(simple_val_.nval); if (type_ == VAL_TYPE_FLOAT) return std::to_string(simple_val_.dval); if (type_ == VAL_TYPE_STRING) { char* u = cJSON_utf8_2_unic(strval_.c_str()); std::string r(u); free(u); special_char_trans::to_writedown(r); return "\"" + r + "\""; } std::string(*k)(json*) = type_ == VAL_TYPE_OBJECT ? json::object_key : json::array_key; std::string str(type_ == VAL_TYPE_OBJECT ? "{" : "["); if (arr_val_.size()) { str += k(arr_val_[0]) + arr_val_[0]->to_string(); for (size_t i = 1; i < arr_val_.size(); ++i) str += "," + k(arr_val_[i]) + arr_val_[i]->to_string(); } str += type_ == VAL_TYPE_OBJECT ? "}" : "]"; return str; } std::string& json::key(void) { return key_; } bool json::is_array(void) { return type_ == VAL_TYPE_ARRAY; } bool json::is_leaf_node(void) { return type_ == VAL_TYPE_BOOL || type_ == VAL_TYPE_INT || type_ == VAL_TYPE_FLOAT || type_ == VAL_TYPE_STRING; } bool json::get_value(const char* key, bool& val) { bool ret = false; json* child = find_child(key); if (child) { if (child->type_ == VAL_TYPE_BOOL) { val = child->simple_val_.bval; ret = true; } child->release(); } else if (type_ == VAL_TYPE_BOOL && key_ == key) { val = simple_val_.bval; ret = true; } return ret; } bool json::get_value(const char* key, int& val) { bool ret = false; json* child = find_child(key); if (child) { if (child->type_ == VAL_TYPE_INT) { val = child->simple_val_.nval; ret = true; } child->release(); } else if (type_ == VAL_TYPE_INT && key_ == key) { val = simple_val_.nval; ret = true; } return ret; } bool json::get_value(const char* key, double& val) { bool ret = false; json* child = find_child(key); if (child) { if (child->type_ == VAL_TYPE_FLOAT) { val = child->simple_val_.dval; ret = true; } child->release(); } else if (type_ == VAL_TYPE_FLOAT && key_ == key) { val = simple_val_.dval; ret = true; } return ret; } bool json::get_value(const char* key, std::string& val) { bool ret = false; json* child = find_child(key); if (child) { if (child->type_ == VAL_TYPE_STRING) { val = child->strval_; ret = true; } child->release(); } else if (type_ == VAL_TYPE_STRING && key_ == key) { val = strval_; ret = true; } return ret; } bool json::get_value(const char* key, json*& val) { bool ret = false; json* child = find_child(key); if (child) { if (child->type_ == VAL_TYPE_OBJECT) { val = child; ret = true; } else { child->release(); } } return ret; } size_t json::children(void) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) return arr_val_.size(); else return -1; } json* json::child(size_t ind) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { if (ind >= 0 && ind < arr_val_.size()) { arr_val_[ind]->add_ref(); return arr_val_[ind]; } } return nullptr; } json* json::first_child(void) { cur_child_ = 0; if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY) { if (arr_val_.size()) { arr_val_[0]->add_ref(); return arr_val_[0]; } } return nullptr; // leaf node, return self //add_ref(); //return this; } json* json::next_child(void) { if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY) { if (++cur_child_ < arr_val_.size()) { arr_val_[cur_child_]->add_ref(); return arr_val_[cur_child_]; } } return nullptr; } bool json::set_value(const char* key, bool val) { if (type_ != VAL_TYPE_OBJECT) return false; json* child = find_child(key); if (child) { child->clear(); child->type_ = VAL_TYPE_BOOL; child->key() = key ? key : ""; child->simple_val_.bval = val; child->release(); } else { child = new json(key, val); arr_val_.push_back(child); } return true; } bool json::set_value(const char* key, int val) { if (type_ != VAL_TYPE_OBJECT) return false; json* child = find_child(key); if (child) { child->clear(); child->type_ = VAL_TYPE_INT; child->key() = key ? key : ""; child->simple_val_.nval = val; child->release(); } else { child = new json(key, val); arr_val_.push_back(child); } return true; } bool json::set_value(const char* key, double val) { if (type_ != VAL_TYPE_OBJECT) return false; json* child = find_child(key); if (child) { child->clear(); child->type_ = VAL_TYPE_FLOAT; child->key() = key ? key : ""; child->simple_val_.dval = val; child->release(); } else { child = new json(key, val); arr_val_.push_back(child); } return true; } bool json::set_value(const char* key, const char* val) { if (type_ != VAL_TYPE_OBJECT) return false; json* child = find_child(key); if (child) { child->clear(); child->type_ = VAL_TYPE_STRING; child->key() = key ? key : ""; child->strval_ = val ? val : ""; child->release(); } else { child = new json(key, val); arr_val_.push_back(child); } return true; } bool json::set_value(const char* key, json* val) { if (type_ != VAL_TYPE_OBJECT) return false; for (size_t i = 0; i < arr_val_.size(); ++i) { if (arr_val_[i]->key() == key) { arr_val_[i]->release(); arr_val_[i] = val; val->add_ref(); return true; } } arr_val_.push_back(val); val->key() = key; val->add_ref(); return true; } json& json::operator+=(bool val) { if (type_ == VAL_TYPE_ARRAY) { json* child = new json(nullptr, val); arr_val_.push_back(child); } return *this; } json& json::operator+=(int val) { if (type_ == VAL_TYPE_ARRAY) { json* child = new json(nullptr, val); arr_val_.push_back(child); } return *this; } json& json::operator+=(double val) { if (type_ == VAL_TYPE_ARRAY) { json* child = new json(nullptr, val); arr_val_.push_back(child); } return *this; } json& json::operator+=(const char* val) { if (type_ == VAL_TYPE_ARRAY) { json* child = new json(nullptr, val); arr_val_.push_back(child); } return *this; } json& json::operator+=(json* val) { if (type_ == VAL_TYPE_ARRAY) { val->add_ref(); arr_val_.push_back(val); } return *this; } json& json::operator-=(int ind) { remove(ind); return *this; } bool json::remove(const char* key) { json* child = find_child(key, true); if (child) { child->release(); return true; } else { return false; } } bool json::remove(json* child) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { for (size_t i = 0; i < arr_val_.size(); ++i) { if (arr_val_[i] == child) { arr_val_[i]->release(); arr_val_.erase(arr_val_.begin() + i); return true; } } } return false; } bool json::remove(int ind) { bool ret = false; if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { if (ind >= 0 && ind < arr_val_.size()) { arr_val_[ind]->release(); arr_val_.erase(arr_val_.begin() + ind); ret = true; } } return ret; } int json::index(json* child) { if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT) { for (int i = 0; i < arr_val_.size(); ++i) { if (arr_val_[i] == child) return i; } } return -1; } int json::index_move_to(json* child, int ind) { int i = index(child); if (i == -1) return -1; arr_val_.erase(arr_val_.begin() + i); if (ind < 0) ind = 0; if (ind > arr_val_.size()) ind = arr_val_.size(); arr_val_.insert(arr_val_.begin() + ind, child); return ind; } bool json::value(bool& val) { bool ret = false; if (is_leaf_node() && type_ == VAL_TYPE_BOOL) { val = simple_val_.bval; ret = true; } return ret; } bool json::value(int& val) { bool ret = false; if (is_leaf_node() && type_ == VAL_TYPE_INT) { val = simple_val_.nval; ret = true; } return ret; } bool json::value(double& val) { bool ret = false; if (is_leaf_node() && type_ == VAL_TYPE_FLOAT) { val = simple_val_.dval; ret = true; } return ret; } bool json::value(std::string& val) { bool ret = false; if (is_leaf_node() && type_ == VAL_TYPE_STRING) { val = strval_; ret = true; } return ret; } json& json::operator=(bool val) { if (is_leaf_node()) { simple_val_.bval = val; type_ = VAL_TYPE_BOOL; } return *this; } json& json::operator=(int val) { if (is_leaf_node()) { simple_val_.nval = val; type_ = VAL_TYPE_INT; } return *this; } json& json::operator=(double val) { if (is_leaf_node()) { simple_val_.dval = val; type_ = VAL_TYPE_FLOAT; } return *this; } json& json::operator=(const char* val) { if (is_leaf_node()) { strval_ = val ? val : ""; type_ = VAL_TYPE_STRING; } return *this; } } namespace gb { static char base64_default_table[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" }; base64::base64() : padding_char_('=') { base64_ind_[0] = base64_char_[0] = 0; initialize_base64_table(base64_default_table); } base64::~base64() {} bool base64::is_valid_base64_table(const char* table) { bool valid = false; if (table && strlen(table) >= 64) { char repeat[4] = { 0 }; valid = true; for (int i = 0; i < 63; ++i) { repeat[0] = table[i]; if (strstr(table + i + 1, repeat)) { valid = false; break; } } } return valid; } bool base64::initialize_base64_table(const char* table) { if (!table || strlen(table) < 64) { if (memcmp(base64_default_table, base64_char_, 64) == 0) { return !table; } memcpy(base64_char_, base64_default_table, 64); } else { if (memcmp(base64_char_, table, 64) == 0) { return true; } else if (!is_valid_base64_table(table)) return false; memcpy(base64_char_, table, 64); } base64_char_[64] = base64_char_[65] = 0; // initialize base64_index memset(base64_ind_, 0, sizeof(base64_ind_)); for (int i = 0; i < 64; ++i) { base64_ind_[base64_char_[i]] = i; } // padding char padding_char_ = '='; if (base64_ind_[padding_char_]) { for (padding_char_ = 0x21; padding_char_ < 0x7e && base64_ind_[padding_char_] && padding_char_ != base64_char_[0]; ++padding_char_); } return padding_char_ < 0x7e; } bool base64::set_base64_table(const char* table) { return initialize_base64_table(table ? table : base64_default_table); } std::string base64::encode(const char* data, size_t bytes, unsigned int line_bytes, bool need_padding) { char* str = (char*)malloc(bytes * 2 + 3); unsigned char c1 = 0, c2 = 0, c3 = 0; unsigned long line_len = 0; unsigned long words = bytes / 3; int rest = bytes % 3, pos = 0; std::string ret(""); for (unsigned long i = 0; i < words; ++i) { // fetch 3 letters c1 = *data++; c2 = *data++; c3 = *data++; // encoding into 4-bytes str[pos++] = base64_char_[c1 >> 2]; str[pos++] = base64_char_[((c1 << 4) | (c2 >> 4)) & 0x3f]; str[pos++] = base64_char_[((c2 << 2) | (c3 >> 6)) & 0x3f]; str[pos++] = base64_char_[c3 & 0x3f]; line_len += 4; // new line ... if ((unsigned int)line_len > line_bytes - 4) { str[pos++] = '\r'; str[pos++] = '\n'; line_len = 0; } } // rest ... if (rest == 1) { c1 = *data++; str[pos++] = base64_char_[(c1 & 0xfc) >> 2]; str[pos++] = base64_char_[((c1 & 0x03) << 4)]; if (need_padding) { str[pos++] = padding_char_; str[pos++] = padding_char_; } } else if (rest == 2) { c1 = *data++; c2 = *data++; str[pos++] = base64_char_[(c1 & 0xfc) >> 2]; str[pos++] = base64_char_[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)]; str[pos++] = base64_char_[((c2 & 0x0f) << 2)]; if (need_padding) { str[pos++] = padding_char_; } } if (pos > 0) { str[pos++] = 0; ret = std::string(str, pos - 1); } free(str); return std::move(ret); } std::string base64::decode(const char* data, size_t bytes) { char* str = (char*)malloc(bytes + 1); int pos = 0, shifts = 18, value = 0; std::string ret(""); for (int i = 0; i < (int)bytes; ++i) { if (*data != '\r' && *data != '\n') { if (*data == padding_char_) { break; } value += base64_ind_[*data] << shifts; if (shifts == 0) { shifts = 18; str[pos++] = (value >> 16) & 0x0ff; str[pos++] = (value >> 8) & 0x0ff; str[pos++] = (value >> 0) & 0x0ff; value = 0; } else { shifts -= 6; } } data++; } if (shifts == 12 || shifts == 6) { str[pos++] = (value >> 16) & 0x0ff; } else if (shifts == 0) { str[pos++] = (value >> 16) & 0x0ff; str[pos++] = (value >> 8) & 0x0ff; } if (pos > 0) { str[pos++] = 0; ret = std::string(str, pos - 1); } free(str); return std::move(ret); } } 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; } } namespace gb { std::string sane_config_schm::opt_data_appendix_("_data"); std::string sane_config_schm::opt_def_id_appendix_("_id"); std::string sane_config_schm::opt_def_val_appendix_("_val"); std::string sane_config_schm::opt_def_type_appendix_("_type"); std::string sane_config_schm::opt_def_title_appendix_("_title"); sane_config_schm::sane_config_schm(scanner_cfg* scanner) : jsn_(nullptr), bkp_(nullptr), in_setting_(false), scheme_name_("") , scanner_(scanner) { char empty[8] = { "{}" }; jsn_ = new gb::json(); jsn_->attach_text(empty); if (scanner_) { scanner_->add_ref(); def_val_ = scanner_->get_option_default_value(); } else def_val_ = new gb::json(); } sane_config_schm::~sane_config_schm() { clear(); def_val_->release(); if (scanner_) scanner_->release(); } bool sane_config_schm::hex(unsigned char ch, unsigned char* val) { bool ret = true; if (ch >= '0' && ch <= '9') ch -= '0'; else if (ch >= 'a' && ch <= 'f') ch = ch - 'a' + 10; else if (ch >= 'A' && ch <= 'F') ch = ch - 'A' + 10; else ret = false; if (ret && val) { *val &= 0x0f0; *val |= ch; } return ret; } bool sane_config_schm::hex_char(const char* data, unsigned char* val) { unsigned char v = 0; bool ret = false; if (sane_config_schm::hex(*data++, &v)) { v <<= 4; if (sane_config_schm::hex(*data++, &v)) { if (val) *val = v; ret = true; } } return ret; } std::string sane_config_schm::to_hex_letter(const char* data, size_t bytes) { std::string hex(""); const unsigned char* ptr = (const unsigned char*)data; char buf[8] = { 0 }; for (size_t i = 0; i < bytes; ++i) { sprintf(buf, "%02X", ptr[i]); hex += buf; } return hex; } std::string sane_config_schm::from_hex_letter(const char* data, size_t bytes) { std::string stream(""); bytes /= 2; for (size_t i = 0; i < bytes; ++i) { unsigned char ch = 0; if (!sane_config_schm::hex_char(data, &ch)) break; stream.append(1, ch); data += 2; } return stream; } bool sane_config_schm::is_option_data(std::string& name) { size_t pos = name.find(sane_config_schm::opt_data_appendix_); if (pos != std::string::npos) { if (pos + sane_config_schm::opt_data_appendix_.length() == name.length()) { name.erase(pos); return true; } } return false; } void sane_config_schm::set_default_value(json* jsn, int id, const char* name, const char* title, void* data, size_t bytes, int type) { std::string key(name); jsn->set_value(std::to_string(id).c_str(), name); jsn->set_value((name + sane_config_schm::opt_def_id_appendix_).c_str(), id); jsn->set_value((name + sane_config_schm::opt_def_val_appendix_).c_str(), sane_config_schm::to_hex_letter((const char*)data, bytes).c_str()); jsn->set_value((name + sane_config_schm::opt_def_type_appendix_).c_str(), type); jsn->set_value((name + sane_config_schm::opt_def_title_appendix_).c_str(), title); } int sane_config_schm::option_name_2_id(json* jsn, const char* name) { int id = -1; return jsn->get_value((std::string(name) + sane_config_schm::opt_def_id_appendix_).c_str(), id) ? id : -1; } int sane_config_schm::option_type(json* jsn, const char* name) { int id = -1; return jsn->get_value((std::string(name) + sane_config_schm::opt_def_type_appendix_).c_str(), id) ? id : -1; } std::string sane_config_schm::option_title(json* jsn, const char* name) { std::string title(""); jsn->get_value((std::string(name) + sane_config_schm::opt_def_title_appendix_).c_str(), title); return std::move(title); } std::string sane_config_schm::option_default_value(json* jsn, const char* name) { std::string val(""); return jsn->get_value((std::string(name) + sane_config_schm::opt_def_val_appendix_).c_str(), val) ? std::move(val) : ""; } std::string sane_config_schm::sane_option_value_2_string(void* val, size_t bytes, int type) { char buf[80] = { 0 }; switch (type) { case SANE_TYPE_BOOL: return *((SANE_Bool*)val) == SANE_TRUE ? "true" : "false"; break; case SANE_TYPE_INT: return std::to_string(*(SANE_Int*)val); break; case SANE_TYPE_FIXED: sprintf_s(buf, _countof(buf) - 1, "%f", SANE_UNFIX(*(SANE_Fixed*)val)); break; case SANE_TYPE_STRING: return std::string((char*)val, bytes); } return buf; } void sane_config_schm::clear() { if (jsn_) jsn_->release(); jsn_ = nullptr; if (bkp_) bkp_->release(); bkp_ = nullptr; } std::string sane_config_schm::default_value(const char* hex_title) { return sane_config_schm::option_default_value(def_val_, hex_title); } sane_config_schm* sane_config_schm::copy(void) { sane_config_schm *cp = new sane_config_schm(scanner_); cp->scheme_name_ = scheme_name_; cp->file_ = file_; if(jsn_) cp->jsn_->copy_from(*jsn_); if (bkp_) { cp->bkp_ = new gb::json(); cp->bkp_->copy_from(*bkp_); } cp->def_val_->release(); cp->def_val_ = def_val_; def_val_->add_ref(); return cp; } bool sane_config_schm::load_from_file(const char* file) { clear(); std::string cont(""); file_ = file; if (gb::load_mini_file(file, cont)) return false; return load_from_mem(cont.c_str()); } bool sane_config_schm::load_from_mem(const char* mem, bool in_b64) { gb::base64 b64; std::string stream(in_b64 ? b64.decode(mem, strlen(mem)) : mem); clear(); jsn_ = new gb::json(); if (!jsn_->attach_text(&stream[0])) { jsn_->release(); jsn_ = NULL; return false; } return true; } bool sane_config_schm::save_to(const char* file) { bool ret = false; std::string encode(to_text_stream()); if (!file || *file == 0) file = file_.c_str(); if (encode.length()) { FILE* dst = fopen(file, "wb"); if (dst) { fwrite(encode.c_str(), 1, encode.length(), dst); fclose(dst); ret = true; } } return ret; } void sane_config_schm::set_default_value(int sn, const char* name, const char* title, const char* val, size_t bytes, int type) { sane_config_schm::set_default_value(def_val_, sn, name, title, (void*)val, bytes, type); } bool sane_config_schm::first_config(std::string& name, std::string& val) { bool ret = false; json* child = nullptr; std::string raw_v(""); if (jsn_ && (child = jsn_->first_child())) { name = child->key(); child->value(raw_v); val = sane_config_schm::from_hex_letter(raw_v.c_str(), raw_v.length()); child->release(); ret = true; } return ret; } bool sane_config_schm::next_config(std::string& name, std::string& val) { bool ret = false; json* child = nullptr; std::string raw_v(""); if (jsn_ && (child = jsn_->next_child())) { name = child->key(); child->value(raw_v); val = sane_config_schm::from_hex_letter(raw_v.c_str(), raw_v.length()); child->release(); ret = true; } return ret; } bool sane_config_schm::get_config(const char* name, std::string& val) { bool ret = jsn_ ? jsn_->get_value(name, val) : false; if(!ret && def_val_) ret = def_val_->get_value(name, val); if(ret) val = sane_config_schm::from_hex_letter(val.c_str(), val.length()); return ret; } void sane_config_schm::begin_setting(bool restore) { if (bkp_) bkp_->release(); bkp_ = jsn_; in_setting_ = true; jsn_ = new gb::json(); if (!restore && bkp_) { jsn_->copy_from(*bkp_); } } 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)); if (extra) { jsn_->set_value((name + sane_config_schm::opt_data_appendix_).c_str(), hex_v.c_str()); } else { std::string def = default_value(name); if (hex_v == def) { jsn_->remove(name); jsn_->remove((name + sane_config_schm::opt_data_appendix_).c_str()); } else jsn_->set_value(name, hex_v.c_str()); } } void sane_config_schm::config_changed(int sn, const char* val, size_t bytes, bool extra) { std::string name(""); def_val_->get_value(std::to_string(sn).c_str(), name); if (!name.empty()) { config_changed(name.c_str(), val, bytes, extra); } } void sane_config_schm::remove_config(const char* name) { if (jsn_) 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()); } bool sane_config_schm::has_changed(int* items) { if(items) *items = jsn_ ? jsn_->children() : 0; if(!bkp_) return false; std::map old; std::string n(""), v(""); json* child = nullptr; if((child = bkp_->first_child())) { do { child->value(v); old[child->key()] = std::move(v); child->release(); }while((child = bkp_->next_child())); } if((child = jsn_->first_child())) { do { n = child->key(); if(old.count(n) == 0) { child->release(); return true; } child->value(v); if(old[n]!=v) { child->release(); return true; } child->release(); old.erase(n); } while ((child = jsn_->next_child())); } return old.size() > 0; } void sane_config_schm::end_setting(bool cancel) { if (in_setting_) { if (cancel) { jsn_->release(); jsn_ = bkp_; bkp_ = nullptr; } else if (bkp_) { bkp_->release(); bkp_ = nullptr; } } in_setting_ = false; } int sane_config_schm::id_from_name(const char* name) { return sane_config_schm::option_name_2_id(def_val_, name); } std::string sane_config_schm::to_text_stream(bool b64, bool with_ver) { if (jsn_) { if(with_ver) { char ver[40] = { 0 }; sprintf(ver, "%u.%u", VERSION_MAIN, VERSION_SUB); jsn_->set_value("ver", ver); } std::string cont(""); //if (jsn_->is_leaf_node()) //{ // jsn_->value(cont); // cont.insert(0, "{\"" + jsn_->key() + "\":\""); // cont += "\"}"; //} //else cont = jsn_->to_string(); if (b64) { gb::base64 b64; cont = b64.encode(cont.c_str(), cont.length()); } return cont; } else return ""; } std::string sane_config_schm::get_version(void) { std::string ver(""); if (jsn_) jsn_->get_value("ver", ver); return ver; } std::string sane_config_schm::get_scheme_name(void) { return scheme_name_; } void sane_config_schm::set_scheme_name(const char* name) { scheme_name_ = name ? name : ""; } std::string sane_config_schm::auto_gen_scheme_name(const char* (__stdcall* lang_trans)(const char*, bool/*true - default language to cur language*/, void*), void* param, bool replace_name) { std::string name(""), key(""), val(""), add(""); int cnt = 0; if (first_config(key, val)) { do { if (cnt++ > 3) break; SANE_Value_Type type = (SANE_Value_Type)sane_config_schm::option_type(def_val_, key.c_str()); if (type == SANE_TYPE_STRING) name += add + lang_trans(val.c_str(), true, param); else name += add + sane_config_schm::option_title(def_val_, key.c_str()) + "(" + sane_config_schm::sane_option_value_2_string(&val[0], val.length(), type) + ")"; add = "+"; } while (next_config(key, val)); } if (name.empty()) name = lang_trans(scanner_cfg::default_setting_name_.c_str(), true, param); cnt = 0; if (scanner_) { sane_config_schm* cfg = scanner_->get_scheme(name.c_str()); while (cfg) { cfg->release(); cfg = scanner_->get_scheme((name + "(" + std::to_string(++cnt) + ")").c_str()); } if (cnt) name += "(" + std::to_string(++cnt) + ")"; } if(replace_name) scheme_name_ = name; return std::move(name); } /////////////////////////////////////////////////////////////////////////////////// // scanner_cfg std::string scanner_cfg::global_name_ = "global"; std::string scanner_cfg::cur_sel_ = "cur"; std::string scanner_cfg::default_setting_name_ = "\xE9\xBB\x98\xE8\xAE\xA4\xE8\xAE\xBE\xE7\xBD\xAE"; // utf-8: 默认设置 scanner_cfg::scanner_cfg() : path_(""), scanner_name_(""), global_(new json()), lang_trans_(scanner_cfg::language_trans), lang_param_(nullptr) { opt_default_value_ = new json(); init_version(); init_select(); } scanner_cfg::~scanner_cfg() { clear(); global_->release(); opt_default_value_->release(); } bool scanner_cfg::update(const char* file, LPUDF func) { return false; } const char* __stdcall scanner_cfg::language_trans(const char* in, bool from_def, void* param) { return in; } 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); } const char* scanner_cfg::trans_language(const char* in, bool from_default) { return lang_trans_(in, from_default, lang_param_); } int scanner_cfg::load_file(const char* file) { std::string cont(""); int ret = gb::load_mini_file(file, cont); if (ret == 0) { const char* name = strrchr(file, PATH_SYMBOL[0]); if (name++ == nullptr) name = file; else path_ = std::string(file, name - file); scanner_name_ = name; ret = scanner_name_.rfind('.'); if (ret != std::string::npos) scanner_name_.erase(ret); ret = load_mem(cont.c_str());; } return ret; } int scanner_cfg::load_mem(const char* mem) { json* jsn = new json(*(char**)&mem), * glb = nullptr; if (jsn->get_value("global", glb)) { int sel = -1; glb->get_value(scanner_cfg::cur_sel_.c_str(), sel); glb->release(); glb = jsn->first_child(); glb->release(); while ((glb = jsn->next_child())) { std::string val(""); sane_config_schm * cfg = new sane_config_schm(this); glb->value(val); if (cfg->load_from_mem(val.c_str())) { val = glb->key(); val = sane_config_schm::from_hex_letter(val.c_str(), val.length()); add_scheme(cfg, val.c_str()); cfg->set_scheme_name(val.c_str()); } cfg->release(); glb->release(); } if (sel < 0 || sel >= schemes_.size()) sel = -1; global_->set_value(scanner_cfg::cur_sel_.c_str(), sel); } else { sane_config_schm* cfg = new sane_config_schm(this); if (cfg->load_from_mem(mem)) { cfg->remove_config("ver"); std::string name(cfg->auto_gen_scheme_name(lang_trans_, lang_param_)); add_scheme(cfg); select_scheme(name.c_str()); save(); } cfg->release(); } jsn->release(); return 0; } int scanner_cfg::save(const char* file) { if (!file && path_.empty() && scanner_name_.empty()) return EINVAL; std::string cont(to_text_stream()), f(file ? file : path_ + scanner_name_ + ".cfg"); FILE* dst = fopen(f.c_str(), "wb"); if (!dst) return errno; fwrite(cont.c_str(), 1, cont.length(), dst); fclose(dst); return 0; } void scanner_cfg::set_language_transform(const char* (__stdcall* lang_trans)(const char*, bool/*true - default language to cur language*/, void*), void* param) { lang_trans_ = lang_trans ? lang_trans : &scanner_cfg::language_trans; lang_param_ = param; } json* scanner_cfg::get_option_default_value(void) { opt_default_value_->add_ref(); return opt_default_value_; } void scanner_cfg::get_all_schemes(std::vector& schemes) { schemes.push_back(trans_language(scanner_cfg::default_setting_name_.c_str(), true)); 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 && *scheme_name) { std::vector::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; } sane_config_schm* scanner_cfg::create_empty_scheme(bool selected) { sane_config_schm* schm = new sane_config_schm(this); int ind = 1; std::string prev(trans_language(scanner_cfg::default_setting_name_.c_str(), true)); while (std::find(schemes_.begin(), schemes_.end(), (prev + "-" + std::to_string(ind)).c_str()) != schemes_.end()) ind++; prev += "-" + std::to_string(ind); add_scheme(schm, prev.c_str(), true); if (selected) select_scheme(prev.c_str()); return schm; } std::string scanner_cfg::get_current_scheme_name(void) { int ind = -1; global_->get_value(scanner_cfg::cur_sel_.c_str(), ind); if (ind >= 0 && ind < schemes_.size()) return schemes_[ind].name; else return trans_language(scanner_cfg::default_setting_name_.c_str(), true); } std::string scanner_cfg::to_text_stream(void) { std::string text(""), val(""); int sel = -1; if (!global_->get_value("ver", val) || val.empty()) init_version(); if (!global_->get_value(scanner_cfg::cur_sel_.c_str(), sel) || sel >= schemes_.size()) init_select(); text = "{\"" + scanner_cfg::global_name_ + "\":" + global_->to_string(); for (auto& v : schemes_) { if (v.should_rename) { v.schm->auto_gen_scheme_name(lang_trans_, lang_param_); v.name = v.schm->get_scheme_name(); v.should_rename = false; } text += ",\"" + sane_config_schm::to_hex_letter(v.name.c_str(), v.name.length()) + "\":\"" + v.schm->to_text_stream(true, false) + "\""; } text += "}"; return std::move(text); } void scanner_cfg::set_default_value(int id, const char* name, const char* title, void* data, size_t bytes, int type) { sane_config_schm::set_default_value(opt_default_value_, id, name, title, data, bytes, type); } int scanner_cfg::option_value_type(const char* name) { return sane_config_schm::option_type(opt_default_value_, name); } std::string scanner_cfg::option_title(const char* name) { return sane_config_schm::option_title(opt_default_value_, name); } bool scanner_cfg::remove_scheme(const char* scheme_name) { std::vector::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; } void scanner_cfg::remove_all_schemes(void) { for(auto& v: schemes_) v.schm->release(); schemes_.clear(); } bool scanner_cfg::select_scheme(const char* scheme_name) { std::vector::iterator it = scheme_name ? std::find(schemes_.begin(), schemes_.end(), scheme_name) : schemes_.end(); if (it == schemes_.end()) global_->set_value(scanner_cfg::cur_sel_.c_str(), -1); else global_->set_value(scanner_cfg::cur_sel_.c_str(), (int)(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 || *cp_from_name == 0 || std::string(trans_language(scanner_cfg::default_setting_name_.c_str(), true)) == cp_from_name) { sane_config_schm* schm = new sane_config_schm(this); schm->set_scheme_name(trans_language(scanner_cfg::default_setting_name_.c_str(), true)); return schm; } else { std::vector::iterator it = std::find(schemes_.begin(), schemes_.end(), cp_from_name); if (it == schemes_.end()) return nullptr; return it->schm->copy(); } } bool scanner_cfg::add_scheme(sane_config_schm* schm, const char* name, bool should_rename) { CFGSCHM cs; cs.name = name ? name : schm->get_scheme_name(); if(cs.name.empty() || cs.name == scanner_cfg::global_name_) return false; if (std::find(schemes_.begin(), schemes_.end(), cs.name.c_str()) != schemes_.end()) return false; cs.schm = schm; cs.should_rename = should_rename; schemes_.push_back(cs); schm->set_scheme_name(cs.name.c_str()); schm->add_ref(); return true; } bool scanner_cfg::rename_scheme(const char* from, const char* to) { if (to && (strcmp(to, trans_language(scanner_cfg::default_setting_name_.c_str(), true)) == 0 || std::find(schemes_.begin(), schemes_.end(), to) != schemes_.end())) return false; for(auto& v: schemes_) { if(v.name == from) { v.name = to; v.should_rename = false; v.schm->set_scheme_name(to); return true; } } return false; } }