ejson/ejson/Object.cpp
2014-09-22 22:14:50 +02:00

491 lines
12 KiB
C++

/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#include <ejson/Object.h>
#include <ejson/Array.h>
#include <ejson/String.h>
#include <ejson/Null.h>
#include <ejson/Number.h>
#include <ejson/Boolean.h>
#include <ejson/debug.h>
#include <ejson/ejson.h>
#undef __class__
#define __class__ "Object"
void ejson::Object::clear() {
for (int32_t iii=0; iii<m_value.size(); ++iii) {
if (NULL == m_value[iii]) {
continue;
}
delete(m_value[iii]);
m_value[iii] = NULL;
}
m_value.clear();
}
enum statusParsing {
parseName,
parseMiddle,
parseValue,
};
bool ejson::Object::iParse(const std::string& _data, size_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc) {
enum statusParsing mode = parseName;
std::string currentName;
JSON_PARSE_ELEMENT("start parse : 'Object' ");
bool standalone = true;
size_t startPos = _pos+1;
if (_data[_pos] != '{' ) { // when the main node call it, it can be start with != '{'
standalone = false;
startPos = _pos;
}
for (size_t iii=startPos; iii<_data.size(); iii++) {
_filePos.check(_data[iii]);
#ifdef ENABLE_DISPLAY_PARSED_ELEMENT
drawElementParsed(_data[iii], _filePos);
#endif
ejson::filePos tmpPos;
if( _data[iii] == ' '
|| _data[iii] == '\t'
|| _data[iii] == '\n'
|| _data[iii] == '\r') {
// white space == > nothing to do ...
} else if(_data[iii] == '#') {
// comment Line ...
for (iii++; iii<_data.size(); iii++) {
if( _data[iii] == '\n'
|| _data[iii] == '\r') {
break;
}
}
} else if(_data[iii] == '}') {
// find end of value:
_pos=iii; // == > return the end element type ==> usefull to check end and check if adding element is needed
return true;
} else {
if (mode == parseName) {
JSON_PARSE_ELEMENT("name START " << '"');
if (_data[iii] == '"') {
currentName = "";
for (iii++; iii<_data.size(); iii++) {
_filePos.check(_data[iii]);
#ifdef ENABLE_DISPLAY_PARSED_ELEMENT
drawElementParsed(_data[iii], _filePos);
#endif
if (_data[iii] == '\"') {
mode = parseMiddle;
break;
} else {
currentName += _data[iii];
}
}
} else if (checkString(_data[iii]) ) {
currentName += _data[iii];
for (iii++; iii<_data.size(); iii++) {
_filePos.check(_data[iii]);
#ifdef ENABLE_DISPLAY_PARSED_ELEMENT
drawElementParsed(_data[iii], _filePos);
#endif
if (false == checkString(_data[iii])) {
mode = parseMiddle;
iii--;
break;
} else {
currentName += _data[iii];
}
}
} else {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "element unknow ...");
_pos = iii;
return false;
}
JSON_PARSE_ELEMENT("name END ");
} else if (mode == parseMiddle) {
JSON_PARSE_ELEMENT(" middle ... ");
if (_data[iii] == ':') {
mode = parseValue;
} else {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "separator is not ':'");
return false;
}
} else if (mode == parseValue) {
if (_data[iii] == '{') {
// find an object:
JSON_PARSE_ELEMENT("find Object");
ejson::Object * tmpElement = new ejson::Object();
if (NULL == tmpElement) {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in object");
_pos=iii;
return false;
}
tmpElement->iParse(_data, iii, _filePos, _doc);
add(currentName, tmpElement);
currentName = "";
} else if (_data[iii] == '"') {
// find a string:
JSON_PARSE_ELEMENT("find String quoted");
ejson::String * tmpElement = new ejson::String();
if (NULL == tmpElement) {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in String");
_pos=iii;
return false;
}
tmpElement->iParse(_data, iii, _filePos, _doc);
add(currentName, tmpElement);
currentName = "";
} else if (_data[iii] == '[') {
// find a list:
JSON_PARSE_ELEMENT("find List");
ejson::Array * tmpElement = new ejson::Array();
if (NULL == tmpElement) {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in Array");
_pos=iii;
return false;
}
tmpElement->iParse(_data, iii, _filePos, _doc);
add(currentName, tmpElement);
currentName = "";
} else if( _data[iii] == 'f'
|| _data[iii] == 't' ) {
// find boolean:
JSON_PARSE_ELEMENT("find Boolean");
ejson::Boolean * tmpElement = new ejson::Boolean();
if (NULL == tmpElement) {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in Boolean");
_pos=iii;
return false;
}
tmpElement->iParse(_data, iii, _filePos, _doc);
add(currentName, tmpElement);
currentName = "";
} else if( _data[iii] == 'n') {
// find null:
JSON_PARSE_ELEMENT("find Null");
ejson::Null * tmpElement = new ejson::Null();
if (NULL == tmpElement) {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in Boolean");
_pos=iii;
return false;
}
tmpElement->iParse(_data, iii, _filePos, _doc);
add(currentName, tmpElement);
currentName = "";
} else if(true == checkNumber(_data[iii])) {
// find number:
JSON_PARSE_ELEMENT("find Number");
ejson::Number * tmpElement = new ejson::Number();
if (NULL == tmpElement) {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in Boolean");
_pos=iii;
return false;
}
tmpElement->iParse(_data, iii, _filePos, _doc);
add(currentName, tmpElement);
currentName = "";
} else if(_data[iii] == ',') {
// find Separator : Restart cycle ...
mode = parseName;
currentName = "";
} else {
// find an error ....
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, std::string("Find '") + _data[iii] + "' with no element in the element...");
// move the curent index
_pos = iii+1;
return false;
}
}
}
}
_pos = _data.size();
if (false == standalone) {
return true;
}
return false;
}
bool ejson::Object::iGenerate(std::string& _data, size_t _indent) const {
bool oneLine=true;
if (m_value.size()>3) {
oneLine=false;
} else if (_indent<=1) {
oneLine=false;
} else {
for (int32_t iii=0; iii<m_value.size() ; iii++) {
ejson::Value* tmp = m_value[iii];
if (tmp == NULL) {
continue;
}
if (true == tmp->isObject()) {
oneLine=false;
break;
}
if (true == tmp->isArray()) {
oneLine=false;
break;
}
if (true == tmp->isString()) {
ejson::String* tmp2 = tmp->toString();
if (tmp2 != nullptr) {
if( tmp2->get().size()>25
|| m_value.getKey(iii).size()>25) {
oneLine=false;
break;
}
}
}
}
}
if (true == oneLine) {
_data += "{ ";
} else {
_data += "{\n";
}
for (int32_t iii=0; iii<m_value.size() ; iii++) {
if (false == oneLine) {
addIndent(_data, _indent);
}
_data += "\"";
_data += m_value.getKey(iii);
_data += "\": ";
m_value.getValue(iii)->iGenerate(_data, _indent+1);
if (iii<m_value.size()-1) {
_data += ",";
}
if (true == oneLine) {
_data += " ";
} else {
_data += "\n";
}
}
if (false == oneLine) {
addIndent(_data, _indent-1);
}
_data += "}";
return true;
}
bool ejson::Object::exist(const std::string& _name) const {
return m_value.exist(_name);
}
ejson::Value* ejson::Object::get(const std::string& _name) {
if (false == m_value.exist(_name)) {
return NULL;
}
return m_value[_name];
}
const ejson::Value* ejson::Object::get(const std::string& _name) const {
if (false == m_value.exist(_name)) {
return NULL;
}
return m_value[_name];
}
ejson::Object* ejson::Object::getObject(const std::string& _name) {
ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return dynamic_cast<ejson::Object*>(tmp);
}
const ejson::Object* ejson::Object::getObject(const std::string& _name) const {
const ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return dynamic_cast<const ejson::Object*>(tmp);
}
ejson::Array* ejson::Object::getArray(const std::string& _name) {
ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return dynamic_cast<ejson::Array*>(tmp);
}
const ejson::Array* ejson::Object::getArray(const std::string& _name) const {
const ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return dynamic_cast<const ejson::Array*>(tmp);
}
ejson::Null* ejson::Object::getNull(const std::string& _name) {
ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return dynamic_cast<ejson::Null*>(tmp);
}
const ejson::Null* ejson::Object::getNull(const std::string& _name) const {
const ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return dynamic_cast<const ejson::Null*>(tmp);
}
ejson::String* ejson::Object::getString(const std::string& _name) {
ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return dynamic_cast<ejson::String*>(tmp);
}
const ejson::String* ejson::Object::getString(const std::string& _name) const {
const ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return dynamic_cast<const ejson::String*>(tmp);
}
const std::string& ejson::Object::getStringValue(const std::string& _name) const {
static const std::string errorString("");
const ejson::String* tmpp = getString(_name);
if (NULL == tmpp) {
return errorString;
}
return tmpp->get();
}
std::string ejson::Object::getStringValue(const std::string& _name, const std::string& _errorValue) const {
const ejson::String* tmpp = getString(_name);
if (NULL == tmpp) {
return _errorValue;
}
return tmpp->get();
}
ejson::Boolean* ejson::Object::getBoolean(const std::string& _name) {
ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return tmp->toBoolean();
}
const ejson::Boolean* ejson::Object::getBoolean(const std::string& _name) const {
const ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return tmp->toBoolean();
}
bool ejson::Object::getBooleanValue(const std::string& _name, bool _errorValue) const {
const ejson::Boolean* tmpp = getBoolean(_name);
if (NULL == tmpp) {
return _errorValue;
}
return tmpp->get();
}
ejson::Number* ejson::Object::getNumber(const std::string& _name) {
ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return tmp->toNumber();
}
const ejson::Number* ejson::Object::getNumber(const std::string& _name) const {
const ejson::Value* tmp = get(_name);
if (NULL == tmp) {
return NULL;
}
return tmp->toNumber();
}
double ejson::Object::getNumberValue(const std::string& _name, double _errorValue) const {
const ejson::Number* tmpp = getNumber(_name);
if (NULL == tmpp) {
return _errorValue;
}
return tmpp->get();
}
bool ejson::Object::add(const std::string& _name, ejson::Value* _value) {
if (NULL == _value) {
return false;
}
if (_name.size() == 0) {
return false;
}
if (m_value.exist(_name)) {
ejson::Value* tmp = m_value[_name];
delete(tmp);
m_value[_name] = _value;
return true;
}
m_value.add(_name, _value);
return true;
}
bool ejson::Object::addString(const std::string& _name, const std::string& _value) {
return add(_name, new ejson::String(_value));
}
bool ejson::Object::addNull(const std::string& _name) {
return add(_name, new ejson::Null());
}
bool ejson::Object::addBoolean(const std::string& _name, bool _value) {
return add(_name, new ejson::Boolean(_value));
}
bool ejson::Object::addNumber(const std::string& _name, double _value) {
return add(_name, new ejson::Number(_value));
}
bool ejson::Object::transfertIn(ejson::Value* _obj) {
if (NULL == _obj) {
JSON_ERROR("Request transfer on an NULL pointer");
return false;
}
ejson::Object* other = _obj->toObject();
if (NULL == other) {
JSON_ERROR("Request transfer on an element that is not an object");
return false;
}
// remove destination elements
other->clear();
// Copy to the destination
other->m_value = m_value;
// remove current:
m_value.clear();
return true;
}
// TODO : Manage error ...
ejson::Value* ejson::Object::duplicate() const {
ejson::Object* output = new ejson::Object();
if (NULL == output) {
JSON_ERROR("Allocation error ...");
return NULL;
}
for (int32_t iii=0; iii<m_value.size(); ++iii) {
ejson::Value* val = m_value.getValue(iii);
std::string key = m_value.getKey(iii);
if (NULL == val) {
continue;
}
output->add(key, val->duplicate());
}
return output;
}