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

/*
* 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