code_app/app/scanner/json.cpp

773 lines
18 KiB
C++
Raw Normal View History

2022-05-03 10:25:52 +00:00

#include "json.h"
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#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;
}
json::json(char* json_txt) : obj_(0), cur_child_(0), is_array_(false)
{
attach_text(json_txt);
}
json::~json()
{
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_with_name(const char* name)
{
cJSON* obj = cJSON_CreateObject();
bzero(obj, sizeof(*obj));
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)
*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_ = cJSON_CreateObject();
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_ = array ? cJSON_CreateArray() : cJSON_CreateObject();
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))
{
delete val;
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_ = cJSON_CreateArray();
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_ = cJSON_CreateArray();
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_ = cJSON_CreateArray();
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_ = cJSON_CreateArray();
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_ = cJSON_CreateArray();
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::remove(const char* key)
{
if(!obj_)
return false;
cJSON **addr = NULL,
*ele = find(key, false, &addr);
if(ele)
{
if(addr)
*addr = 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;
}
}