You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1335 lines
35 KiB
1335 lines
35 KiB
/* |
|
* This file is a part of PikoTools |
|
* and is distributed under the (new) BSD licence. |
|
* Author: Tomasz Sowa <t.sowa@ttmath.org> |
|
*/ |
|
|
|
/* |
|
* Copyright (c) 2010-2021, 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_space |
|
#define headerfile_picotools_space_space |
|
|
|
#include <string> |
|
#include <list> |
|
#include <vector> |
|
#include <map> |
|
#include <cstdio> |
|
#include <cwchar> |
|
#include "textstream/types.h" |
|
#include "convert/inttostr.h" |
|
#include <errno.h> |
|
|
|
|
|
|
|
namespace pt |
|
{ |
|
|
|
|
|
|
|
/* |
|
|
|
Simple form: |
|
key = value |
|
|
|
If value is equal to 'null' then the internal representation is equal to Type::type_null, e.g: |
|
key = null |
|
|
|
If value is either 'false' or 'true' then the internal representation is Type::type_bool, e.g: |
|
key = false |
|
key = true |
|
|
|
If value is an integer number and not an overflow has occured while parsing then type of the value |
|
is Type::type_long (type is 'long long' internally): |
|
key = 1000 |
|
|
|
If value is a floating point number then type is Type::type_double (type is 'double' internally): |
|
key = 123.45 |
|
key = 123.45e+10 |
|
|
|
In other cases value has Type::type_wstring type. |
|
|
|
The form with quotation marks: |
|
key = "value" |
|
In such a case value has Type::type_wstring type and can be multiline e.g: |
|
key = "multiline |
|
value" |
|
In this form you can have spaces around value, e.g.: |
|
key = " value with spaces " |
|
|
|
|
|
The value can be a list: |
|
key = (value1,value2) |
|
or the same written with spaces around: |
|
key = ( value1 , value2 ) |
|
or written in multiline fashion: |
|
key = ( |
|
value1, |
|
value2, |
|
) |
|
a colon after value2 is optional. |
|
|
|
List can be written with quotation marks too: |
|
key = ( |
|
"value1", |
|
"value2", |
|
"value3 |
|
with a new line character inside", |
|
) |
|
|
|
List without value: |
|
key = () |
|
is equal to simple form without value, e.g.: |
|
key = |
|
|
|
|
|
|
|
Difference between a simple form and a list is when parsing the colon, in simple form the colon is a part of the value, e.g.: |
|
key = value with , a colon inside |
|
this is equal to: |
|
key = "value with , a colon inside" |
|
|
|
and in a form of a list it would have two values: |
|
key = (value with , a colon inside) |
|
would be equal to: |
|
key = ("value with" , "a colon inside") |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
class Space |
|
{ |
|
public: |
|
|
|
typedef std::map<std::wstring, Space*> ObjectType; |
|
typedef std::vector<Space*> TableType; |
|
|
|
enum Escape |
|
{ |
|
no_escape, |
|
escape_space, |
|
escape_json, |
|
}; |
|
|
|
enum Type |
|
{ |
|
type_null, |
|
type_bool, |
|
type_long, |
|
type_float, |
|
type_double, |
|
type_string, |
|
type_wstring, |
|
type_object, |
|
type_table, |
|
}; |
|
|
|
union Value |
|
{ |
|
bool value_bool; |
|
long long value_long; |
|
float value_float; |
|
double value_double; |
|
std::string value_string; |
|
std::wstring value_wstring; |
|
ObjectType value_object; |
|
TableType value_table; |
|
|
|
Value() |
|
{ |
|
} |
|
|
|
~Value() |
|
{ |
|
} |
|
}; |
|
|
|
|
|
Type type; |
|
Value value; |
|
|
|
std::wstring * name; |
|
TableType * child_spaces; |
|
|
|
|
|
|
|
Space(); |
|
Space(const Space & space); |
|
Space(Space && space); |
|
Space & operator=(const Space & space); |
|
Space & operator=(Space && space); |
|
~Space(); |
|
|
|
Space(bool val); |
|
Space(short val); |
|
Space(int val); |
|
Space(long val); |
|
Space(long long val); |
|
Space(unsigned short val); |
|
Space(unsigned int val); |
|
Space(unsigned long val); |
|
Space(unsigned long long val); |
|
Space(float val); |
|
Space(double val); |
|
Space(const char * str); |
|
Space(const wchar_t * str); |
|
Space(const std::string & str); |
|
Space(const std::wstring & str); |
|
Space(const Space * space); |
|
|
|
|
|
void clear(); |
|
|
|
// set a new value |
|
void set_null(); |
|
void set_empty_string(); |
|
void set_empty_wstring(); |
|
void set_empty_table(); |
|
void set_empty_object(); |
|
|
|
void set(bool val); |
|
void set(short val); |
|
void set(int val); |
|
void set(long val); |
|
void set(long long val); |
|
void set(unsigned short val); |
|
void set(unsigned int val); |
|
void set(unsigned long val); |
|
void set(unsigned long long val); |
|
void set(float val); |
|
void set(double val); |
|
void set(const char * str); |
|
void set(const wchar_t * str); |
|
void set(const std::string & str); |
|
void set(const std::wstring & str); |
|
void set(const Space & space); |
|
void set(const Space * space); |
|
void set(Space && space); |
|
|
|
|
|
// add a value to the table, change to table if needed, return the reference to the new inserted item |
|
Space & add(bool val); |
|
Space & add(short val); |
|
Space & add(int val); |
|
Space & add(long val); |
|
Space & add(long long val); |
|
Space & add(unsigned short val); |
|
Space & add(unsigned int val); |
|
Space & add(unsigned long val); |
|
Space & add(unsigned long long val); |
|
Space & add(float val); |
|
Space & add(double val); |
|
Space & add(const char * val); |
|
Space & add(const wchar_t * val); |
|
Space & add(const std::string & val); |
|
Space & add(const std::wstring & val); |
|
Space & add(const Space & space); |
|
Space & add(const Space * space); |
|
Space & add(Space && space); |
|
Space & add_empty_space(); // IMPROVEME rename me to something better |
|
|
|
|
|
|
|
// add a value to the object, change to object if needed, return the reference to the new inserted item |
|
Space & add(const wchar_t * field, bool val); |
|
Space & add(const wchar_t * field, short val); |
|
Space & add(const wchar_t * field, int val); |
|
Space & add(const wchar_t * field, long val); |
|
Space & add(const wchar_t * field, long long val); |
|
Space & add(const wchar_t * field, unsigned short val); |
|
Space & add(const wchar_t * field, unsigned int val); |
|
Space & add(const wchar_t * field, unsigned long val); |
|
Space & add(const wchar_t * field, unsigned long long val); |
|
Space & add(const wchar_t * field, float val); |
|
Space & add(const wchar_t * field, double val); |
|
Space & add(const wchar_t * field, const char * val); |
|
Space & add(const wchar_t * field, const wchar_t * val); |
|
Space & add(const wchar_t * field, const std::string & val); |
|
Space & add(const wchar_t * field, const std::wstring & val); |
|
Space & add(const wchar_t * field, const Space & space); |
|
Space & add(const wchar_t * field, const Space * space); |
|
Space & add(const wchar_t * field, Space && space); |
|
Space & add_empty_space(const wchar_t * field); // IMPROVEME rename me to something better |
|
|
|
Space & add(const std::wstring & field, bool val); |
|
Space & add(const std::wstring & field, short val); |
|
Space & add(const std::wstring & field, int val); |
|
Space & add(const std::wstring & field, long val); |
|
Space & add(const std::wstring & field, long long val); |
|
Space & add(const std::wstring & field, unsigned short val); |
|
Space & add(const std::wstring & field, unsigned int val); |
|
Space & add(const std::wstring & field, unsigned long val); |
|
Space & add(const std::wstring & field, unsigned long long val); |
|
Space & add(const std::wstring & field, float val); |
|
Space & add(const std::wstring & field, double val); |
|
Space & add(const std::wstring & field, const char * val); |
|
Space & add(const std::wstring & field, const wchar_t * val); |
|
Space & add(const std::wstring & field, const std::string & val); |
|
Space & add(const std::wstring & field, const std::wstring & val); |
|
Space & add(const std::wstring & field, const Space & space); |
|
Space & add(const std::wstring & field, const Space * space); |
|
Space & add(const std::wstring & field, Space && space); |
|
Space & add_empty_space(const std::wstring & field); // IMPROVEME rename me to something better |
|
|
|
|
|
// IMPROVEME add a similar 'set' method and cctor |
|
template<typename StreamType> |
|
Space & add_stream(const wchar_t * field, StreamType & str) |
|
{ |
|
std::wstring temp; |
|
str.to_string(temp); |
|
|
|
return add(field, temp); |
|
} |
|
|
|
template<typename StreamType> |
|
Space & add_stream(const std::wstring & field, StreamType & str) |
|
{ |
|
std::wstring temp; |
|
str.to_string(temp); |
|
|
|
return add(field, temp); |
|
} |
|
|
|
|
|
|
|
bool is_null() const; |
|
bool is_bool() const; |
|
bool is_llong() const; |
|
bool is_long_long() const; |
|
bool is_float() const; |
|
bool is_double() const; |
|
bool is_numeric() const; |
|
bool is_str() const; |
|
bool is_wstr() const; |
|
bool is_text() const; |
|
bool is_object() const; |
|
bool is_table() const; |
|
|
|
|
|
|
|
bool to_bool() const; |
|
short to_short() const; |
|
int to_int() const; |
|
long to_long() const; |
|
long long to_llong() const; |
|
long long to_long_long() const; |
|
unsigned short to_ushort() const; |
|
unsigned int to_uint() const; |
|
unsigned long to_ulong() const; |
|
unsigned long long to_ullong() const; |
|
unsigned long long to_ulong_long() const; |
|
std::string to_str() const; |
|
std::wstring to_wstr() const; |
|
|
|
void to_list(std::list<std::string> & output_list, bool clear_list = true) const; |
|
void to_list(std::list<std::wstring> & output_list, bool clear_list = true) const; |
|
void to_list(std::vector<std::string> & output_list, bool clear_list = true) const; |
|
void to_list(std::vector<std::wstring> & output_list, bool clear_list = true) const; |
|
|
|
|
|
// returns value from object, field is a key |
|
bool to_bool(const wchar_t * field, bool default_value = false) const; |
|
short to_short(const wchar_t * field, short default_value = 0) const; |
|
int to_int(const wchar_t * field, int default_value = 0) const; |
|
long to_long(const wchar_t * field, long default_value = 0) const; |
|
long long to_llong(const wchar_t * field, long long default_value = 0) const; |
|
long long to_long_long(const wchar_t * field, long long default_value = 0) const; |
|
unsigned short to_ushort(const wchar_t * field, unsigned short default_value = 0) const; |
|
unsigned int to_uint(const wchar_t * field, unsigned int default_value = 0) const; |
|
unsigned long to_ulong(const wchar_t * field, unsigned long default_value = 0) const; |
|
unsigned long long to_ullong(const wchar_t * field, unsigned long long default_value = 0) const; |
|
unsigned long long to_ulong_long(const wchar_t * field, unsigned long long default_value = 0) const; |
|
std::string to_str(const wchar_t * field, const char * default_value = nullptr) const; |
|
std::string to_str(const wchar_t * field, const std::string & default_value) const; |
|
std::wstring to_wstr(const wchar_t * field, const wchar_t * default_value = nullptr) const; |
|
std::wstring to_wstr(const wchar_t * field, const std::wstring & default_value) const; |
|
|
|
bool to_list(const wchar_t * field, std::list<std::string> & output_list, bool clear_list = true) const; |
|
bool to_list(const wchar_t * field, std::list<std::wstring> & output_list, bool clear_list = true) const; |
|
bool to_list(const std::wstring & field, std::list<std::string> & output_list, bool clear_list = true) const; |
|
bool to_list(const std::wstring & field, std::list<std::wstring> & output_list, bool clear_list = true) const; |
|
|
|
bool to_list(const wchar_t * field, std::vector<std::string> & output_list, bool clear_list = true) const; |
|
bool to_list(const wchar_t * field, std::vector<std::wstring> & output_list, bool clear_list = true) const; |
|
bool to_list(const std::wstring & field, std::vector<std::string> & output_list, bool clear_list = true) const; |
|
bool to_list(const std::wstring & field, std::vector<std::wstring> & output_list, bool clear_list = true) const; |
|
|
|
// returns value from object, field is a key |
|
bool to_bool(const std::wstring & field, bool default_value = false) const; |
|
short to_short(const std::wstring & field, short default_value = 0) const; |
|
int to_int(const std::wstring & field, int default_value = 0) const; |
|
long to_long(const std::wstring & field, long default_value = 0) const; |
|
long long to_llong(const std::wstring & field, long long default_value = 0) const; |
|
long long to_long_long(const std::wstring & field, long long default_value = 0) const; |
|
unsigned short to_ushort(const std::wstring & field, unsigned short default_value = 0) const; |
|
unsigned int to_uint(const std::wstring & field, unsigned int default_value = 0) const; |
|
unsigned long to_ulong(const std::wstring & field, unsigned long default_value = 0) const; |
|
unsigned long long to_ullong(const std::wstring & field, unsigned long long default_value = 0) const; |
|
unsigned long long to_ulong_long(const std::wstring & field, unsigned long long default_value = 0) const; |
|
std::string to_str(const std::wstring & field, const char * default_value = nullptr) const; |
|
std::string to_str(const std::wstring & field, const std::string & default_value) const; |
|
std::wstring to_wstr(const std::wstring & field, const wchar_t * default_value = nullptr) const; |
|
std::wstring to_wstr(const std::wstring & field, const std::wstring & default_value) const; |
|
|
|
|
|
bool to_str_list(std::list<std::string> & output_list) const; |
|
bool to_wstr_list(std::list<std::wstring> & output_list) const; |
|
|
|
|
|
bool * get_bool(); |
|
long long * get_llong(); |
|
long long * get_long_long(); |
|
float * get_float(); |
|
double * get_double(); |
|
std::string * get_str(); |
|
std::wstring * get_wstr(); |
|
ObjectType * get_object(); |
|
TableType * get_table(); |
|
|
|
// may a better name? |
|
bool is_equal(const char * val) const; |
|
bool is_equal(const std::string & val) const; |
|
bool is_equal(const wchar_t * val) const; |
|
bool is_equal(const std::wstring & val) const; |
|
|
|
// may a better name? |
|
bool has_value(const char * val) const; |
|
bool has_value(const std::string & val) const; |
|
bool has_value(const wchar_t * val) const; |
|
bool has_value(const std::wstring & val) const; |
|
|
|
|
|
// what about getters from tables? |
|
// may something like: Space * get_table_item(size_t index)? |
|
// and get_table_bool(size_t index) |
|
// or just only get_bool(size_t index)? |
|
// size_t argument will be only for tables, wchar_t* or std::wstring for objects? |
|
|
|
// getters from object |
|
Space * get_object_field(const wchar_t * field); // may a better name? |
|
const Space * get_object_field(const wchar_t * field) const; // may a better name? |
|
Space * get_object_field(const std::wstring & field); |
|
const Space * get_object_field(const std::wstring & field) const; // may a better name? |
|
|
|
|
|
bool * get_bool(const wchar_t * field); |
|
long long * get_llong(const wchar_t * field); |
|
long long * get_long_long(const wchar_t * field); |
|
float * get_float(const wchar_t * field); |
|
double * get_double(const wchar_t * field); |
|
std::string * get_str(const wchar_t * field); |
|
std::wstring * get_wstr(const wchar_t * field); |
|
ObjectType * get_object(const wchar_t * field); |
|
TableType * get_table(const wchar_t * field); |
|
// add these getters with std::wstring |
|
|
|
|
|
const bool * get_bool() const; |
|
const long long * get_llong() const; |
|
const long long * get_long_long() const; |
|
const float * get_float() const; |
|
const double * get_double() const; |
|
const std::string * get_str() const; |
|
const std::wstring * get_wstr() const; |
|
const ObjectType * get_object() const; |
|
const TableType * get_table() const; |
|
|
|
bool has_key(const wchar_t * field) const; // may has_key() would be a better name? |
|
bool has_key(const std::wstring & field) const; |
|
|
|
|
|
const bool * get_bool(const wchar_t * field) const; |
|
const long long * get_llong(const wchar_t * field) const; |
|
const long long * get_long_long(const wchar_t * field) const; |
|
const float * get_float(const wchar_t * field) const; |
|
const double * get_double(const wchar_t * field) const; |
|
const std::string * get_str(const wchar_t * field) const; |
|
const std::wstring * get_wstr(const wchar_t * field) const; |
|
const ObjectType * get_object(const wchar_t * field) const; |
|
const TableType * get_table(const wchar_t * field) const; |
|
// add these getters with std::wstring |
|
|
|
|
|
// no case, has O(n) complexity |
|
Space * get_object_field_nc(const wchar_t * field); |
|
Space * get_object_field_nc(const std::wstring & field); |
|
const Space * get_object_field_nc(const wchar_t * field) const; |
|
const Space * get_object_field_nc(const std::wstring & field) const; |
|
|
|
|
|
|
|
// remove a field from an object |
|
void remove(const wchar_t * field); |
|
void remove(const std::wstring & field); |
|
|
|
|
|
std::string serialize_to_space_str(bool pretty_print = false) const; |
|
std::wstring serialize_to_space_wstr(bool pretty_print = false) const; |
|
void serialize_to_space_to(std::string & str, bool pretty_print = false) const; |
|
void serialize_to_space_to(std::wstring & str, bool pretty_print = false) const; |
|
|
|
template<typename StreamType> |
|
void serialize_to_space_stream(StreamType & str, bool pretty_print = false) const |
|
{ |
|
if( is_object() ) |
|
{ |
|
serialize_to_space_stream(str, pretty_print, 0, true); |
|
} |
|
} |
|
|
|
|
|
|
|
std::string serialize_to_json_str() const; |
|
std::wstring serialize_to_json_wstr() const; |
|
void serialize_to_json_to(std::string & str) const; |
|
void serialize_to_json_to(std::wstring & str) const; |
|
|
|
|
|
template<typename StreamType> |
|
void serialize_to_json_stream(StreamType & str, bool pretty_print = false) const |
|
{ |
|
switch(type) |
|
{ |
|
case type_null: |
|
serialize_json_null(str); |
|
break; |
|
|
|
case type_bool: |
|
serialize_json_bool(str); |
|
break; |
|
|
|
case type_long: |
|
serialize_json_long(str); |
|
break; |
|
|
|
case type_float: |
|
serialize_json_float(str); |
|
break; |
|
|
|
case type_double: |
|
serialize_json_double(str); |
|
break; |
|
|
|
case type_string: |
|
serialize_json_string(str); |
|
break; |
|
|
|
case type_wstring: |
|
serialize_json_wstring(str); |
|
break; |
|
|
|
case type_object: |
|
serialize_json_object(str); |
|
break; |
|
|
|
case type_table: |
|
serialize_json_table(str); |
|
break; |
|
} |
|
} |
|
|
|
|
|
// add this method with field with std::wstring |
|
bool is_equal(const wchar_t * field, const char * val) const; |
|
bool is_equal(const wchar_t * field, const std::string & val) const; |
|
bool is_equal(const wchar_t * field, const wchar_t * val) const; |
|
bool is_equal(const wchar_t * field, const std::wstring & val) const; |
|
|
|
// may a better name? |
|
// add this method with field with std::wstring |
|
bool has_value(const wchar_t * field, const char * val) const; |
|
bool has_value(const wchar_t * field, const std::string & val) const; |
|
bool has_value(const wchar_t * field, const wchar_t * val) const; |
|
bool has_value(const wchar_t * field, const std::wstring & val) const; |
|
|
|
|
|
// for child spaces (used only in Space format) |
|
Space * find_child_space(const wchar_t * name); |
|
Space * find_child_space(const std::wstring & name); |
|
const Space * find_child_space(const wchar_t * name) const; |
|
const Space * find_child_space(const std::wstring & name) const; |
|
|
|
Space & add_child_space(const wchar_t * space_name); |
|
|
|
Space & find_add_child_space(const wchar_t * name); |
|
Space & find_add_child_space(const std::wstring & name); |
|
|
|
void remove_child_space(const wchar_t * name); |
|
void remove_child_space(const std::wstring & name); |
|
void remove_child_space(size_t index); |
|
|
|
|
|
protected: |
|
|
|
|
|
template<typename ArgType> |
|
Space & add_generic(const ArgType & val) |
|
{ |
|
initialize_value_table_if_needed(); |
|
|
|
Space * new_space = new Space(val); |
|
value.value_table.push_back(new_space); |
|
|
|
return *value.value_table.back(); |
|
} |
|
|
|
|
|
template<typename ArgType> |
|
Space & add_generic(const wchar_t * field, const ArgType & val) |
|
{ |
|
initialize_value_object_if_needed(); |
|
|
|
auto insert_res = value.value_object.insert(std::make_pair(field, nullptr)); |
|
insert_res.first->second = new Space(val); |
|
|
|
return *(insert_res.first->second); |
|
} |
|
|
|
|
|
template<typename ArgType> |
|
Space & add_generic(const std::wstring & field, const ArgType & val) |
|
{ |
|
return add_generic(field.c_str(), val); |
|
} |
|
|
|
|
|
template<typename ArgType> |
|
ArgType to_generic_numeric_signed_value() const |
|
{ |
|
long long val = to_long_long(); |
|
|
|
if( val < std::numeric_limits<ArgType>::min() || val > std::numeric_limits<ArgType>::max() ) |
|
val = 0; |
|
|
|
return val; |
|
} |
|
|
|
template<typename ArgType> |
|
ArgType to_generic_numeric_unsigned_value() const |
|
{ |
|
unsigned long long val = to_ulong_long(); |
|
|
|
if( val > std::numeric_limits<ArgType>::max() ) |
|
val = 0; |
|
|
|
return val; |
|
} |
|
|
|
long long convert_string_to_long_long() const; |
|
long long convert_wstring_to_long_long() const; |
|
|
|
unsigned long long convert_string_to_ulong_long() const; |
|
unsigned long long convert_wstring_to_ulong_long() const; |
|
|
|
|
|
template<typename ListType> |
|
void to_list_str_generic(ListType & output_list, bool clear_list) const |
|
{ |
|
if( clear_list ) |
|
output_list.clear(); |
|
|
|
if( type == type_string ) |
|
{ |
|
output_list.push_back(value.value_string); |
|
} |
|
else |
|
if( type == type_table ) |
|
{ |
|
for(size_t i = 0 ; i < value.value_table.size() ; ++i) |
|
{ |
|
output_list.push_back(value.value_table[i]->to_str()); |
|
} |
|
} |
|
else |
|
{ |
|
output_list.push_back(to_str()); |
|
} |
|
} |
|
|
|
|
|
template<typename ListType> |
|
void to_list_wstr_generic(ListType & output_list, bool clear_list) const |
|
{ |
|
if( clear_list ) |
|
output_list.clear(); |
|
|
|
if( type == type_wstring ) |
|
{ |
|
output_list.push_back(value.value_wstring); |
|
} |
|
else |
|
if( type == type_table ) |
|
{ |
|
for(size_t i = 0 ; i < value.value_table.size() ; ++i) |
|
{ |
|
output_list.push_back(value.value_table[i]->to_wstr()); |
|
} |
|
} |
|
else |
|
{ |
|
output_list.push_back(to_wstr()); |
|
} |
|
} |
|
|
|
template<typename ListType> |
|
bool to_list_generic(const wchar_t * field, ListType & output_list, bool clear_list) const |
|
{ |
|
if( clear_list ) |
|
output_list.clear(); |
|
|
|
const Space * space = get_object_field(field); |
|
|
|
if( space ) |
|
{ |
|
space->to_list(output_list, false); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
template<typename ListType> |
|
bool to_list_generic(const std::wstring & field, ListType & output_list, bool clear_list) const |
|
{ |
|
if( clear_list ) |
|
output_list.clear(); |
|
|
|
const Space * space = get_object_field(field); |
|
|
|
if( space ) |
|
{ |
|
space->to_list(output_list, false); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
template<typename ArgType> |
|
Space * find_child_space_generic(const ArgType & name) |
|
{ |
|
if( child_spaces ) |
|
{ |
|
for(size_t i = 0 ; i < child_spaces->size() ; ++i) |
|
{ |
|
Space * space = (*child_spaces)[i]; |
|
|
|
if( space->name && *space->name == name ) |
|
{ |
|
return space; |
|
} |
|
} |
|
} |
|
|
|
return nullptr; |
|
} |
|
|
|
|
|
template<typename ArgType> |
|
Space * find_child_space_generic(const ArgType & name) const |
|
{ |
|
if( child_spaces ) |
|
{ |
|
for(size_t i = 0 ; i < child_spaces->size() ; ++i) |
|
{ |
|
Space * space = (*child_spaces)[i]; |
|
|
|
if( space->name && *space->name == name ) |
|
{ |
|
return space; |
|
} |
|
} |
|
} |
|
|
|
return nullptr; |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void escape_to_space_format(int c, StreamType & out) const |
|
{ |
|
// IMPLEMENT ME |
|
escape_to_json_format(c, out); |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void escape_to_json_format(int c, StreamType & out) const |
|
{ |
|
switch(c) |
|
{ |
|
case 0: out << '\\'; out << '0'; break; |
|
case '\r': out << '\\'; out << 'r'; break; |
|
case '\n': out << '\\'; out << 'n'; break; |
|
case '\\': out << '\\'; out << '\\'; break; |
|
case '"': out << '\\'; out << '\"'; break; |
|
//case '(': out << '\\'; out << '('; break; |
|
//case ')': out << '\\'; out << ')'; break; |
|
//case '=': out << '\\'; out << '='; break; |
|
default: |
|
out << static_cast<typename StreamType::char_type>(c); |
|
} |
|
} |
|
|
|
|
|
|
|
template<typename CharT, typename StreamType> |
|
void copy_input_string_to_output(const CharT * input_str, StreamType & out_str, Escape escape) const |
|
{ |
|
while( *input_str ) |
|
{ |
|
if( escape == Escape::no_escape ) |
|
out_str << static_cast<typename StreamType::char_type>(*input_str); |
|
else |
|
if( escape == Escape::escape_space ) |
|
escape_to_space_format(*input_str, out_str); |
|
else |
|
if( escape == Escape::escape_json ) |
|
escape_to_json_format(*input_str, out_str); |
|
|
|
input_str += 1; |
|
} |
|
} |
|
|
|
template<typename StreamType> |
|
void copy_input_stream_to_output(const StreamType & input_str, StreamType & out_str, Escape escape) const |
|
{ |
|
typename StreamType::const_iterator i = input_str.begin(); |
|
|
|
while( i != input_str.end() ) |
|
{ |
|
if( escape == Escape::no_escape ) |
|
out_str << static_cast<typename StreamType::char_type>(*i); |
|
else |
|
if( escape == Escape::escape_space ) |
|
escape_to_space_format(*i, out_str); |
|
else |
|
if( escape == Escape::escape_json ) |
|
escape_to_json_format(*i, out_str); |
|
|
|
++i; |
|
} |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void serialize_string_buffer(const char * input_str, StreamType & out_str, Escape escape) const |
|
{ |
|
if constexpr ( sizeof(char) == sizeof(typename StreamType::char_type) ) |
|
{ |
|
// input and output are char (we assume it is utf8) |
|
copy_input_string_to_output(input_str, out_str, escape); |
|
} |
|
else |
|
{ |
|
// input is utf8 but output is wide |
|
copy_input_string_to_output(input_str, out_str, escape); // temporarily |
|
|
|
// !!!!!!!!!!!!!!!!!!! FIXME |
|
// StreamType temp_stream; |
|
// UTF8ToWide(input_str, temp_stream, false); |
|
// |
|
// copy_input_stream_to_output(temp_stream, out_str, escape); |
|
} |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void serialize_string_buffer(const wchar_t * input_str, StreamType & out_str, Escape escape) const |
|
{ |
|
if constexpr ( sizeof(wchar_t) == sizeof(typename StreamType::char_type) ) |
|
{ |
|
// input and output are wide characters |
|
copy_input_string_to_output(input_str, out_str, escape); |
|
} |
|
else |
|
{ |
|
StreamType temp_stream; |
|
|
|
// input is wide but output is utf8 |
|
WideToUTF8(input_str, temp_stream, false); |
|
copy_input_stream_to_output(temp_stream, out_str, escape); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
template<typename StreamType> |
|
void serialize_space_null(StreamType & str) const |
|
{ |
|
serialize_string_buffer(L"null", str, Escape::escape_space); |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_space_bool(StreamType & str) const |
|
{ |
|
if( value.value_bool ) |
|
{ |
|
serialize_string_buffer(L"true", str, Escape::escape_space); |
|
} |
|
else |
|
{ |
|
serialize_string_buffer(L"false", str, Escape::escape_space); |
|
} |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void serialize_space_long(StreamType & str) const |
|
{ |
|
wchar_t buffer[50]; |
|
size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); |
|
|
|
Toa(value.value_long, buffer, buffer_len); |
|
serialize_string_buffer(buffer, str, Escape::escape_space); |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_space_float(StreamType & str) const |
|
{ |
|
wchar_t buffer[100]; |
|
size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); |
|
|
|
int chars_written = std::swprintf(buffer, buffer_len, L"%e", static_cast<double>(value.value_float)); |
|
|
|
if( errno == EOVERFLOW || chars_written < 0 ) |
|
buffer[0] = 0; |
|
|
|
serialize_string_buffer(buffer, str, Escape::escape_space); |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_space_double(StreamType & str) const |
|
{ |
|
wchar_t buffer[100]; |
|
size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); |
|
|
|
int chars_written = std::swprintf(buffer, buffer_len, L"%e", value.value_double); |
|
|
|
if( errno == EOVERFLOW || chars_written < 0 ) |
|
buffer[0] = 0; |
|
|
|
serialize_string_buffer(buffer, str, Escape::escape_space); |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_space_string(StreamType & str) const |
|
{ |
|
str << '"'; |
|
serialize_string_buffer(value.value_string.c_str(), str, Escape::escape_space); |
|
str << '"'; |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_space_wstring(StreamType & str) const |
|
{ |
|
str << '"'; |
|
serialize_string_buffer(value.value_wstring.c_str(), str, Escape::escape_space); |
|
str << '"'; |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_space_object(StreamType & str, bool pretty_print, int level, bool is_main_object) const |
|
{ |
|
if( !is_main_object ) |
|
{ |
|
str << '{'; |
|
print_if(pretty_print && (!value.value_object.empty() || (child_spaces && !child_spaces->empty())), str, '\n'); |
|
} |
|
|
|
bool is_first = true; |
|
|
|
for(auto & map_item : value.value_object) |
|
{ |
|
if( !is_first ) |
|
print_if(pretty_print, str, '\n', ','); |
|
|
|
bool quote_field = should_field_be_quoted(map_item.first); |
|
|
|
print_level(pretty_print, level, str); |
|
print_if(quote_field, str, '"'); |
|
serialize_string_buffer(map_item.first.c_str(), str, Escape::escape_space); |
|
print_if(quote_field, str, '"'); |
|
|
|
print_if(pretty_print, str, ' '); |
|
str << '='; |
|
print_if(pretty_print, str, ' '); |
|
|
|
map_item.second->serialize_to_space_stream(str, pretty_print, level + 1, false); |
|
is_first = false; |
|
} |
|
|
|
print_if(!is_first && pretty_print, str, '\n'); |
|
serialize_child_spaces(str, pretty_print, level); |
|
|
|
if( !is_main_object ) |
|
{ |
|
print_level(pretty_print, level - 1, str); |
|
str << '}'; |
|
print_if(pretty_print, str, '\n'); |
|
} |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void serialize_child_spaces(StreamType & str, bool pretty_print, int level) const |
|
{ |
|
if( child_spaces && !child_spaces->empty() ) |
|
{ |
|
print_if(pretty_print, str, '\n'); |
|
|
|
for(Space * child_space : *child_spaces) |
|
{ |
|
print_if(!pretty_print, str, ' '); |
|
|
|
if( child_space->name && !child_space->name->empty() ) |
|
{ |
|
bool quote_field = should_field_be_quoted(*child_space->name); |
|
|
|
print_level(pretty_print, level, str); |
|
print_if(quote_field, str, '"'); |
|
serialize_string_buffer(child_space->name->c_str(), str, Escape::escape_space); |
|
print_if(quote_field, str, '"'); |
|
|
|
str << ' '; |
|
} |
|
|
|
child_space->serialize_to_space_stream(str, pretty_print, level + 1, false); |
|
print_if(pretty_print, str, '\n'); |
|
} |
|
} |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void serialize_space_table(StreamType & str, bool pretty_print, int level) const |
|
{ |
|
bool multivalue_table = false; |
|
bool is_first = true; |
|
|
|
if( value.value_table.size() > 1 ) |
|
{ |
|
multivalue_table = true; |
|
} |
|
|
|
str << '('; |
|
print_if(pretty_print && multivalue_table, str, '\n'); |
|
|
|
for(Space * space : value.value_table) |
|
{ |
|
if( !is_first ) |
|
print_if(pretty_print, str, '\n', ','); |
|
|
|
print_level(pretty_print && multivalue_table, level, str); |
|
space->serialize_to_space_stream(str, pretty_print, level + 1, false); |
|
is_first = false; |
|
} |
|
|
|
print_if(pretty_print && multivalue_table, str, '\n'); |
|
print_level(pretty_print && multivalue_table, level - 1, str); |
|
str << ')'; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
template<typename StreamType> |
|
void serialize_json_null(StreamType & str) const |
|
{ |
|
serialize_string_buffer(L"null", str, Escape::escape_json); |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_json_bool(StreamType & str) const |
|
{ |
|
if( value.value_bool ) |
|
{ |
|
serialize_string_buffer(L"true", str, Escape::escape_json); |
|
} |
|
else |
|
{ |
|
serialize_string_buffer(L"false", str, Escape::escape_json); |
|
} |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void serialize_json_long(StreamType & str) const |
|
{ |
|
wchar_t buffer[50]; |
|
size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); |
|
|
|
Toa(value.value_long, buffer, buffer_len); |
|
serialize_string_buffer(buffer, str, Escape::escape_json); |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_json_float(StreamType & str) const |
|
{ |
|
wchar_t buffer[100]; |
|
size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); |
|
|
|
int chars_written = std::swprintf(buffer, buffer_len, L"%e", static_cast<double>(value.value_float)); |
|
|
|
if( errno == EOVERFLOW || chars_written < 0 ) |
|
buffer[0] = 0; |
|
|
|
serialize_string_buffer(buffer, str, Escape::escape_json); |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_json_double(StreamType & str) const |
|
{ |
|
wchar_t buffer[100]; |
|
size_t buffer_len = sizeof(buffer) / sizeof(wchar_t); |
|
|
|
int chars_written = std::swprintf(buffer, buffer_len, L"%e", value.value_double); |
|
|
|
if( errno == EOVERFLOW || chars_written < 0 ) |
|
buffer[0] = 0; |
|
|
|
serialize_string_buffer(buffer, str, Escape::escape_json); |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_json_string(StreamType & str) const |
|
{ |
|
str << '"'; |
|
serialize_string_buffer(value.value_string.c_str(), str, Escape::escape_json); |
|
str << '"'; |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_json_wstring(StreamType & str) const |
|
{ |
|
str << '"'; |
|
serialize_string_buffer(value.value_wstring.c_str(), str, Escape::escape_json); |
|
str << '"'; |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_json_object(StreamType & str) const |
|
{ |
|
str << '{'; |
|
|
|
bool is_first = true; |
|
|
|
for(auto & map_item : value.value_object) |
|
{ |
|
if( !is_first ) |
|
{ |
|
str << ','; |
|
} |
|
|
|
str << '"'; |
|
serialize_string_buffer(map_item.first.c_str(), str, Escape::escape_json); |
|
str << '"'; |
|
str << ':'; |
|
map_item.second->serialize_to_json_stream(str); |
|
is_first = false; |
|
} |
|
|
|
str << '}'; |
|
} |
|
|
|
template<typename StreamType> |
|
void serialize_json_table(StreamType & str) const |
|
{ |
|
str << '['; |
|
|
|
bool is_first = true; |
|
|
|
for(Space * space : value.value_table) |
|
{ |
|
if( !is_first ) |
|
{ |
|
str << ','; |
|
} |
|
|
|
space->serialize_to_json_stream(str); |
|
is_first = false; |
|
} |
|
|
|
str << ']'; |
|
} |
|
|
|
|
|
protected: |
|
|
|
template<typename StreamType> |
|
void serialize_to_space_stream(StreamType & str, bool pretty_print, int level, bool is_main_object) const |
|
{ |
|
switch(type) |
|
{ |
|
case type_null: |
|
serialize_space_null(str); |
|
break; |
|
|
|
case type_bool: |
|
serialize_space_bool(str); |
|
break; |
|
|
|
case type_long: |
|
serialize_space_long(str); |
|
break; |
|
|
|
case type_float: |
|
serialize_space_float(str); |
|
break; |
|
|
|
case type_double: |
|
serialize_space_double(str); |
|
break; |
|
|
|
case type_string: |
|
serialize_space_string(str); |
|
break; |
|
|
|
case type_wstring: |
|
serialize_space_wstring(str); |
|
break; |
|
|
|
case type_object: |
|
serialize_space_object(str, pretty_print, level, is_main_object); |
|
break; |
|
|
|
case type_table: |
|
serialize_space_table(str, pretty_print, level); |
|
break; |
|
} |
|
} |
|
|
|
|
|
template<typename StringType> |
|
bool should_field_be_quoted(StringType & str) const |
|
{ |
|
if( str.empty() ) |
|
return true; |
|
|
|
for(size_t i = 0 ; i < str.size() ; ++i) |
|
{ |
|
int c = str[i]; |
|
|
|
// '{' is used when child spaces begin |
|
|
|
if( c == '\n' || c == '#' || c == '=' || c == '{' || c == '}' ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void print_level(bool pretty_print, int level, StreamType & str) const |
|
{ |
|
if( pretty_print ) |
|
{ |
|
for(int i=0 ; i < level ; ++i) |
|
{ |
|
str << ' ' << ' '; |
|
} |
|
} |
|
} |
|
|
|
|
|
template<typename StreamType> |
|
void print_if(bool condition, StreamType & str, wchar_t c) const |
|
{ |
|
if( condition ) |
|
str << c; |
|
} |
|
|
|
template<typename StreamType> |
|
void print_if(bool condition, StreamType & str, wchar_t c1, wchar_t c2) const |
|
{ |
|
if( condition ) |
|
str << c1; |
|
else |
|
str << c2; |
|
} |
|
|
|
|
|
void copy_value_from(const Space & space); |
|
void copy_child_spaces_from(const Space & space); |
|
void copy_space_name_from(const Space & space); |
|
void copy_from(const Space & space); |
|
|
|
void copy_value_object(const Value & value_from); |
|
void copy_value_table(const Value & value_from); |
|
|
|
void move_value_from(Space && space); |
|
void move_from(Space && space); |
|
|
|
void initialize(); |
|
void initialize_value_null_if_needed(); |
|
void initialize_value_bool_if_needed(); |
|
void initialize_value_long_if_needed(); |
|
void initialize_value_float_if_needed(); |
|
void initialize_value_double_if_needed(); |
|
void initialize_value_string_if_needed(); |
|
void initialize_value_string_if_needed(std::string && str); |
|
void initialize_value_wstring_if_needed(); |
|
void initialize_value_wstring_if_needed(std::wstring && str); |
|
void initialize_value_object_if_needed(); |
|
void initialize_value_object_if_needed(ObjectType && obj); |
|
void initialize_value_table_if_needed(); |
|
void initialize_value_table_if_needed(TableType && tab); |
|
void initialize_child_spaces_if_needed(); |
|
void initialize_space_name_if_needed(); |
|
|
|
void remove_value(); |
|
void remove_value_string(); |
|
void remove_value_wstring(); |
|
void remove_value_object(); |
|
void remove_value_table(); |
|
void remove_child_spaces(); |
|
void remove_space_name(); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace |
|
|
|
|
|
|
|
#endif
|
|
|