996 lines
17 KiB
C++
996 lines
17 KiB
C++
#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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|