diff --git a/ejson/Array.cpp b/ejson/Array.cpp index e69de29..f2ab721 100644 --- a/ejson/Array.cpp +++ b/ejson/Array.cpp @@ -0,0 +1,38 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2011, Edouard DUPIN, all right reserved + * + * @license BSD v3 (see license file) + */ + + +#include +#include +#include +#include +#include + +#undef __class__ +#define __class__ "Array" + + +void ejson::Array::Clear(void) +{ + +} + +bool ejson::Array::IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc) +{ + return false; +} + + +bool ejson::Array::IGenerate(etk::UString& _data, int32_t _indent) const +{ + return false; +} + + + + diff --git a/ejson/Array.h b/ejson/Array.h index e69de29..dee94de 100644 --- a/ejson/Array.h +++ b/ejson/Array.h @@ -0,0 +1,72 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2011, Edouard DUPIN, all right reserved + * + * @license BSD v3 (see license file) + */ + +#ifndef __ETK_JSON_ARRAY_H__ +#define __ETK_JSON_ARRAY_H__ + +#include +#include +#include +#include + +namespace ejson +{ + class Array : public ejson::Value + { + public: + /** + * @brief basic element of a xml structure + */ + Array(void) { }; + /** + * @brief destructor + */ + virtual ~Array(void) { }; + public: + /** + * @brief Parse the Current node [pure VIRUAL] + * @param[in] _data data string to parse. + * @param[in,out] _pos position in the string to start parse, return the position end of parsing. + * @param[in] _caseSensitive Request a parsion of element that is not case sensitive (all element is in low case) + * @param[in,out] file parsing position (line x col x) + * @return false if an error occured. + */ + virtual bool IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc); + /** + * @brief Generate a string with the tree of the xml + * @param[in,out] _data string where to add the elements + * @param[in] current indentation of the file + * @return false if an error occured. + */ + virtual bool IGenerate(etk::UString& _data, int32_t _indent) const; + private: + etk::Vector m_value; //!< vector of sub elements + public: + + public: + /** + * @brief Get the node type. + * @return the type of the Node. + */ + virtual nodeType_te GetType(void) const { return typeArray; }; + public: + /** + * @brief Cast the element in a Array if it is possible. + * @return pointer on the class or NULL. + */ + virtual ejson::Array* ToArray(void) { return this; }; + virtual const ejson::Array* ToArray(void) const{ return this; }; + /** + * @brief Clear the Node + */ + virtual void Clear(void); + }; +}; + +#endif + diff --git a/ejson/Boolean.cpp b/ejson/Boolean.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/ejson/Boolean.h b/ejson/Boolean.h deleted file mode 100644 index e69de29..0000000 diff --git a/ejson/Null.cpp b/ejson/Null.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/ejson/Null.h b/ejson/Null.h deleted file mode 100644 index e69de29..0000000 diff --git a/ejson/Number.cpp b/ejson/Number.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/ejson/Number.h b/ejson/Number.h deleted file mode 100644 index e69de29..0000000 diff --git a/ejson/Object.cpp b/ejson/Object.cpp index e69de29..f9db43a 100644 --- a/ejson/Object.cpp +++ b/ejson/Object.cpp @@ -0,0 +1,176 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2011, Edouard DUPIN, all right reserved + * + * @license BSD v3 (see license file) + */ + + +#include +#include +#include +#include +#include + +#undef __class__ +#define __class__ "Object" + +void ejson::Object::Clear(void) +{ + +} +typedef enum { + parseName, + parseMiddle, + parseValue, +} statusParsing_te; + +bool ejson::Object::IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc) +{ + statusParsing_te mode = parseName; + etk::UString currentName; + JSON_PARSE_ELEMENT("start parse : 'Object' "); + for (int32_t iii=_pos+1; 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]=='}') { + // 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 (CheckAvaillable(_data[iii]) ) { + for (iii++; iii<_data.Size(); iii++) { + _filePos.Check(_data[iii]); + #ifdef ENABLE_DISPLAY_PARSED_ELEMENT + DrawElementParsed(_data[iii], _filePos); + #endif + if (CheckAvaillable(_data[iii])) { + mode = parseMiddle; + 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); + m_value.Add(currentName, tmpElement); + } else if (_data[iii]=='"') { + // find a string: + JSON_PARSE_ELEMENT("find String quoted"); + ejson::String * tmpElement = new ejson::String(true); + if (NULL==tmpElement) { + EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in String"); + _pos=iii; + return false; + } + tmpElement->IParse(_data, iii, _filePos, _doc); + JSON_WARNING(" add : " << currentName); + m_value.Add(currentName, tmpElement); + } 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); + m_value.Add(currentName, tmpElement); + } else if( CheckAvaillable(_data[iii]) ) { + // find a string without "" ==> special hook for the etk-json parser + JSON_PARSE_ELEMENT("find String"); + ejson::String * tmpElement = new ejson::String(false); + if (NULL==tmpElement) { + EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in String"); + _pos=iii; + return false; + } + tmpElement->IParse(_data, iii, _filePos, _doc); + m_value.Add(currentName, tmpElement); + } else if(_data[iii]==',') { + // find Separator : Restart cycle ... + JSON_INFO("start new parse ..."); + mode = parseName; + currentName = ""; + } else { + // find an error .... + EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Find '>' with no element in the element..."); + // move the curent index + _pos = iii+1; + return false; + } + } + } + } + _pos = _data.Size(); + return false; +} +bool ejson::Object::IGenerate(etk::UString& _data, int32_t _indent) const +{ + AddIndent(_data, _indent); + _data += "{\n"; + for (esize_t iii=0; iiiIGenerate(_data, _indent+1); + _data += "\n"; + } + AddIndent(_data, _indent); + _data += "}\n"; + return true; +} + + + + diff --git a/ejson/Object.h b/ejson/Object.h index e69de29..d77e792 100644 --- a/ejson/Object.h +++ b/ejson/Object.h @@ -0,0 +1,73 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2011, Edouard DUPIN, all right reserved + * + * @license BSD v3 (see license file) + */ + +#ifndef __ETK_JSON_OBJECT_H__ +#define __ETK_JSON_OBJECT_H__ + +#include +#include +#include +#include +#include + +namespace ejson +{ + class Object : public ejson::Value + { + public: + /** + * @brief basic element of a xml structure + */ + Object(void) { }; + /** + * @brief destructor + */ + virtual ~Object(void) { }; + public: + /** + * @brief Parse the Current node [pure VIRUAL] + * @param[in] _data data string to parse. + * @param[in,out] _pos position in the string to start parse, return the position end of parsing. + * @param[in] _caseSensitive Request a parsion of element that is not case sensitive (all element is in low case) + * @param[in,out] file parsing position (line x col x) + * @return false if an error occured. + */ + virtual bool IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc); + /** + * @brief Generate a string with the tree of the xml + * @param[in,out] _data string where to add the elements + * @param[in] current indentation of the file + * @return false if an error occured. + */ + virtual bool IGenerate(etk::UString& _data, int32_t _indent) const; + protected: + etk::Hash m_value; //!< value of the node (for element this is the name, for text it is the inside text ...) + public: + + public: + /** + * @brief Get the node type. + * @return the type of the Node. + */ + virtual nodeType_te GetType(void) const { return typeObject; }; + public: + /** + * @brief Cast the element in a Object if it is possible. + * @return pointer on the class or NULL. + */ + virtual ejson::Object* ToObject(void) { return this; }; + virtual const ejson::Object* ToObject(void) const{ return this; }; + /** + * @brief Clear the Node + */ + virtual void Clear(void); + }; +}; + +#endif + diff --git a/ejson/String.cpp b/ejson/String.cpp new file mode 100644 index 0000000..adaf9f5 --- /dev/null +++ b/ejson/String.cpp @@ -0,0 +1,80 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2011, Edouard DUPIN, all right reserved + * + * @license BSD v3 (see license file) + */ + + +#include +#include +#include +#include +#include + +#undef __class__ +#define __class__ "String" + +void ejson::String::Clear(void) +{ + +} + + +bool ejson::String::IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc) +{ + JSON_PARSE_ELEMENT("start parse : 'String' "); + for (int32_t iii=_pos+1; 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(m_quoted==true) { + // TODO : manage \x + if( _data[iii]!= '"') { + m_value += _data[iii]; + } else { + _pos = iii; + return true; + } + } else { + if (CheckAvaillable(_data[iii]) ) { + m_value += _data[iii]; + } else { + _pos = iii; + return true; + } + } + } + if(m_quoted==true) { + _pos=_data.Size(); + EJSON_CREATE_ERROR(_doc, _data, _pos, _filePos, "get end of string whithout fincding end of quote"); + return false; + } + _pos=_data.Size(); + return true; +} + + +bool ejson::String::IGenerate(etk::UString& _data, int32_t _indent) const +{ + if (m_quoted==true) { + _data += '"'; + } + _data += m_value; + if (m_quoted==true) { + _data += '"'; + } + return true; +} + + + + diff --git a/ejson/String.h b/ejson/String.h new file mode 100644 index 0000000..2d52dcc --- /dev/null +++ b/ejson/String.h @@ -0,0 +1,83 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2011, Edouard DUPIN, all right reserved + * + * @license BSD v3 (see license file) + */ + +#ifndef __ETK_JSON_STRING_H__ +#define __ETK_JSON_STRING_H__ + +#include +#include +#include +#include + +namespace ejson +{ + class String : public ejson::Value + { + private: + bool m_quoted; //!< this is for all element that is not generised (like null & numbers) + public: + /** + * @brief basic element of a xml structure + */ + String(bool _quoted=false) : m_quoted(_quoted) { }; + /** + * @brief destructor + */ + virtual ~String(void) { }; + public: + /** + * @brief Parse the Current node [pure VIRUAL] + * @param[in] _data data string to parse. + * @param[in,out] _pos position in the string to start parse, return the position end of parsing. + * @param[in] _caseSensitive Request a parsion of element that is not case sensitive (all element is in low case) + * @param[in,out] file parsing position (line x col x) + * @return false if an error occured. + */ + virtual bool IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc); + /** + * @brief Generate a string with the tree of the xml + * @param[in,out] _data string where to add the elements + * @param[in] current indentation of the file + * @return false if an error occured. + */ + virtual bool IGenerate(etk::UString& _data, int32_t _indent) const; + protected: + etk::UString m_value; //!< value of the node (for element this is the name, for text it is the inside text ...) + public: + /** + * @brief Set the value of the node. + * @param[in] _value New value of the node. + */ + void SetValue(etk::UString _value) { m_value = _value; }; + /** + * @brief Get the current element Value. + * @return the reference of the string value. + */ + const etk::UString& GetValue(void) const { return m_value; }; + public: + /** + * @brief Get the node type. + * @return the type of the Node. + */ + virtual nodeType_te GetType(void) const { return typeString; }; + public: + /** + * @brief Cast the element in a Object if it is possible. + * @return pointer on the class or NULL. + */ + virtual ejson::String* ToString(void) { return this; }; + virtual const ejson::String* ToString(void) const{ return this; }; + /** + * @brief Clear the Node + */ + virtual void Clear(void); + }; +}; + +#endif + diff --git a/ejson/Value.cpp b/ejson/Value.cpp index 3eded60..1cc4d96 100644 --- a/ejson/Value.cpp +++ b/ejson/Value.cpp @@ -8,6 +8,7 @@ #include #include +#include #undef __class__ #define __class__ "Value" @@ -23,12 +24,6 @@ etk::CCout& ejson::operator <<(etk::CCout& _os, const ejson::filePos& _obj) return _os; } -ejson::Value::Value(const etk::UString& _value) : - m_pos(0,0), - m_value(_value) -{ - // nothing to do. -} void ejson::Value::AddIndent(etk::UString& _data, int32_t _indent) const { @@ -64,22 +59,56 @@ int32_t ejson::Value::CountWhiteChar(const etk::UString& _data, int32_t _pos, ej return white; } -void ejson::Value::Clear(void) + +bool ejson::Value::CheckAvaillable(const etk::UniChar& _val, bool _firstChar) const { - m_value=""; - m_pos.Clear(); + if( _val == '!' + || _val == '"' + || _val == '#' + || _val == '$' + || _val == '%' + || _val == '&' + || _val == '\'' // ' + || _val == '(' + || _val == ')' + || _val == '*' + || _val == '+' + || _val == ',' + || _val == '/' + || _val == ';' + || _val == '<' + || _val == '=' + || _val == '>' + || _val == '?' + || _val == '@' + || _val == '[' + || _val == '\\' + || _val == ']' + || _val == '^' + || _val == '`' + || _val == '{' + || _val == '|' + || _val == '}' + || _val == '~' + || _val == ' ' + || _val == '\n' + || _val == '\t' + || _val == '\r') { + return false; + } + return true; } -bool ejson::Value::IParse(const etk::UString& _data, int32_t& _pos, exml::filePos& _filePos, ejson::Document& _doc) +bool ejson::Value::IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc) { - JSON_PARSE_ELEMENT("start parse : 'Value' named='" << m_value << "'"); - for (int32_t iii=_pos; iii<_data.Size(); iii++) { + JSON_PARSE_ELEMENT("start parse : 'Value' "); + for (int32_t iii=_pos+1; iii<_data.Size(); iii++) { _filePos.Check(_data[iii]); #ifdef ENABLE_DISPLAY_PARSED_ELEMENT DrawElementParsed(_data[iii], _filePos); #endif - exml::filePos tmpPos; + ejson::filePos tmpPos; if( _data[iii]==' ' || _data[iii]=='\t' || _data[iii]=='\n' @@ -89,40 +118,23 @@ bool ejson::Value::IParse(const etk::UString& _data, int32_t& _pos, exml::filePo // find an object: } else if (_data[iii]=='"') { - // find a string + // find a string: } else if (_data[iii]=='[') { // find a list: - } else if( _data[iii]=='n' - && iii+3<_data.Size() - && _data[iii+1]=='u' - && _data[iii+2]=='l' - && _data[iii+3]=='l') { - // maybe find null: - - } else if( _data[iii]=='t' - && iii+3<_data.Size() - && _data[iii+1]=='r' - && _data[iii+2]=='u' - && _data[iii+3]=='u') { - // maybe find true: - - } else if( _data[iii]=='f' - && iii+3<_data.Size() - && _data[iii+1]=='a' - && _data[iii+2]=='l' - && _data[iii+3]=='s' - && _data[iii+4]=='e') { - // maybe find false: - - } else if( _data[iii]=>'0' - && _data[iii]=<'9') { - // maybe find number: + } else if( CheckAvaillable(_data[iii]) ) { + // find a string without "" ==> special hook for the etk-json parser + } else if( _data[iii]==']' + || _data[iii]=='}' + || _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 { // find an error .... - CREATE_ERROR(_doc, _data, _pos, _filePos, "Find '>' with no element in the element..."); + EJSON_CREATE_ERROR(_doc, _data, _pos, _filePos, "Find '>' with no element in the element..."); // move the curent index _pos += iii+1; return false; diff --git a/ejson/Value.h b/ejson/Value.h index 1719dd7..647cd0d 100644 --- a/ejson/Value.h +++ b/ejson/Value.h @@ -13,32 +13,30 @@ #include #include -namespace exml +namespace ejson { - #if 1 - #define EXML_PARSE_ELEMENT EXML_VERBOSE + #define ENABLE_DISPLAY_PARSED_ELEMENT + #if 0 + #define JSON_PARSE_ELEMENT JSON_VERBOSE #else - #define EXML_PARSE_ELEMENT EXML_DEBUG + #define JSON_PARSE_ELEMENT JSON_DEBUG #endif - #if 1 - #define EXML_PARSE_ATTRIBUTE EXML_VERBOSE + #if 0 + #define JSON_PARSE_ATTRIBUTE JSON_VERBOSE #else - #define EXML_PARSE_ATTRIBUTE EXML_DEBUG + #define JSON_PARSE_ATTRIBUTE JSON_DEBUG #endif class Document; - class Attribute; - class Comment; - class Declaration; - class Element; - class Text; + class Array; + class Object; + class String; typedef enum { typeUnknow, //!< might be an error ... typeValue, //!< XXXXXX:* typeDocument, //!< all the file main access typeArray, //!< [...] - typeNull, //!< the 'null' - typeNumber, //!< the 216516.211651e+5454 + typeString, //!< the "" or %d numbers null ... typeObject, //!< the { ... } } nodeType_te; @@ -105,12 +103,7 @@ namespace exml /** * @brief basic element of a xml structure */ - Value(void) : m_pos(0,0) { }; - /** - * @brief basic element of a xml structure - * @param[in] value of the value - */ - Value(const etk::UString& _value); + Value(void) { }; /** * @brief destructor */ @@ -124,7 +117,7 @@ namespace exml * @param[in,out] file parsing position (line x col x) * @return false if an error occured. */ - virtual bool IParse(const etk::UString& _data, int32_t& _pos, exml::filePos& _filePos, ejson::Document& _doc) = 0; + virtual bool IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc); /** * @brief Generate a string with the tree of the xml * @param[in,out] _data string where to add the elements @@ -132,19 +125,6 @@ namespace exml * @return false if an error occured. */ virtual bool IGenerate(etk::UString& _data, int32_t _indent) const { return true; }; - protected: - etk::UString m_value; //!< value of the node (for element this is the name, for text it is the inside text ...) - public: - /** - * @brief Set the value of the node. - * @param[in] _value New value of the node. - */ - virtual void SetValue(etk::UString _value) { m_value = _value; }; - /** - * @brief Get the current element Value. - * @return the reference of the string value. - */ - virtual const etk::UString& GetValue(void) const { return m_value; }; public: /** * @brief Get the node type. @@ -163,7 +143,13 @@ namespace exml * @param[in] _val Char that is parsed. * @param[in] _filePos Position of the char in the file. */ - void DrawElementParsed(const etk::UniChar& _val, const exml::filePos& _filePos) const; + void DrawElementParsed(const etk::UniChar& _val, const ejson::filePos& _filePos) const; + /** + * @brief check if an element or attribute is availlable (not : !"#$%&'()*+,/;<=>?@[\]^`{|}~ \n\t\r and for first char : not -.0123456789). + * @param[in] _val Value to check the conformity. + * @param[in] _firstChar True if the element check is the first char. + */ + bool CheckAvaillable(const etk::UniChar& _val, bool _firstChar=true) const; /** * @brief count the number of white char in the string from the specify position (stop at the first element that is not a white char) * @param[in] _data Data to parse. @@ -171,7 +157,7 @@ namespace exml * @param[out] _filePos new poistion of te file to add. * @return number of white element. */ - int32_t CountWhiteChar(const etk::UString& _data, int32_t _pos, exml::filePos& _filePos) const; + int32_t CountWhiteChar(const etk::UString& _data, int32_t _pos, ejson::filePos& _filePos) const; public: /** * @brief Cast the element in a Document if it is possible. @@ -192,23 +178,11 @@ namespace exml virtual ejson::Object* ToObject(void) { return NULL; }; virtual const ejson::Object* ToObject(void) const{ return NULL; }; /** - * @brief Cast the element in a Boolean if it is possible. + * @brief Cast the element in a String if it is possible. * @return pointer on the class or NULL. */ - virtual ejson::Boolean* ToBoolean(void) { return NULL; }; - virtual const ejson::Boolean* ToBoolean(void) const{ return NULL; }; - /** - * @brief Cast the element in a Null if it is possible. - * @return pointer on the class or NULL. - */ - virtual ejson::Null* ToNull(void) { return NULL; }; - virtual const ejson::Null* ToNull(void) const{ return NULL; }; - /** - * @brief Cast the element in a Number if it is possible. - * @return pointer on the class or NULL. - */ - virtual ejson::Number* ToNumber(void) { return NULL; }; - virtual const ejson::Number* ToNumber(void) const{ return NULL; }; + virtual ejson::String* ToString(void) { return NULL; }; + virtual const ejson::String* ToString(void) const{ return NULL; }; /** * @brief Check if the node is a ejson::Document @@ -226,25 +200,15 @@ namespace exml */ bool IsObject(void) const { return GetType()==ejson::typeObject; }; /** - * @brief Check if the node is a ejson::Boolean - * @return true if the node is a ejson::Boolean + * @brief Check if the node is a ejson::String + * @return true if the node is a ejson::String */ - bool IsBoolean(void) const { return GetType()==ejson::typeBoolean; }; - /** - * @brief Check if the node is a ejson::Null - * @return true if the node is a ejson::Null - */ - bool IsNull(void) const { return GetType()==ejson::typeNull; }; - /** - * @brief Check if the node is a ejson::Number - * @return true if the node is a ejson::Number - */ - bool IsNumber(void) const { return GetType()==ejson::typeNumber; }; + bool IsString(void) const { return GetType()==ejson::typeString; }; /** * @brief Clear the Node */ - virtual void Clear(void); + virtual void Clear(void) {}; }; }; diff --git a/ejson/ejson.cpp b/ejson/ejson.cpp index a92bb10..d7f2e74 100644 --- a/ejson/ejson.cpp +++ b/ejson/ejson.cpp @@ -6,14 +6,19 @@ * @license BSD v3 (see license file) */ -#include +#include #include #include +#include +#include +#include + #undef __class__ #define __class__ "Document" ejson::Document::Document(void) : + m_subElement(NULL), m_writeErrorWhenDetexted(true), m_comment(""), m_Line(""), @@ -22,13 +27,23 @@ ejson::Document::Document(void) : } +ejson::Document::~Document(void) +{ + if (NULL!=m_subElement) { + delete m_subElement; + m_subElement=NULL; + } +} + bool ejson::Document::IGenerate(etk::UString& _data, int32_t _indent) const { - for (int32_t iii=0; iiiIGenerate(_data, _indent); - } + AddIndent(_data, _indent); + _data += "{\n"; + if (NULL!=m_subElement) { + m_subElement->IGenerate(_data, _indent+1); } + AddIndent(_data, _indent); + _data += "}\n"; return true; } @@ -38,7 +53,7 @@ bool ejson::Document::Parse(const etk::UString& _data) Clear(); ejson::filePos filePos(1,0); int32_t parsePos = 0; - return SubParse(_data, parsePos, m_caseSensitive, filePos, *this, true); + return IParse(_data, parsePos, filePos, *this); } bool ejson::Document::Generate(etk::UString& _data) @@ -160,3 +175,75 @@ void ejson::Document::CreateError(const etk::UString& _data, int32_t _pos, const } } +bool ejson::Document::IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc) +{ + JSON_PARSE_ELEMENT("start parse : 'Value' "); + for (int32_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]=='{') { + // 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); + m_subElement = tmpElement; + } else if (_data[iii]=='"') { + // find a string: + JSON_PARSE_ELEMENT("find String quoted"); + ejson::String * tmpElement = new ejson::String(true); + if (NULL==tmpElement) { + EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in String"); + _pos=iii; + return false; + } + tmpElement->IParse(_data, iii, _filePos, _doc); + m_subElement = tmpElement; + } 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); + m_subElement = tmpElement; + } else if( CheckAvaillable(_data[iii]) ) { + // find a string without "" ==> special hook for the etk-json parser + JSON_PARSE_ELEMENT("find String"); + ejson::String * tmpElement = new ejson::String(false); + if (NULL==tmpElement) { + EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, "Allocation error in String"); + _pos=iii; + return false; + } + tmpElement->IParse(_data, iii, _filePos, _doc); + m_subElement = tmpElement; + } 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 { + // find an error .... + EJSON_CREATE_ERROR(_doc, _data, iii, _filePos, etk::UString("Find '") + _data[iii] + "' with no element in the element..."); + // move the curent index + _pos = iii+1; + return false; + } + } + return true; +} diff --git a/ejson/ejson.h b/ejson/ejson.h index d718092..3b5218f 100644 --- a/ejson/ejson.h +++ b/ejson/ejson.h @@ -9,13 +9,14 @@ #ifndef __ETK_JSON_H__ #define __ETK_JSON_H__ -#include +#include #include #include +#include namespace ejson { - class Document : public ejson::Object + class Document : public ejson::Value { public: /** @@ -25,7 +26,7 @@ namespace ejson /** * @brief Destructor */ - virtual ~Document(void) { }; + virtual ~Document(void); public: /** * @brief Parse a string that contain an XML @@ -59,6 +60,10 @@ namespace ejson * @brief Display the Document on console */ void Display(void); + private: + ejson::Value* m_subElement; //!< only element that contain the json document: + public: + // TODO : sdfsdfsdf private: bool m_writeErrorWhenDetexted; etk::UString m_comment; @@ -72,7 +77,7 @@ namespace ejson void DisplayError(void); public: // herited function: virtual nodeType_te GetType(void) const { return typeDocument; }; - bool IParse(const etk::UString& _data, int32_t& _pos, exml::filePos& _filePos, ejson::Document& _doc); + bool IParse(const etk::UString& _data, int32_t& _pos, ejson::filePos& _filePos, ejson::Document& _doc); bool IGenerate(etk::UString& _data, int32_t _indent) const; virtual ejson::Document* ToDocument(void) { return this; }; virtual const ejson::Document* ToDocument(void) const { return this; }; @@ -81,7 +86,7 @@ namespace ejson #define EJSON_CREATE_ERROR(doc,data,pos,filePos,comment) \ do { \ - JSON_ERROR(comment); \ + JSON_CRITICAL(comment); \ (doc).CreateError((data),(pos),(filePos),(comment)); \ } while (0) diff --git a/ejson/test.cpp b/ejson/test.cpp new file mode 100644 index 0000000..1fead19 --- /dev/null +++ b/ejson/test.cpp @@ -0,0 +1,171 @@ +/** + * @author Edouard DUPIN + * + * @copyright 2011, Edouard DUPIN, all right reserved + * + * @license BSD v3 (see license file) + */ + +#include +#include +#include +#include +#include + +#undef __class__ +#define __class__ "ejson::test" + +class testCheck +{ + public: + etk::UString m_ref; + etk::UString m_input; + int32_t m_errorPos; // -1 : no error , 1 : parsing error, 2 generation error, 3 comparaison error ???? + testCheck(void) {}; + void Set(const etk::UString& _ref, int32_t _pos, const etk::UString& _input) + { + m_ref = _ref; + m_input = _input; + m_errorPos = _pos; + } +}; + +etk::Vector l_list; + +void Init(void) +{ + etk::UString reference; + etk::UString input; + testCheck check; + + // ====================================================== + check.Set("test ejson::Doc", -2, ""); + l_list.PushBack(check); + // ====================================================== + reference = "{\n}\n"; + check.Set(reference, + -1, + "{}\n"); + l_list.PushBack(check); + // ------------------------------------------------------ + check.Set(reference, + -1, + "{ \t\r }\n"); + l_list.PushBack(check); + // ====================================================== + check.Set("test ejson::all", -2, ""); + l_list.PushBack(check); + // ====================================================== + reference = "{\n" + " \"menu\": {\n" + " \"id\": \"file\",\n" + " \"value\": \"File\",\n" + " \"popup\": {\n" + " \"menuitem\": {\"value\": \"Close\", \"onclick\": \"CloseDoc()\"}\n" + " }\n" + " }\n" + "}\n"; + check.Set(reference, + -1, + reference); + l_list.PushBack(check); + reference = "{\n" + " \"menu\": {\n" + " \"id\": \"file\",\n" + " \"value\": \"File\",\n" + " \"popup\": {\n" + " \"menuitem\": [\n" + " {\"value\": \"New\", \"onclick\": \"CreateNewDoc()\"},\n" + " {\"value\": \"Open\", \"onclick\": \"OpenDoc()\"},\n" + " {\"value\": \"Close\", \"onclick\": \"CloseDoc()\"}\n" + " ]\n" + " }\n" + " }\n" + "}\n"; + check.Set(reference, + -1, + reference); + l_list.PushBack(check); +} + +int main(int argc, const char *argv[]) +{ + GeneralDebugSetLevel(etk::LOG_LEVEL_VERBOSE); + Init(); + int32_t countError = 0; + int32_t countSeparator = 0; + int32_t sectionID = 0; + for (int32_t iii=0 ; iii0) { + JSON_ERROR("[TEST] produce " << countError << " error on " << l_list.Size()-countSeparator << " test"); + } else { + JSON_INFO("[TEST] produce " << countError << " error on " << l_list.Size()-countSeparator << " test"); + } + return 0; +} + diff --git a/lutin_ejson.py b/lutin_ejson.py index c866d0c..ac63777 100644 --- a/lutin_ejson.py +++ b/lutin_ejson.py @@ -9,13 +9,9 @@ def Create(target): myModule.AddSrcFile([ 'ejson/debug.cpp', - 'ejson/Node.cpp', 'ejson/ejson.cpp', 'ejson/Array.cpp', - 'ejson/Boolean.cpp', - 'ejson/Node.cpp', - 'ejson/Null.cpp', - 'ejson/Number.cpp', + 'ejson/String.cpp', 'ejson/Object.cpp', 'ejson/Value.cpp']) diff --git a/lutin_ejsontest.py b/lutin_ejsontest.py new file mode 100644 index 0000000..7a14f32 --- /dev/null +++ b/lutin_ejsontest.py @@ -0,0 +1,31 @@ +#!/usr/bin/python +import lutinModule +import lutinTools +import datetime + +def Create(target): + # module name is 'edn' and type binary. + myModule = lutinModule.module(__file__, 'ejsontest', 'BINARY') + + # add the file to compile: + myModule.AddSrcFile([ + 'ejson/test.cpp']) + + myModule.AddModuleDepend(['ejson']) + + now = datetime.datetime.now() + versionID=str(now.year-2012)+"."+str(now.month)+"."+str(now.day) + + # set the package properties : + myModule.pkgSet("VERSION", versionID) + myModule.pkgSet("COMPAGNY_TYPE", "org") + myModule.pkgSet("COMPAGNY_NAME", "Edouard DUPIN") + myModule.pkgSet("MAINTAINER", ["Mr DUPIN Edouard "]) + myModule.pkgSet("SECTION", ["Development"]) + myModule.pkgSet("PRIORITY", "optional") + myModule.pkgSet("DESCRIPTION", "e-json tester soft") + myModule.pkgSet("NAME", "exml_tester") + + # add the currrent module at the + return myModule +