ejson/ejson/ejson.cpp

201 lines
5.1 KiB
C++

/**
* @author Edouard DUPIN
*
* @copyright 2011, Edouard DUPIN, all right reserved
*
* @license APACHE v2.0 (see license file)
*/
#include <ejson/ejson.h>
#include <ejson/debug.h>
#include <etk/os/FSNode.h>
#include <ejson/Object.h>
#include <ejson/Array.h>
#include <ejson/String.h>
#include <ejson/Null.h>
#include <ejson/Number.h>
#include <ejson/Boolean.h>
ememory::SharedPtr<ejson::Document> ejson::Document::create() {
return ememory::SharedPtr<ejson::Document>(new ejson::Document());
}
ejson::Document::Document() :
m_writeErrorWhenDetexted(true),
m_comment(""),
m_Line(""),
m_filePos(0,0) {
}
ejson::Document::~Document() {
}
bool ejson::Document::iGenerate(std::string& _data, size_t _indent) const {
ejson::Object::iGenerate(_data, _indent+1);
_data += "\n";
return true;
}
bool ejson::Document::parse(const std::string& _data) {
JSON_VERBOSE("Start parsing document (type: string) size=" << _data.size());
clear();
ejson::FilePos filePos(1,0);
size_t parsePos = 0;
return iParse(_data, parsePos, filePos, *this);
}
bool ejson::Document::generate(std::string& _data) {
_data = "";
return iGenerate(_data,0);
}
bool ejson::Document::load(const std::string& _file) {
// Start loading the XML :
JSON_VERBOSE("open file (xml) \"" << _file << "\"");
clear();
etk::FSNode tmpFile(_file);
if (false == tmpFile.exist()) {
JSON_ERROR("File Does not exist : " << _file);
return false;
}
int64_t fileSize = tmpFile.fileSize();
if (0 == fileSize) {
JSON_ERROR("This file is empty : " << _file);
return false;
}
if (false == tmpFile.fileOpenRead()) {
JSON_ERROR("Can not open (r) the file : " << _file);
return false;
}
// allocate data
std::vector<char> fileBuffer;
fileBuffer.resize(fileSize+5, 0);
// load data from the file :
tmpFile.fileRead(&fileBuffer[0], 1, fileSize);
// close the file:
tmpFile.fileClose();
std::string tmpDataUnicode(&fileBuffer[0]);
// parse the data :
bool ret = parse(tmpDataUnicode);
//Display();
return ret;
}
bool ejson::Document::store(const std::string& _file) {
std::string createData;
if (false == generate(createData)) {
JSON_ERROR("Error while creating the XML : " << _file);
return false;
}
etk::FSNode tmpFile(_file);
if (false == tmpFile.fileOpenWrite()) {
JSON_ERROR("Can not open (w) the file : " << _file);
return false;
}
if (tmpFile.fileWrite((char*)createData.c_str(), sizeof(char), createData.size()) != (int32_t)createData.size()) {
JSON_ERROR("Error while writing output XML file : " << _file);
tmpFile.fileClose();
return false;
}
tmpFile.fileClose();
return true;
}
static std::string createPosPointer(const std::string& _line, size_t _pos) {
std::string out;
size_t iii;
for (iii=0; iii<_pos && iii<_line.size(); iii++) {
if (_line[iii] == '\t') {
out += "\t";
} else {
out += " ";
}
}
for (; iii<_pos; iii++) {
out += " ";
}
out += "^";
return out;
}
void ejson::Document::displayError() {
if (m_comment.size() == 0) {
JSON_ERROR("No error detected ???");
return;
}
JSON_ERROR(m_filePos << " " << m_comment << "\n"
<< m_Line << "\n"
<< createPosPointer(m_Line, m_filePos.getCol()) );
#ifdef ENABLE_CRITICAL_WHEN_ERROR
JSON_CRITICAL("detect error");
#endif
}
void ejson::Document::createError(const std::string& _data, size_t _pos, const ejson::FilePos& _filePos, const std::string& _comment) {
m_comment = _comment;
m_Line = etk::extract_line(_data, _pos);
m_filePos = _filePos;
if (true == m_writeErrorWhenDetexted) {
displayError();
}
}
bool ejson::Document::iParse(const std::string& _data, size_t& _pos, ejson::FilePos& _filePos, ejson::Document& _doc) {
JSON_PARSE_ELEMENT("start parse : 'Document' ");
bool haveMainNode=false;
bool nodeParsed=false;
for (size_t iii=_pos; 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] == '{') {
if (nodeParsed == true) {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "element already parsed");
_pos=iii;
}
// find a main object:
// == > generic sub parsing
iii++;
haveMainNode=true;
nodeParsed=true;
ejson::Object::iParse(_data, iii, _filePos, _doc);
} else if(_data[iii] == '}') {
_pos=iii; // == > return the end element type ==> usefull to check end and check if adding element is needed
if (haveMainNode == true) {
// find end of value:
return true;
} else {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "find } but never start !!!");
return false;
}
} else {
if (nodeParsed == true) {
_pos=iii;
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "element already parsed");
return false;
}
nodeParsed=true;
// this might not have the '{' start element !!!
if (false == ejson::Object::iParse(_data, iii, _filePos, _doc)) {
EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Object sub parsing in error");
_pos = iii;
return false;
}
}
}
return true;
}