newtx/sdk/json/gb_json.cpp

996 lines
17 KiB
C++
Raw Normal View History

2023-12-01 09:17:09 +00:00
#include "gb_json.h"
#include "cJSON.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
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++;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// life callback ...
#ifdef DUMP_JSON_OBJECT_LIFE
static void record_life_empty(gb_json*, bool, void*)
{}
static void(*g_life)(gb_json*, bool, void*) = &record_life_empty;
static void* g_life_param = nullptr;
void set_gbjson_life_callback(void(*life)(gb_json*, bool, void*), void* param)
{
g_life_param = param;
g_life = life ? life : &record_life_empty;
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// gb_json ...
gb_json::gb_json(char* json_txt) : ref_(1), type_(VAL_TYPE_OBJECT), key_(""), strval_(""), cur_child_(-1)
{
#ifdef DUMP_JSON_OBJECT_LIFE
g_life(this, true, g_life_param);
#endif
simple_val_.dval = .0f;
if(json_txt)
attach_text(json_txt);
}
gb_json::gb_json(const char* key, bool val) : ref_(1), type_(VAL_TYPE_BOOL), key_(key ? key : ""), strval_(""), cur_child_(-1)
{
#ifdef DUMP_JSON_OBJECT_LIFE
g_life(this, true, g_life_param);
#endif
simple_val_.bval = val;
}
gb_json::gb_json(const char* key, int val) : ref_(1), type_(VAL_TYPE_INT), key_(key ? key : ""), strval_(""), cur_child_(-1)
{
#ifdef DUMP_JSON_OBJECT_LIFE
g_life(this, true, g_life_param);
#endif
simple_val_.nval = val;
}
gb_json::gb_json(const char* key, double val) : ref_(1), type_(VAL_TYPE_FLOAT), key_(key ? key : ""), strval_(""), cur_child_(-1)
{
#ifdef DUMP_JSON_OBJECT_LIFE
g_life(this, true, g_life_param);
#endif
simple_val_.dval = val;
}
gb_json::gb_json(const char* key, const char* val) : ref_(1), type_(VAL_TYPE_STRING), key_(key ? key : ""), strval_(val ? val : ""), cur_child_(-1)
{
#ifdef DUMP_JSON_OBJECT_LIFE
g_life(this, true, g_life_param);
#endif
}
gb_json::gb_json(const char* key, const std::string& val) : ref_(1), type_(VAL_TYPE_STRING), key_(key ? key : ""), strval_(val), cur_child_(-1)
{
#ifdef DUMP_JSON_OBJECT_LIFE
g_life(this, true, g_life_param);
#endif
}
gb_json::~gb_json()
{
clear();
#ifdef DUMP_JSON_OBJECT_LIFE
g_life(this, false, g_life_param);
#endif
}
std::string gb_json::object_key(gb_json* jsn)
{
return "\"" + jsn->key() + "\":";
}
std::string gb_json::array_key(gb_json* jsn)
{
return "";
}
void gb_json::from_cjson(cJSON* cj)
{
key_ = cj && cj->string ? cj->string : "";
while (cj)
{
gb_json* child = nullptr;
if (cj->type == cJSON_True)
{
child = new gb_json(cj->string, true);
}
else if(cj->type == cJSON_False)
{
child = new gb_json(cj->string, false);
}
else if (cj->type == cJSON_Number)
{
if (cj->valuedouble - (int)cj->valuedouble < .00001)
{
child = new gb_json(cj->string, cj->valueint);
}
else
{
child = new gb_json(cj->string, cj->valuedouble);
}
}
else if (cj->type == cJSON_String)
{
child = new gb_json(cj->string, cj->valuestring);
}
else if (cj->type == cJSON_Object || cj->type == cJSON_Array)
{
child = new gb_json();
child->from_cjson(cj->child);
child->key_ = cj->string ? cj->string : "";
if (child->key_.empty())
child->type_ = VAL_TYPE_OBJECT;
}
arr_val_.push_back(child);
cj = cj->next;
}
//if (arr_val_.size() == 1 && arr_val_[0]->arr_val_.size() == 0)
//{
// gb_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;
}
}
gb_json* gb_json::find_child(const char* key, bool remove)
{
gb_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;
}
int32_t gb_json::add_ref()
{
std::lock_guard<std::mutex> lock(ref_mutex_);
int32_t ref = ++ref_;
return ref;
}
int32_t gb_json::release()
{
int32_t ref = 0;
{
std::lock_guard<std::mutex> lock(ref_mutex_);
ref = --ref_;
}
if (ref == 0)
delete this;
return ref;
}
static void check_cJSON(cJSON* root, std::vector<cJSON*>* existing)
{
if (!root)
return;
for (auto& v : *existing)
{
if (v == root)
{
printf("cJSON* 0x%08x is repeat!\n", v);
break;
}
}
existing->push_back(root);
check_cJSON(root->child, existing);
cJSON* next = root->next;
while (next)
{
check_cJSON(next, existing);
next = next->next;
}
}
bool gb_json::attach_text(char* json_txt)
{
clear();
cJSON* jsn = cJSON_Parse(json_txt);
if (jsn)
{
char *text = cJSON_Print(jsn);
if (text)
{
if (0)
{
FILE* dst = fopen("e:\\test-json.txt", "wb");
fwrite(text, 1, strlen(text), dst);
fclose(dst);
}
free(text);
}
std::vector<cJSON*> repeat;
if(0)
check_cJSON(jsn, &repeat);
from_cjson(jsn->child);
cJSON_Delete(jsn);
return true;
}
return false;
}
void gb_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 gb_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)(gb_json*) = type_ == VAL_TYPE_OBJECT ? gb_json::object_key : gb_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& gb_json::key(void)
{
return key_;
}
bool gb_json::is_array(void)
{
return type_ == VAL_TYPE_ARRAY;
}
bool gb_json::is_leaf_node(void)
{
return type_ == VAL_TYPE_BOOL ||
type_ == VAL_TYPE_INT ||
type_ == VAL_TYPE_FLOAT ||
type_ == VAL_TYPE_STRING;
}
bool gb_json::get_value(const char* key, bool& val)
{
bool ret = false;
gb_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 gb_json::get_value(const char* key, int& val)
{
bool ret = false;
gb_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 gb_json::get_value(const char* key, double& val)
{
bool ret = false;
gb_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;
}
// added on 2023-04-27: for cJSON consider both int and float as CJSON_Number, we consider int if the value is just an integer
if(!ret)
{
int v = 0;
ret = get_value(key, v);
if(ret)
val = v;
}
return ret;
}
bool gb_json::get_value(const char* key, std::string& val)
{
bool ret = false;
gb_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 gb_json::get_value(const char* key, gb_json*& val)
{
bool ret = false;
gb_json *child = find_child(key);
if (child)
{
if (child->type_ == VAL_TYPE_OBJECT || child->type_ == VAL_TYPE_ARRAY)
{
val = child;
ret = true;
}
else
{
child->release();
}
}
return ret;
}
size_t gb_json::children(void)
{
if (type_ == VAL_TYPE_ARRAY || type_ == VAL_TYPE_OBJECT)
return arr_val_.size();
else
return -1;
}
gb_json* gb_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;
}
gb_json* gb_json::first_child(void)
{
if (type_ == VAL_TYPE_OBJECT || type_ == VAL_TYPE_ARRAY)
{
cur_child_ = 0;
if (arr_val_.size())
{
arr_val_[0]->add_ref();
return arr_val_[0];
}
}
return nullptr;
}
gb_json* gb_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 gb_json::set_value(const char* key, bool val)
{
if (type_ != VAL_TYPE_OBJECT)
return false;
gb_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 gb_json(key, val);
arr_val_.push_back(child);
}
return true;
}
bool gb_json::set_value(const char* key, int val)
{
if (type_ != VAL_TYPE_OBJECT)
return false;
gb_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 gb_json(key, val);
arr_val_.push_back(child);
}
return true;
}
bool gb_json::set_value(const char* key, double val)
{
if (type_ != VAL_TYPE_OBJECT)
return false;
gb_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 gb_json(key, val);
arr_val_.push_back(child);
}
return true;
}
bool gb_json::set_value(const char* key, const char* val)
{
if (type_ != VAL_TYPE_OBJECT)
return false;
gb_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 gb_json(key, val);
arr_val_.push_back(child);
}
return true;
}
bool gb_json::set_value(const char* key, gb_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;
}
gb_json& gb_json::operator+=(bool val)
{
if (type_ == VAL_TYPE_ARRAY)
{
gb_json* child = new gb_json(nullptr, val);
arr_val_.push_back(child);
}
return *this;
}
gb_json& gb_json::operator+=(int val)
{
if (type_ == VAL_TYPE_ARRAY)
{
gb_json* child = new gb_json(nullptr, val);
arr_val_.push_back(child);
}
return *this;
}
gb_json& gb_json::operator+=(double val)
{
if (type_ == VAL_TYPE_ARRAY)
{
gb_json* child = new gb_json(nullptr, val);
arr_val_.push_back(child);
}
return *this;
}
gb_json& gb_json::operator+=(const char* val)
{
if (type_ == VAL_TYPE_ARRAY)
{
gb_json* child = new gb_json(nullptr, val);
arr_val_.push_back(child);
}
return *this;
}
gb_json& gb_json::operator+=(gb_json* val)
{
if (type_ == VAL_TYPE_ARRAY)
{
val->add_ref();
arr_val_.push_back(val);
}
return *this;
}
gb_json& gb_json::operator-=(int ind)
{
remove(ind);
return *this;
}
bool gb_json::remove(const char* key)
{
gb_json* child = find_child(key, true);
if (child)
{
child->release();
return true;
}
else
{
return false;
}
}
bool gb_json::remove(gb_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 gb_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 gb_json::index(gb_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 gb_json::index_move_to(gb_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;
}
int gb_json::insert(int ind, const char* key, gb_json* child)
{
int i = index(child);
if (i == -1)
{
if (ind < 0)
ind = 0;
else if (ind > arr_val_.size())
ind = arr_val_.size();
child->key() = key ? key : "";
arr_val_.insert(arr_val_.begin() + ind, child);
child->add_ref();
}
else if(i != ind)
{
arr_val_.erase(arr_val_.begin() + i);
if (ind < 0)
ind = 0;
if (ind > arr_val_.size())
ind = arr_val_.size();
child->key() = key ? key : "";
arr_val_.insert(arr_val_.begin() + ind, child);
}
return ind;
}
bool gb_json::value(bool& val)
{
bool ret = false;
if (is_leaf_node() && type_ == VAL_TYPE_BOOL)
{
val = simple_val_.bval;
ret = true;
}
return ret;
}
bool gb_json::value(int& val)
{
bool ret = false;
if (is_leaf_node() && type_ == VAL_TYPE_INT)
{
val = simple_val_.nval;
ret = true;
}
return ret;
}
bool gb_json::value(double& val)
{
bool ret = false;
if (is_leaf_node() && type_ == VAL_TYPE_FLOAT)
{
val = simple_val_.dval;
ret = true;
}
return ret;
}
bool gb_json::value(std::string& val)
{
bool ret = false;
if (is_leaf_node() && type_ == VAL_TYPE_STRING)
{
val = strval_;
ret = true;
}
return ret;
}
gb_json& gb_json::operator=(bool val)
{
if (is_leaf_node())
{
simple_val_.bval = val;
type_ = VAL_TYPE_BOOL;
}
return *this;
}
gb_json& gb_json::operator=(int val)
{
if (is_leaf_node())
{
simple_val_.nval = val;
type_ = VAL_TYPE_INT;
}
return *this;
}
gb_json& gb_json::operator=(double val)
{
if (is_leaf_node())
{
simple_val_.dval = val;
type_ = VAL_TYPE_FLOAT;
}
return *this;
}
gb_json& gb_json::operator=(const char* val)
{
if (is_leaf_node())
{
strval_ = val ? val : "";
type_ = VAL_TYPE_STRING;
}
return *this;
}
bool gb_json::operator==(const gb_json& r)
{
if (type_ != r.type_)
return false;
if (type_ == VAL_TYPE_BOOL)
return simple_val_.bval == r.simple_val_.bval;
if (type_ == VAL_TYPE_INT)
return simple_val_.nval == r.simple_val_.nval;
if (type_ == VAL_TYPE_FLOAT)
return fabs(simple_val_.dval - r.simple_val_.dval) < .00001;
if (type_ == VAL_TYPE_STRING)
return strval_ == r.strval_;
if (arr_val_.size() != r.arr_val_.size())
return false;
for (int i = 0; i < arr_val_.size(); ++i)
{
if (!(*arr_val_[i] == *r.arr_val_[i]))
return false;
}
return true;
}
bool gb_json::operator!=(const gb_json& r)
{
return !(*this == r);
}
2024-01-13 09:14:12 +00:00
bool gb_json::revise_number_type(bool dbval)
{
bool chg = false;
if (dbval)
{
// int -> double
if (type_ == VAL_TYPE_INT)
{
type_ = VAL_TYPE_FLOAT;
simple_val_.dval = simple_val_.nval;
chg = true;
}
else
chg = type_ == VAL_TYPE_FLOAT;
}
else
{
// double -> int
if (type_ == VAL_TYPE_FLOAT)
{
type_ = VAL_TYPE_INT;
simple_val_.nval = simple_val_.dval + .5f;
chg = true;
}
else
chg = type_ == VAL_TYPE_INT;
}
return chg;
}