2022-10-28 01:03:22 +00:00
|
|
|
|
|
|
|
|
|
#include "gb_json.h"
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "../../sdk/include/huagao/brand.h"
|
|
|
|
|
|
|
|
|
|
#if defined(WIN32) || defined(_WIN64)
|
|
|
|
|
#define bzero(b, s) memset(b, 0, s)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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) : obj_(0), cur_child_(0), is_array_(false)
|
|
|
|
|
{
|
|
|
|
|
memset(&walk_head_, 0, sizeof(walk_head_));
|
|
|
|
|
attach_text(json_txt);
|
|
|
|
|
}
|
|
|
|
|
json::~json()
|
|
|
|
|
{
|
|
|
|
|
memset(&walk_head_, 0, sizeof(walk_head_));
|
|
|
|
|
clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string json::to_string(cJSON* root, bool formatted)
|
|
|
|
|
{
|
|
|
|
|
char* txt = formatted ? cJSON_Print(root) : cJSON_PrintUnformatted(root);
|
|
|
|
|
std::string ret(txt ? txt : "");
|
|
|
|
|
|
|
|
|
|
if (txt)
|
|
|
|
|
free(txt);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
std::string json::get_value_as_string(cJSON* root, bool integer)
|
|
|
|
|
{
|
|
|
|
|
std::string ret("");
|
|
|
|
|
|
|
|
|
|
switch (root->type)
|
|
|
|
|
{
|
|
|
|
|
case cJSON_False:
|
|
|
|
|
ret = "false";
|
|
|
|
|
break;
|
|
|
|
|
case cJSON_True:
|
|
|
|
|
ret = "true";
|
|
|
|
|
break;
|
|
|
|
|
case cJSON_NULL:
|
|
|
|
|
ret = "null";
|
|
|
|
|
break;
|
|
|
|
|
case cJSON_Number:
|
|
|
|
|
{
|
|
|
|
|
char buf[40];
|
|
|
|
|
if (integer)
|
|
|
|
|
sprintf(buf, "%d", root->valueint);
|
|
|
|
|
else
|
|
|
|
|
sprintf(buf, "%f", root->valuedouble);
|
|
|
|
|
ret = buf;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case cJSON_String:
|
|
|
|
|
if (root->valuestring)
|
|
|
|
|
ret = root->valuestring;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ret = json::to_string(root, false);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
void json::free_node_data(cJSON* node)
|
|
|
|
|
{
|
|
|
|
|
if (node->type == cJSON_String && node->valuestring)
|
|
|
|
|
free(node->valuestring);
|
|
|
|
|
else if((node->type == cJSON_Object || node->type == cJSON_Array) && node->child)
|
|
|
|
|
cJSON_Delete(node->child);
|
|
|
|
|
|
|
|
|
|
node->type = cJSON_NULL;
|
|
|
|
|
node->valuestring = NULL;
|
|
|
|
|
node->child = NULL;
|
|
|
|
|
}
|
|
|
|
|
cJSON* json::create_element(bool is_array)
|
|
|
|
|
{
|
|
|
|
|
cJSON* obj = is_array ? cJSON_CreateArray() : cJSON_CreateObject();
|
|
|
|
|
|
|
|
|
|
// bzero(obj, sizeof(*obj)); // cleared in constructor already !
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
cJSON* json::create_element_with_name(const char* name)
|
|
|
|
|
{
|
|
|
|
|
cJSON* obj = json::create_element();
|
|
|
|
|
|
|
|
|
|
if(name)
|
|
|
|
|
{
|
|
|
|
|
obj->string = (char*)malloc(strlen(name) + 4);
|
|
|
|
|
bzero(obj->string, strlen(name) + 4);
|
|
|
|
|
strcpy(obj->string, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cJSON* json::find_sibling(cJSON* first, const char* name, cJSON*** prev)
|
|
|
|
|
{
|
|
|
|
|
cJSON* now = first, **prv = NULL;
|
|
|
|
|
while(now)
|
|
|
|
|
{
|
|
|
|
|
if(now->string && strcmp(now->string, name) == 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
prv = &now->next;
|
|
|
|
|
now = now->next;
|
|
|
|
|
}
|
|
|
|
|
if(prev)
|
|
|
|
|
*prev = prv;
|
|
|
|
|
|
|
|
|
|
return now;
|
|
|
|
|
}
|
|
|
|
|
cJSON* json::find_child(cJSON *parent, std::vector<std::string>& path, bool create, cJSON*** addr)
|
|
|
|
|
{
|
|
|
|
|
if(!parent->child)
|
|
|
|
|
{
|
|
|
|
|
if(!create)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
parent->child = json::create_element_with_name(path[0].c_str());
|
|
|
|
|
if(path.size() == 1)
|
|
|
|
|
{
|
|
|
|
|
if(addr)
|
|
|
|
|
*addr = &parent->child;
|
|
|
|
|
|
|
|
|
|
return parent->child;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cJSON** prev = NULL,
|
|
|
|
|
*now = find_sibling(parent->child, path[0].c_str(), &prev);
|
|
|
|
|
if(!now)
|
|
|
|
|
{
|
|
|
|
|
if(!create)
|
|
|
|
|
return now;
|
|
|
|
|
|
|
|
|
|
now = json::create_element_with_name(path[0].c_str());
|
|
|
|
|
if (prev)
|
|
|
|
|
{
|
|
|
|
|
cJSON* pr = (cJSON*)((DWORD_PTR)prev - (DWORD_PTR)&((cJSON*)0)->next);
|
|
|
|
|
pr->next = now;
|
|
|
|
|
now->prev = pr;
|
|
|
|
|
// *prev = now;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
obj_->child = now;
|
|
|
|
|
prev = &obj_->child;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
path.erase(path.begin());
|
|
|
|
|
if(path.empty())
|
|
|
|
|
{
|
|
|
|
|
if(addr)
|
|
|
|
|
*addr = prev ? prev : &parent->child;
|
|
|
|
|
|
|
|
|
|
return now;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return find_child(now, path, create, addr);
|
|
|
|
|
}
|
|
|
|
|
cJSON* json::find(const char* path, bool create, cJSON*** addr)
|
|
|
|
|
{
|
|
|
|
|
std::vector<std::string> tree(split_with(path));
|
|
|
|
|
|
|
|
|
|
if(tree.empty())
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if(!obj_)
|
|
|
|
|
{
|
|
|
|
|
if(!create)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
obj_ = json::create_element();
|
|
|
|
|
obj_->child = json::create_element_with_name(tree[0].c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return find_child(obj_, tree, create, addr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool json::attach_text(char* json_txt)
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
|
|
obj_ = cJSON_Parse(json_txt);
|
|
|
|
|
if(obj_)
|
|
|
|
|
is_array_ = obj_->type == cJSON_Array;
|
|
|
|
|
|
|
|
|
|
return obj_ != 0;
|
|
|
|
|
}
|
|
|
|
|
bool json::attach_cjson(cJSON* cjson)
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
|
|
if (cjson)
|
|
|
|
|
{
|
|
|
|
|
std::string txt(json::to_string(cjson, false));
|
|
|
|
|
if (txt.length())
|
|
|
|
|
obj_ = cJSON_Parse(txt.c_str());
|
|
|
|
|
}
|
|
|
|
|
if(obj_)
|
|
|
|
|
is_array_ = obj_->type == cJSON_Array;
|
|
|
|
|
|
|
|
|
|
return obj_ != 0;
|
|
|
|
|
}
|
|
|
|
|
bool json::create_empty(bool array)
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
|
|
obj_ = json::create_element(array);
|
|
|
|
|
is_array_ = array;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
void json::clear(void)
|
|
|
|
|
{
|
|
|
|
|
if (obj_)
|
|
|
|
|
{
|
|
|
|
|
cJSON_Delete(obj_);
|
|
|
|
|
obj_ = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::string json::to_string(bool formatted)
|
|
|
|
|
{
|
|
|
|
|
if (obj_)
|
|
|
|
|
return json::to_string(obj_, formatted);
|
|
|
|
|
else
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool json::get_value(const char* key, bool& val)
|
|
|
|
|
{
|
|
|
|
|
cJSON* obj = find(key);
|
|
|
|
|
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (obj->type == cJSON_True)
|
|
|
|
|
val = true;
|
|
|
|
|
else if (obj->type == cJSON_False)
|
|
|
|
|
val = false;
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::get_value(const char* key, int& val)
|
|
|
|
|
{
|
|
|
|
|
cJSON* obj = find(key);
|
|
|
|
|
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (obj->type != cJSON_Number)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
val = obj->valueint;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::get_value(const char* key, double& val)
|
|
|
|
|
{
|
|
|
|
|
cJSON *obj = find(key);
|
|
|
|
|
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (obj->type != cJSON_Number)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
val = obj->valuedouble;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::get_value(const char* key, std::string& val)
|
|
|
|
|
{
|
|
|
|
|
cJSON *obj = find(key);
|
|
|
|
|
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (obj->type != cJSON_String)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
val = obj->valuestring ? obj->valuestring : "";
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::get_value(const char* key, json*& val)
|
|
|
|
|
{
|
|
|
|
|
cJSON *obj = find(key);
|
|
|
|
|
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
val = new json();
|
|
|
|
|
if (!val->attach_cjson(obj))
|
|
|
|
|
{
|
|
|
|
|
val->release();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::get_value_as_string(const char* key, std::string& val, bool integer)
|
|
|
|
|
{
|
|
|
|
|
cJSON* obj = find(key);
|
|
|
|
|
|
|
|
|
|
if (!obj)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
val = json::get_value_as_string(obj, integer);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::get_as_array(const char* key, std::vector<std::string>& val)
|
|
|
|
|
{
|
|
|
|
|
cJSON *obj = find(key);
|
|
|
|
|
|
|
|
|
|
val.clear();
|
|
|
|
|
if (obj && obj->type == cJSON_Array)
|
|
|
|
|
{
|
|
|
|
|
cJSON *child = obj->child;
|
|
|
|
|
while (child)
|
|
|
|
|
{
|
|
|
|
|
if (child->type == cJSON_Number)
|
|
|
|
|
{
|
|
|
|
|
char buf[40];
|
|
|
|
|
sprintf(buf, "%d", child->valueint);
|
|
|
|
|
val.push_back(buf);
|
|
|
|
|
}
|
|
|
|
|
else if (child->type == cJSON_String)
|
|
|
|
|
val.push_back(child->valuestring ? child->valuestring : "");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *text = cJSON_Print(child);
|
|
|
|
|
val.push_back(text);
|
|
|
|
|
free(text);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
child = child->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool json::first_child(std::string& val, std::string* name)
|
|
|
|
|
{
|
|
|
|
|
cur_child_ = obj_->child;
|
|
|
|
|
val = "";
|
|
|
|
|
if (cur_child_)
|
|
|
|
|
{
|
|
|
|
|
val = json::get_value_as_string(cur_child_);
|
|
|
|
|
if (name && cur_child_->string)
|
|
|
|
|
*name = cur_child_->string;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool json::next_child(std::string& val, std::string* name)
|
|
|
|
|
{
|
|
|
|
|
if (cur_child_)
|
|
|
|
|
cur_child_ = cur_child_->next;
|
|
|
|
|
|
|
|
|
|
val = "";
|
|
|
|
|
if (cur_child_)
|
|
|
|
|
{
|
|
|
|
|
val = json::get_value_as_string(cur_child_);
|
|
|
|
|
if (name && cur_child_->string)
|
|
|
|
|
*name = cur_child_->string;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool json::set_value(const char* key, bool val)
|
|
|
|
|
{
|
|
|
|
|
if(!key)
|
|
|
|
|
{
|
|
|
|
|
if(is_array_)
|
|
|
|
|
{
|
|
|
|
|
if(!obj_)
|
|
|
|
|
obj_ = json::create_element(true);
|
|
|
|
|
cJSON_AddItemToArray(obj_, val ? cJSON_CreateTrue() : cJSON_CreateFalse());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return is_array_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cJSON* ele = this->find(key, true);
|
|
|
|
|
|
|
|
|
|
if (!ele)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
json::free_node_data(ele);
|
|
|
|
|
|
|
|
|
|
if (val)
|
|
|
|
|
ele->type = cJSON_True;
|
|
|
|
|
else
|
|
|
|
|
ele->type = cJSON_False;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::set_value(const char* key, int val)
|
|
|
|
|
{
|
|
|
|
|
if(!key)
|
|
|
|
|
{
|
|
|
|
|
if(is_array_)
|
|
|
|
|
{
|
|
|
|
|
if(!obj_)
|
|
|
|
|
obj_ = json::create_element(true);
|
|
|
|
|
cJSON_AddItemToArray(obj_, cJSON_CreateNumber(val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return is_array_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cJSON* ele = this->find(key, true);
|
|
|
|
|
|
|
|
|
|
if (!ele)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
json::free_node_data(ele);
|
|
|
|
|
|
|
|
|
|
ele->type = cJSON_Number;
|
|
|
|
|
ele->valuedouble = ele->valueint = val;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::set_value(const char* key, double val)
|
|
|
|
|
{
|
|
|
|
|
if(!key)
|
|
|
|
|
{
|
|
|
|
|
if(is_array_)
|
|
|
|
|
{
|
|
|
|
|
if(!obj_)
|
|
|
|
|
obj_ = json::create_element(true);
|
|
|
|
|
cJSON_AddItemToArray(obj_, cJSON_CreateNumber(val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return is_array_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cJSON* ele = this->find(key, true);
|
|
|
|
|
|
|
|
|
|
if (!ele)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
json::free_node_data(ele);
|
|
|
|
|
|
|
|
|
|
ele->type = cJSON_Number;
|
|
|
|
|
ele->valuedouble = val;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::set_value(const char* key, std::string val)
|
|
|
|
|
{
|
|
|
|
|
if(!key)
|
|
|
|
|
{
|
|
|
|
|
if(is_array_)
|
|
|
|
|
{
|
|
|
|
|
if(!obj_)
|
|
|
|
|
obj_ = json::create_element(true);
|
|
|
|
|
cJSON_AddItemToArray(obj_, cJSON_CreateString(val.c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return is_array_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cJSON* ele = this->find(key, true);
|
|
|
|
|
|
|
|
|
|
if (!ele)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
json::free_node_data(ele);
|
|
|
|
|
|
|
|
|
|
ele->type = cJSON_String;
|
|
|
|
|
ele->valuestring = (char*)malloc(val.length() + 4);
|
|
|
|
|
bzero(ele->valuestring, val.length() + 4);
|
|
|
|
|
strcpy(ele->valuestring, val.c_str());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::set_value(const char* key, const char* val)
|
|
|
|
|
{
|
|
|
|
|
return set_value(key, std::string(val));
|
|
|
|
|
}
|
|
|
|
|
bool json::set_value(const char* key, json* obj)
|
|
|
|
|
{
|
|
|
|
|
if(!key)
|
|
|
|
|
{
|
|
|
|
|
if(is_array_)
|
|
|
|
|
{
|
|
|
|
|
if(!obj_)
|
|
|
|
|
obj_ = json::create_element(true);
|
|
|
|
|
if(obj && obj->obj_)
|
|
|
|
|
{
|
|
|
|
|
cJSON_AddItemToArray(obj_, obj->obj_);
|
|
|
|
|
obj->obj_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return is_array_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cJSON** addr = NULL;
|
|
|
|
|
cJSON* ele = this->find(key, true, &addr);
|
|
|
|
|
|
|
|
|
|
if (!ele)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// json::free_node_data(ele);
|
|
|
|
|
cJSON_Delete(ele);
|
|
|
|
|
*addr = obj->obj_;
|
|
|
|
|
ele = obj->obj_;
|
|
|
|
|
if(ele->string)
|
|
|
|
|
free(ele->string);
|
|
|
|
|
ele->string = (char*)malloc(strlen(key) + 4);
|
|
|
|
|
bzero(ele->string, strlen(key) + 4);
|
|
|
|
|
strcpy(ele->string, key);
|
|
|
|
|
obj->obj_ = NULL;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool json::change_key(const char* old_key, const char* new_key)
|
|
|
|
|
{
|
|
|
|
|
if (!obj_ || !new_key || *new_key == 0 || !old_key || *old_key == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
cJSON** addr = NULL,
|
|
|
|
|
*ele = find(old_key, false, &addr);
|
|
|
|
|
|
|
|
|
|
if (!ele)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (strlen(ele->string) < strlen(new_key))
|
|
|
|
|
{
|
|
|
|
|
int l = strlen(new_key) + 4;
|
|
|
|
|
free(ele->string);
|
|
|
|
|
ele->string = (char*)malloc(l);
|
|
|
|
|
memset(ele->string, 0, l);
|
|
|
|
|
}
|
|
|
|
|
strcpy(ele->string, new_key);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool json::remove(const char* key)
|
|
|
|
|
{
|
|
|
|
|
if(!obj_)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
cJSON **addr = NULL,
|
|
|
|
|
*ele = find(key, false, &addr);
|
|
|
|
|
|
|
|
|
|
if(ele)
|
|
|
|
|
{
|
|
|
|
|
bool cur_child = cur_child_ == obj_->child;
|
|
|
|
|
|
|
|
|
|
if(addr)
|
|
|
|
|
*addr = ele->next;
|
|
|
|
|
if (cur_child_ == ele)
|
|
|
|
|
{
|
|
|
|
|
if (cur_child)
|
|
|
|
|
{
|
|
|
|
|
walk_head_.next = obj_->child;
|
|
|
|
|
cur_child_ = &walk_head_;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
cur_child_ = ele->prev;
|
|
|
|
|
}
|
|
|
|
|
if (ele->prev)
|
|
|
|
|
ele->prev->next = ele->next;
|
|
|
|
|
if (ele->next)
|
|
|
|
|
ele->next->prev = ele->prev;
|
|
|
|
|
ele->prev = NULL;
|
|
|
|
|
ele->next = NULL;
|
|
|
|
|
cJSON_Delete(ele);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 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 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;
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
std::string sane_config_schm::opt_data_appendix_("_data");
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
if (scanner_)
|
|
|
|
|
scanner_->add_ref();
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
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::clear()
|
|
|
|
|
{
|
|
|
|
|
if (jsn_)
|
|
|
|
|
jsn_->release();
|
|
|
|
|
jsn_ = NULL;
|
|
|
|
|
if (bkp_)
|
|
|
|
|
bkp_->release();
|
|
|
|
|
bkp_ = NULL;
|
|
|
|
|
// file_ = "";
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
std::string sane_config_schm::default_value(const char* hex_title)
|
|
|
|
|
{
|
|
|
|
|
std::string val("");
|
|
|
|
|
|
|
|
|
|
def_val_->get_value(hex_title, val);
|
|
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sane_config_schm* sane_config_schm::copy(void)
|
|
|
|
|
{
|
|
|
|
|
sane_config_schm *cp = new sane_config_schm(scanner_);
|
|
|
|
|
std::string val(jsn_->to_string(false));
|
|
|
|
|
|
|
|
|
|
cp->scheme_name_ = scheme_name_;
|
|
|
|
|
cp->file_ = file_;
|
|
|
|
|
cp->jsn_->attach_text(&val[0]);
|
|
|
|
|
cp->id_name_ = id_name_;
|
|
|
|
|
val = def_val_->to_string(false);
|
|
|
|
|
cp->def_val_->attach_text(&val[0]);
|
|
|
|
|
|
|
|
|
|
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* val, size_t bytes)
|
|
|
|
|
{
|
|
|
|
|
id_name_[sn] = name;
|
|
|
|
|
def_val_->set_value(name, to_hex_letter(val, bytes).c_str());
|
|
|
|
|
}
|
|
|
|
|
void sane_config_schm::copy_default_value(sane_config_schm* from)
|
|
|
|
|
{
|
|
|
|
|
if(from)
|
|
|
|
|
{
|
|
|
|
|
std::string t(from->def_val_->to_string(false));
|
|
|
|
|
|
|
|
|
|
id_name_ = from->id_name_;
|
|
|
|
|
def_val_->attach_text(&t[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool sane_config_schm::first_config(std::string& name, std::string& val)
|
|
|
|
|
{
|
|
|
|
|
bool ret = false;
|
|
|
|
|
std::string raw_v("");
|
|
|
|
|
|
|
|
|
|
if (jsn_ && jsn_->first_child(raw_v, &name))
|
|
|
|
|
{
|
|
|
|
|
val = sane_config_schm::from_hex_letter(raw_v.c_str(), raw_v.length());
|
|
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
bool sane_config_schm::next_config(std::string& name, std::string& val)
|
|
|
|
|
{
|
|
|
|
|
bool ret = false;
|
|
|
|
|
std::string raw_v("");
|
|
|
|
|
|
|
|
|
|
if (jsn_ && jsn_->next_child(raw_v, &name))
|
|
|
|
|
{
|
|
|
|
|
val = sane_config_schm::from_hex_letter(raw_v.c_str(), raw_v.length());
|
|
|
|
|
|
|
|
|
|
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_)
|
|
|
|
|
{
|
|
|
|
|
std::string stream(bkp_->to_string(false));
|
|
|
|
|
if(stream.length())
|
|
|
|
|
jsn_->attach_text(&stream[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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("");
|
|
|
|
|
|
|
|
|
|
if (id_name_.count(sn))
|
|
|
|
|
{
|
|
|
|
|
name = id_name_[sn];
|
|
|
|
|
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(void)
|
|
|
|
|
{
|
|
|
|
|
if(!bkp_)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
std::map<std::string, std::string> old;
|
|
|
|
|
std::string n(""), v("");
|
|
|
|
|
if(bkp_->first_child(v, &n))
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
old[n] = v;
|
|
|
|
|
}while(bkp_->next_child(v, &n));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(jsn_->first_child(v, &n))
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if(old.count(n) == 0)
|
|
|
|
|
return true;
|
|
|
|
|
if(old[n]!=v)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
old.erase(n);
|
|
|
|
|
}while(jsn_->next_child(v, &n));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return old.size() > 0;
|
|
|
|
|
}
|
|
|
|
|
void sane_config_schm::end_setting(bool cancel)
|
|
|
|
|
{
|
|
|
|
|
if (in_setting_)
|
|
|
|
|
{
|
|
|
|
|
if (cancel)
|
|
|
|
|
{
|
|
|
|
|
jsn_->release();
|
|
|
|
|
jsn_ = bkp_;
|
|
|
|
|
bkp_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (bkp_)
|
|
|
|
|
{
|
|
|
|
|
bkp_->release();
|
|
|
|
|
bkp_ = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
in_setting_ = false;
|
|
|
|
|
}
|
|
|
|
|
int sane_config_schm::id_from_name(const char* name)
|
|
|
|
|
{
|
|
|
|
|
for (const auto& v : id_name_)
|
|
|
|
|
{
|
|
|
|
|
if (v.second == name)
|
|
|
|
|
return v.first;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
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(jsn_->to_string(false));
|
|
|
|
|
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 : "";
|
|
|
|
|
}
|
|
|
|
|
void sane_config_schm::update(bool(* is_float)(int, void*), void* param, const char* (* t2n)(const char*), std::string* discard)
|
|
|
|
|
{
|
|
|
|
|
if (!jsn_)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
std::string ver(get_version()),
|
|
|
|
|
name(""),
|
|
|
|
|
val("");
|
|
|
|
|
int mv = atoi(ver.c_str()),
|
|
|
|
|
sv = ver.find(".");
|
|
|
|
|
bool changed = false;
|
|
|
|
|
char vs[40] = { 0 };
|
|
|
|
|
|
|
|
|
|
if (sv++ != -1)
|
|
|
|
|
sv = atoi(ver.c_str() + sv);
|
|
|
|
|
|
|
|
|
|
// change title to name ...
|
|
|
|
|
if (mv <= 4 && sv < 30)
|
|
|
|
|
{
|
|
|
|
|
if (jsn_->first_child(val, &name))
|
|
|
|
|
{
|
|
|
|
|
changed = true;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
jsn_->change_key(name.c_str(), t2n(sane_config_schm::from_hex_letter(name.c_str(), name.length()).c_str()));
|
|
|
|
|
} while (jsn_->next_child(val, &name));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fix float does not convert to SANE_Fixed bug in eldest version .... (discard them)
|
|
|
|
|
if (ver.empty())
|
|
|
|
|
{
|
|
|
|
|
if (jsn_->first_child(val, &name))
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
int id = id_from_name(name.c_str());
|
|
|
|
|
if (id == -1 || is_float(id, param))
|
|
|
|
|
{
|
|
|
|
|
jsn_->remove(name.c_str());
|
|
|
|
|
if (discard)
|
|
|
|
|
*discard += name + "\r\n";
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
} while (jsn_->next_child(val, &name));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sprintf(vs, "%u.%u", VERSION_MAIN, VERSION_SUB);
|
|
|
|
|
jsn_->set_value("ver", vs);
|
|
|
|
|
|
|
|
|
|
if (changed)
|
|
|
|
|
save_to(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// 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;
|
|
|
|
|
else
|
|
|
|
|
path_ = std::string(file, 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)
|
|
|
|
|
{
|
|
|
|
|
base64 b64;
|
|
|
|
|
std::string text(b64.decode(mem, strlen(mem)));
|
|
|
|
|
cJSON* root = cJSON_Parse(text.c_str());
|
|
|
|
|
|
|
|
|
|
if (!root)
|
|
|
|
|
{
|
|
|
|
|
FILE* dst = fopen((path_ + "err_cfg.txt").c_str(), "wb");
|
|
|
|
|
fwrite(text.c_str(), 1, text.length(), dst);
|
|
|
|
|
fclose(dst);
|
|
|
|
|
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_ + ".cfg"),
|
|
|
|
|
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;
|
|
|
|
|
|
2022-10-28 08:53:43 +00:00
|
|
|
|
if (scheme_name && *scheme_name)
|
2022-10-28 01:03:22 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
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 scanner_cfg::default_setting_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)
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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 && std::find(schemes_.begin(), schemes_.end(), to) != schemes_.end())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for(auto& v: schemes_)
|
|
|
|
|
{
|
|
|
|
|
if(v.name == from)
|
|
|
|
|
{
|
|
|
|
|
v.name = to;
|
|
|
|
|
v.schm->set_scheme_name(to);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|