diff --git a/space/jsontospaceparser.cpp b/space/jsontospaceparser.cpp new file mode 100644 index 0000000..c31f5c5 --- /dev/null +++ b/space/jsontospaceparser.cpp @@ -0,0 +1,893 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2012, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "jsontospaceparser.h" +#include "utf8/utf8.h" + + +namespace PT +{ + + + +JSONToSpaceParser::JSONToSpaceParser() +{ + root_space = 0; + SetDefault(); +} + + +void JSONToSpaceParser::SetSpace(Space * pspace) +{ + root_space = pspace; +} + + +void JSONToSpaceParser::SetSpace(Space & pspace) +{ + root_space = &pspace; +} + + +void JSONToSpaceParser::SetDefault() +{ + // you can change this separators to what you want + // you shoud not use only white characters here (as expected by IsWhite() method) + // and new line characters ('\n') + separator = ':'; + space_start = '{'; + space_end = '}'; + table_start = '['; + table_end = ']'; + option_delimiter = ','; + split_single = true; + skip_empty = false; + use_escape_char = true; + input_as_utf8 = true; + max_nested_level = 1000; + create_table_as_space = true; +} + + +void JSONToSpaceParser::SplitSingle(bool split) +{ + split_single = split; +} + + +void JSONToSpaceParser::SkipEmpty(bool skip) +{ + skip_empty = skip; +} + + +void JSONToSpaceParser::UseEscapeChar(bool escape) +{ + use_escape_char = escape; +} + + +void JSONToSpaceParser::UTF8(bool utf) +{ + input_as_utf8 = utf; +} + + +void JSONToSpaceParser::CreateTableAsSpace(bool create_table_as_space_) +{ + create_table_as_space = create_table_as_space_; +} + + +JSONToSpaceParser::Status JSONToSpaceParser::Parse(const char * file_name) +{ + reading_from_file = true; + + file.clear(); + file.open(file_name, std::ios_base::binary | std::ios_base::in); + + if( file ) + { + Parse(); + file.close(); + } + else + { + status = cant_open_file; + } + +return status; +} + + + +JSONToSpaceParser::Status JSONToSpaceParser::Parse(const std::string & file_name) +{ + return Parse(file_name.c_str()); +} + + + + +JSONToSpaceParser::Status JSONToSpaceParser::Parse(const wchar_t * file_name) +{ + PT::WideToUTF8(file_name, afile_name); + return Parse(afile_name.c_str()); +} + + + +JSONToSpaceParser::Status JSONToSpaceParser::Parse(const std::wstring & file_name) +{ + return Parse(file_name.c_str()); +} + + + +JSONToSpaceParser::Status JSONToSpaceParser::ParseString(const char * str) +{ + reading_from_file = false; + reading_from_wchar_string = false; + pchar_ascii = str; + pchar_unicode = 0; + + Parse(); + +return status; +} + + +JSONToSpaceParser::Status JSONToSpaceParser::ParseString(const std::string & str) +{ + return ParseString(str.c_str()); +} + + +JSONToSpaceParser::Status JSONToSpaceParser::ParseString(const wchar_t * str) +{ + reading_from_file = false; + reading_from_wchar_string = true; + pchar_unicode = str; + pchar_ascii = 0; + + Parse(); + +return status; +} + + +JSONToSpaceParser::Status JSONToSpaceParser::ParseString(const std::wstring & str) +{ + return ParseString(str.c_str()); +} + + +void JSONToSpaceParser::Parse() +{ + if( !root_space ) + { + status = no_space; + return; + } + + line = 1; + status = ok; + space = root_space; + skipped = 0; + current_nested_level = 0; + ReadChar(); + SkipWhite(); + + if( lastc == space_start ) + { + ParseSpace(false, false); + } + else + if( lastc == table_start ) + { + ParseTable(false); + } + else + { + // '{' or '[' expected + status = syntax_error; + } + + if( status == ok && space != root_space ) + { + // last closing '}' characters are missing (closing a space) + status = syntax_error; + } + + token.clear(); + key.clear(); + value.clear(); +} + + + + + +void JSONToSpaceParser::ParseSpace(bool has_space_name, bool insert_new_space) +{ + current_nested_level += 1; + + if( current_nested_level > max_nested_level ) + { + status = max_nested_spaces_exceeded; + return; + } + + if( insert_new_space ) + { + SpaceStarts(has_space_name); + } + else + { + // insert_new_space as a false is used only when parsing + // the first space (root_space) + ReadChar(); // skipping the first space character '{' + } + + ParseKeyValuePairs(); + + if( insert_new_space ) + { + SpaceEnds(); + } + else + { + ReadChar(); // skipping the last space character '}' + } +} + + +void JSONToSpaceParser::ParseKeyValuePairs() +{ + SkipWhite(); + + while( status == ok && lastc != space_end && lastc != -1 ) + { + ReadKey(); + SkipWhite(); + + if( lastc == separator ) + { + value.clear(); + ReadChar(); // skipping separator ':' + ReadValue(false, false, true, true); + SkipWhite(); + + if( lastc == option_delimiter ) + { + ReadChar(); // skipping delimiter ',' + } + else + if( lastc != space_end && status == ok ) + { + status = syntax_error; + } + } + else + if( status == ok ) + { + status = syntax_error; + } + } +} + + +void JSONToSpaceParser::ParseTextTable() +{ + ReadChar(); // skipping table start character '[' + SkipWhite(); + value.clear(); + + while( status == ok && lastc != table_end && lastc != -1 ) + { + // all space objects inside or tables will be skipped + ReadValue(true); + SkipWhite(); + + if( lastc == option_delimiter ) + { + ReadChar(); // skipping delimiter ',' + } + else + if( lastc != table_end && status == ok ) + { + status = syntax_error; + } + } + + if( lastc == table_end ) + ReadChar(); // skipping end table character ']' + + AddKeyValuePair(); +} + + +void JSONToSpaceParser::ParseObjectsTable(bool has_key) +{ + ReadChar(); // skipping table start character '[' + SpaceStarts(has_key, false); + SkipWhite(); + + while( status == ok && lastc != table_end && lastc != -1 ) + { + // 'value' table will not be used here + // (we are creating spaces) + ReadValue(false, true); + SkipWhite(); + + if( lastc == option_delimiter ) + { + ReadChar(); // skipping delimiter ',' + } + else + if( lastc != table_end && status == ok ) + { + status = syntax_error; + } + } + + if( lastc == table_end ) + ReadChar(); // skipping end table character ']' + + SpaceEnds(false); +} + + +void JSONToSpaceParser::ParseTable(bool has_key) +{ + if( create_table_as_space ) + { + current_nested_level += 1; + + if( current_nested_level > max_nested_level ) + { + status = max_nested_spaces_exceeded; + } + else + { + ParseObjectsTable(has_key); + } + } + else + { + // ParseTextTable will not create a next level + + if( !has_key ) + key.clear(); + + ParseTextTable(); // ParseTextTable will use key + } +} + + + +void JSONToSpaceParser::SpaceStarts(bool has_space_name, bool skip_space_char) +{ + Space * new_space = new Space(); + space->spaces.push_back(new_space); + new_space->parent = space; + + if( has_space_name ) + new_space->name = key; + + space = new_space; + + if( skip_space_char ) + ReadChar(); // skipping space starts character '{' +} + + +void JSONToSpaceParser::SpaceEnds(bool skip_space_char) +{ + if( space == root_space ) + { + // there cannot be a loose list end character in the global space + status = syntax_error; + } + else + { + space = space->parent; + + if( skip_space_char ) + ReadChar(); // skipping closing space character '}' + } +} + + + +bool JSONToSpaceParser::IsWhite(int c) +{ + // 13 (\r) is at the end of a line in a dos file \r\n + // 160 is an unbreakable space + if( c==' ' || c=='\t' || c==13 || c==160 || c==10 ) + return true; + +return false; +} + + + +void JSONToSpaceParser::SkipWhite() +{ + while( IsWhite(lastc) ) + { + ReadChar(); + } +} + + + +void JSONToSpaceParser::Trim(std::wstring & s) +{ +std::wstring::size_type i; + + if( s.empty() ) + return; + + // looking for white characters at the end + for(i=s.size()-1 ; i>0 && IsWhite(s[i]) ; --i); + + if( i==0 && IsWhite(s[i]) ) + { + // the whole string has white characters + s.clear(); + return; + } + + // deleting white characters at the end + if( i != s.size() - 1 ) + s.erase(i+1, std::wstring::npos); + + // looking for white characters at the beginning + for(i=0 ; itable.find(var); + + if( i != space->table.end() ) + space->table.erase(i); +} + + + +void JSONToSpaceParser::DeleteFromTableSingle(const std::wstring & var) +{ + Space::TableSingle::iterator i = space->table_single.find(var); + + if( i != space->table_single.end() ) + space->table_single.erase(i); +} + + + + +void JSONToSpaceParser::ReadTokenQuoted() +{ + ReadChar(); // skipping the first quotation mark + + while( lastc != -1 && (char_was_escaped || lastc != '"') ) + { + token += static_cast(lastc); + ReadChar(); + } + + if( !char_was_escaped && lastc == '"' ) + ReadChar(); // skipping the last quotation mark + else + status = syntax_error; +} + + +void JSONToSpaceParser::ReadTokenSingle(bool white_delimit, bool new_line_delimit, int delimit1, int delimit2) +{ + while( true ) + { + if( lastc == -1 || + (!char_was_escaped && + ( + lastc == space_end || + lastc == table_end || + (white_delimit && IsWhite(lastc)) || + (new_line_delimit && lastc == '\n') || + (delimit1 != -1 && lastc == delimit1) || + (delimit2 != -1 && lastc == delimit2) + ) ) ) + + { + break; + } + + token += static_cast(lastc); + ReadChar(); + } + + Trim(token); +} + + +void JSONToSpaceParser::ReadToken(bool white_delimit, bool new_line_delimit, int delimit1, int delimit2) +{ + token.clear(); + SkipWhite(); + + if( !char_was_escaped && lastc == '"' ) + ReadTokenQuoted(); + else + ReadTokenSingle(white_delimit, new_line_delimit, delimit1, delimit2); +} + + +void JSONToSpaceParser::ReadKey() +{ + SkipWhite(); + ReadToken(false, true, separator, table_start); + key = token; +} + + +void JSONToSpaceParser::SkipText() +{ + ReadChar(); // skipping the first quote character '"' + + while( lastc != '"' && lastc != -1 ) + ReadChar(); +} + + +void JSONToSpaceParser::SkipObjectOrTable(int start_char, int end_char) +{ +int mark = 1; + + skipped += 1; + ReadChar(); // skipping the first object character '{' or '[' + + do + { + if( lastc == '"' ) + SkipText(); + else + if( lastc == end_char ) + mark -= 1; + else + if( lastc == start_char ) + mark += 1; + + ReadChar(); + } + while( mark > 0 && lastc != -1 ); +} + + +void JSONToSpaceParser::SkipObject() +{ + SkipObjectOrTable(space_start, space_end); +} + + +void JSONToSpaceParser::SkipTable() +{ + SkipObjectOrTable(table_start, table_end); +} + + + +//void JSONToSpaceParser::ReadValue(bool add_space_for_single_value, bool auto_add_single_value, bool has_space_name) +void JSONToSpaceParser::ReadValue(bool skip_object_or_table, + bool add_space_for_text_value, + bool has_key, + bool auto_add_text_value) +{ + SkipWhite(); + + if( lastc == space_start ) + { + if( skip_object_or_table ) + SkipObject(); + else + ParseSpace(has_key); + } + else + if( lastc == table_start ) + { + if( skip_object_or_table ) + SkipTable(); + else + ParseTable(has_key); + } + else + { + if( add_space_for_text_value ) + { + SpaceStarts(false, false); + ReadToken(false, true, option_delimiter, -1); + space->name = token; + SpaceEnds(false); + } + else + { + ReadToken(false, true, option_delimiter, -1); + value.push_back(token); + + if( auto_add_text_value ) + AddKeyValuePair(); + } + } +} + + +void JSONToSpaceParser::AddKeyValuePair() +{ + if( value.empty() && skip_empty ) + { + DeleteFromTable(key); + DeleteFromTableSingle(key); + return; + } + + if( split_single && value.size() == 1 ) + { + space->table_single[key] = value[0]; + DeleteFromTable(key); + } + else + { + space->table[key] = value; + DeleteFromTableSingle(key); + } +} + + + + + + +int JSONToSpaceParser::ReadUTF8Char() +{ +int c; +bool correct; + + lastc = -1; + + do + { + PT::UTF8ToInt(file, c, correct); + + if( !file ) + return lastc; + } + while( !correct ); + + lastc = c; + + if( lastc == '\n' ) + ++line; + +return lastc; +} + + + +int JSONToSpaceParser::ReadASCIIChar() +{ + lastc = file.get(); + + if( lastc == '\n' ) + ++line; + +return lastc; +} + + + + +int JSONToSpaceParser::ReadCharFromWcharString() +{ + if( *pchar_unicode == 0 ) + lastc = -1; + else + lastc = *(pchar_unicode++); + + if( lastc == '\n' ) + ++line; + +return lastc; +} + + +int JSONToSpaceParser::ReadCharFromUTF8String() +{ +int c; +bool correct; + + lastc = -1; + + do + { + size_t len = PT::UTF8ToInt(pchar_ascii, c, correct); + pchar_ascii += len; + + if( *pchar_ascii == 0 ) + return lastc; + } + while( !correct ); + + lastc = c; + + if( lastc == '\n' ) + ++line; + +return lastc; + +} + + +int JSONToSpaceParser::ReadCharFromAsciiString() +{ + if( *pchar_ascii == 0 ) + lastc = -1; + else + lastc = *(pchar_ascii++); + + if( lastc == '\n' ) + ++line; + +return lastc; +} + + +int JSONToSpaceParser::ReadCharNoEscape() +{ + if( reading_from_file ) + { + if( input_as_utf8 ) + return ReadUTF8Char(); + else + return ReadASCIIChar(); + } + else + { + if( reading_from_wchar_string ) + { + return ReadCharFromWcharString(); + } + else + { + if( input_as_utf8 ) + return ReadCharFromUTF8String(); + else + return ReadCharFromAsciiString(); + } + } +} + +bool JSONToSpaceParser::IsHexDigit(wchar_t c) +{ + return ((c>='0' && c<='9') || + (c>='a' && c<='f') || + (c>='A' && c<='F') ); +} + + +int JSONToSpaceParser::HexToInt(wchar_t c) +{ + if( c>='0' && c<='9' ) + return c - '0'; + + if( c>='a' && c<='f' ) + return c - 'a' + 10; + + if( c>='A' && c<='F' ) + return c - 'A' + 10; + +return 0; +} + + +void JSONToSpaceParser::ReadUnicodeCodePoint() +{ +wchar_t c; +int value = 0; + + for(int i=0 ; i<4 ; ++i) + { + c = ReadCharNoEscape(); + + if( !IsHexDigit(c) ) + { + status = syntax_error; + return; + } + + value = (value << 4) | HexToInt(c); + } + + lastc = (wchar_t)value; +} + + +int JSONToSpaceParser::ReadChar() +{ + char_was_escaped = false; + ReadCharNoEscape(); + + if( use_escape_char && lastc == '\\' ) + { + char_was_escaped = true; + ReadCharNoEscape(); + + switch(lastc) + { + case '0': lastc = 0; break; + case 't': lastc = '\t'; break; + case 'r': lastc = '\r'; break; + case 'n': lastc = '\n'; break; + case 'b': lastc = 0x08; break; + case 'f': lastc = 0x0c; break; + case 'u': ReadUnicodeCodePoint(); break; + // in other cases we return the last character + } + } + +return lastc; +} + + + +} // namespace + + + + diff --git a/space/jsontospaceparser.h b/space/jsontospaceparser.h new file mode 100644 index 0000000..c75b530 --- /dev/null +++ b/space/jsontospaceparser.h @@ -0,0 +1,380 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2012, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef headerfile_picotools_space_jsonspaceparser +#define headerfile_picotools_space_jsonspaceparser + +#include +#include "space.h" + + + +namespace PT +{ + + + +class JSONToSpaceParser +{ +public: + + + /* + ctor -- setting default values (SetDefault() method) + */ + JSONToSpaceParser(); + + + /* + setting the root space + */ + void SetSpace(Space * pspace); + void SetSpace(Space & pspace); + + + /* + setting options of the parser to the default values + utf8, split single etc. + */ + void SetDefault(); + + + /* + status of parsing + */ + enum Status { ok, cant_open_file, syntax_error, max_nested_spaces_exceeded, no_space }; + + + /* + the last status of parsing, set by Parse() methods + */ + Status status; + + + /* + a number of a line in which there is a syntax_error + */ + int line; + + + /* + how many objects were skipped + used in parsing tables when create_table_as_space is false + */ + size_t skipped; + + + /* + main methods used to parse + file_name is the path to a file + */ + Status Parse(const char * file_name); + Status Parse(const std::string & file_name); + Status Parse(const wchar_t * file_name); + Status Parse(const std::wstring & file_name); + + + /* + main methods used to parse + str - input string (either 8bit ascii or UTF-8 -- see UTF8() method) + */ + Status ParseString(const char * str); + Status ParseString(const std::string & str); + + + /* + main methods used to parse + here input string is always in unicode (wide characters) + */ + Status ParseString(const wchar_t * str); + Status ParseString(const std::wstring & str); + + + /* + if your list consists of only one item, e.g: + option1 = value 1 + option2 = "value 2" + option3 = ( "value 3" ) + then if you call SplitSingle(true) then such values will be stored in + 'table_single' instead of 'table' map + default: false + */ + void SplitSingle(bool split); + + + /* + if true then empty values and lists, e.g: + option = + option2 = () + will be omitted (not inserted to 'table' or 'table_single') + default: false + */ + void SkipEmpty(bool skip); + + + /* + '\' character is used to escape other characters in a quoted string + so "some \t t\"ext" will produce "some t t"ext" + default: true + */ + void UseEscapeChar(bool escape); + + + /* + if true then the input file or string (char* or std::string) is treated as UTF-8 + */ + void UTF8(bool utf); + + + /* + + default: true + */ + void CreateTableAsSpace(bool create_table_as_space_); + +private: + + + /* + current space set by SetSpace(); + */ + Space * root_space; + + + /* + a space in which we are now + */ + Space * space; + + + /* + true if Parse() method was called + false if ParseString() was called + */ + bool reading_from_file; + + + /* + pointers to the current character + if ParseString() is in used + */ + const char * pchar_ascii; + const wchar_t * pchar_unicode; + + + /* + true if ParseString(wchar_t *) or ParseString(std::wstring&) was called + */ + bool reading_from_wchar_string; + + + /* + last read token + */ + std::wstring token; + + + /* + last read key + */ + std::wstring key; + + + /* + last read list + */ + Space::Value value; + + + /* + separator between a variable and a value, default: '=' + */ + int separator; + + + /* + space starting character, default: '{' + */ + int space_start; + + + /* + space ending character, default: '}' + */ + int space_end; + + + /* + table starting character, default: '[' + */ + int table_start; + + + /* + table ending character, default: ']' + */ + int table_end; + + + /* + option delimiter, default: ',' + */ + int option_delimiter; + + + /* + last read char + or -1 if the end + */ + int lastc; + + + /* + true if the lastc was escaped (with a backslash) + we have to know if the last sequence was \" or just " + */ + bool char_was_escaped; + + + /* + current file + */ + std::ifstream file; + + + /* + if true then lists with one item will be put into 'table_single' table + default: false + */ + bool split_single; + + + /* + if true then empty lists, e.g: + option = + option2 = () + will be omitted (not inserted to 'table' or 'table_single') + default: false + */ + bool skip_empty; + + + /* + input file is in UTF-8 + default: true + */ + bool input_as_utf8; + + + /* + if true you can use an escape character '\' in quoted values + */ + bool use_escape_char; + + + /* + if false we only allow the tables to consists of text items (numeric, boolean too) + objects are not allowed then + default: true + */ + bool create_table_as_space; + + + /* + + */ + size_t current_nested_level; + + + /* + + default: 1000; + */ + size_t max_nested_level; + + + std::string afile_name; + + void Parse(); + void ParseSpace(bool has_space_name, bool insert_new_space = true); + void ParseTextTable(); + void ParseObjectsTable(bool has_key); + void ParseTable(bool has_key); + void ParseKeyValuePairs(); + + void SkipText(); + void SkipObjectOrTable(int start_char, int end_char); + void SkipTable(); + void SkipObject(); + + void SpaceEnds(bool skip_space_char = true); + void SpaceStarts(bool has_space_name, bool skip_space_char = true); + + void DeleteFromTable(const std::wstring & var); + void DeleteFromTableSingle(const std::wstring & var); + + void ReadTokenQuoted(); + void ReadTokenSingle(bool white_delimit, bool new_line_delimit, int delimit1, int delimit2); + void ReadToken(bool white_delimit, bool new_line_delimit, int delimit1, int delimit2); + void ReadKey(); + void ReadValue(bool skip_object_or_table = false, + bool add_space_for_text_value = false, + bool has_key = false, + bool auto_add_text_value = false); + + void AddKeyValuePair(); + int ReadUTF8Char(); + int ReadASCIIChar(); + int ReadCharFromWcharString(); + int ReadCharFromUTF8String(); + int ReadCharFromAsciiString(); + int ReadCharNoEscape(); + int ReadChar(); + bool IsWhite(int c); + void SkipWhite(); + void Trim(std::wstring & s); + bool IsHexDigit(wchar_t c); + int HexToInt(wchar_t c); + void ReadUnicodeCodePoint(); + +}; + + +} // namespace + + +#endif diff --git a/space/space.h b/space/space.h index 62794f7..c4f8ade 100755 --- a/space/space.h +++ b/space/space.h @@ -35,8 +35,8 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef headerfile_picotools_confparser_space -#define headerfile_picotools_confparser_space +#ifndef headerfile_picotools_space_space +#define headerfile_picotools_space_space #include #include diff --git a/space/spaceparser.cpp b/space/spaceparser.cpp index 5119607..fa24164 100755 --- a/space/spaceparser.cpp +++ b/space/spaceparser.cpp @@ -212,6 +212,10 @@ void SpaceParser::Parse() // last closing ')' characters are missing (closing a space) status = syntax_error; } + + token.clear(); + key.clear(); + value.clear(); } @@ -498,7 +502,7 @@ void SpaceParser::ReadValue() value.clear(); SkipWhite(); - if( lastc == '(' ) + if( lastc == list_start ) ReadValueList(); else ReadValueSingle(); diff --git a/space/spaceparser.h b/space/spaceparser.h index 7fab9fb..df6633c 100755 --- a/space/spaceparser.h +++ b/space/spaceparser.h @@ -35,8 +35,8 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef headerfile_picotools_confparser_confparser -#define headerfile_picotools_confparser_confparser +#ifndef headerfile_picotools_confparser_spaceparser +#define headerfile_picotools_confparser_spaceparser #include #include "space.h" @@ -276,7 +276,7 @@ private: /* input file is in UTF-8 - default: false + default: true */ bool input_as_utf8; diff --git a/space/spacetojson.cpp b/space/spacetojson.cpp new file mode 100644 index 0000000..657e4d9 --- /dev/null +++ b/space/spacetojson.cpp @@ -0,0 +1,61 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2012, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spacetojson.h" + + +namespace PT +{ + + + +bool SpaceToJSON::HasUnnamedSpace(Space & space) const +{ + for(size_t i=0 ; iname.empty() ) + return true; + +return false; +} + + + + + + +} // namespace + diff --git a/space/spacetojson.h b/space/spacetojson.h new file mode 100644 index 0000000..9890dc5 --- /dev/null +++ b/space/spacetojson.h @@ -0,0 +1,231 @@ +/* + * This file is a part of PikoTools + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2012, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef headerfile_picotools_space_spacetojson +#define headerfile_picotools_space_spacetojson + +#include "space.h" + + +namespace PT +{ + + +class SpaceToJSON +{ +public: + + + template + void Serialize(Space & space, Stream & out, bool use_indents = false, int level = 0) const; + + template + void SerializeTableSingle(Space & space, Stream & out, bool use_indents, int level) const; + + template + void SerializeTableMulti(Space & space, Stream & out, bool use_indents, int level) const; + + template + static void PrintToken(Stream & out, const StringType & str); + + template + static void PrintLevel(Stream & out, bool use_indents, int level); + +private: + + bool HasUnnamedSpace(Space & space) const; + +}; + + + + +template +void SpaceToJSON::PrintLevel(Stream & out, bool use_indents, int level) +{ + if( use_indents ) + { + for(int i=0 ; i +void SpaceToJSON::PrintToken(Stream & out, const StringType & str) +{ + out << '\"'; + + for(size_t i=0 ; i +void SpaceToJSON::SerializeTableSingle(Space & space, Stream & out, bool use_indents, int level) const +{ +Space::TableSingle::const_iterator i; +size_t index = 0; + + for(i=space.table_single.begin() ; i != space.table_single.end() ; ++i, ++index) + { + PrintLevel(out, use_indents, level); + PrintToken(out, i->first); + out << L": "; + PrintToken(out, i->second); + + if( index + 1 < space.table_single.size() || !space.table.empty() ) + out << ','; + + out << '\n'; + } +} + + + +template +void SpaceToJSON::SerializeTableMulti(Space & space, Stream & out, bool use_indents, int level) const +{ +Space::Table::const_iterator i2; +size_t v; +size_t index = 0; + + for(i2 = space.table.begin() ; i2 != space.table.end() ; ++i2, ++index) + { + PrintLevel(out, use_indents, level); + PrintToken(out, i2->first); + out << L": "; + + if( i2->second.size() != 1 ) + out << '['; + + for(v = 0 ; v < i2->second.size() ; ++v) + { + if( v > 0 ) + PrintLevel(out, use_indents, level + i2->first.size() + 3); + + PrintToken(out, i2->second[v]); + + if( v + 1 < i2->second.size() ) + out << L",\n"; + } + + if( i2->second.size() != 1 ) + out << ']'; + + if( index + 1 < space.table.size() || !space.spaces.empty() ) + out << ','; + + out << '\n'; + } +} + + + + +template +void SpaceToJSON::Serialize(Space & space, Stream & out, bool use_indents, int level) const +{ +// if( level > 0 ) +// out << '\n'; + + PrintLevel(out, use_indents, level); + + if( !space.name.empty() ) + { + PrintToken(out, space.name); + out << L": "; + } + + bool is_table = HasUnnamedSpace(space); + + if( is_table ) + out << L"[\n"; + else + out << L"{\n"; + + // !! what about if table or table.single has values + // and there is the table? (not supported yet) + + SerializeTableSingle(space, out, use_indents, level); + SerializeTableMulti(space, out, use_indents, level); + + for(size_t i=0 ; i