code_twain/sane/gb_json.cpp

2044 lines
53 KiB
C++

#include "gb_json.h"
#include <stdlib.h>
#include <string.h>
#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<std::string> split_with(const char* str, const char* splitor = "/")
{
std::vector<std::string> 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<std::string, std::string> 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<std::string>& 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<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;
}
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<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;
}
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<CFGSCHM>::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<CFGSCHM>::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;
}
}