JSON Spirit library from http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx,...
[novacoin.git] / json / json_spirit_writer_template.h
1 #ifndef JSON_SPIRIT_WRITER_TEMPLATE\r
2 #define JSON_SPIRIT_WRITER_TEMPLATE\r
3 \r
4 //          Copyright John W. Wilkinson 2007 - 2009.\r
5 // Distributed under the MIT License, see accompanying file LICENSE.txt\r
6 \r
7 // json spirit version 4.03\r
8 \r
9 #include "json_spirit_value.h"\r
10 \r
11 #include <cassert>\r
12 #include <sstream>\r
13 #include <iomanip>\r
14 \r
15 namespace json_spirit\r
16 {\r
17     inline char to_hex_char( unsigned int c )\r
18     {\r
19         assert( c <= 0xF );\r
20 \r
21         const char ch = static_cast< char >( c );\r
22 \r
23         if( ch < 10 ) return '0' + ch;\r
24 \r
25         return 'A' - 10 + ch;\r
26     }\r
27 \r
28     template< class String_type >\r
29     String_type non_printable_to_string( unsigned int c )\r
30     {\r
31         typedef typename String_type::value_type Char_type;\r
32 \r
33         String_type result( 6, '\\' );\r
34 \r
35         result[1] = 'u';\r
36 \r
37         result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4;\r
38         result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4;\r
39         result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4;\r
40         result[ 2 ] = to_hex_char( c & 0x000F );\r
41 \r
42         return result;\r
43     }\r
44 \r
45     template< typename Char_type, class String_type >\r
46     bool add_esc_char( Char_type c, String_type& s )\r
47     {\r
48         switch( c )\r
49         {\r
50             case '"':  s += to_str< String_type >( "\\\"" ); return true;\r
51             case '\\': s += to_str< String_type >( "\\\\" ); return true;\r
52             case '\b': s += to_str< String_type >( "\\b"  ); return true;\r
53             case '\f': s += to_str< String_type >( "\\f"  ); return true;\r
54             case '\n': s += to_str< String_type >( "\\n"  ); return true;\r
55             case '\r': s += to_str< String_type >( "\\r"  ); return true;\r
56             case '\t': s += to_str< String_type >( "\\t"  ); return true;\r
57         }\r
58 \r
59         return false;\r
60     }\r
61 \r
62     template< class String_type >\r
63     String_type add_esc_chars( const String_type& s )\r
64     {\r
65         typedef typename String_type::const_iterator Iter_type;\r
66         typedef typename String_type::value_type     Char_type;\r
67 \r
68         String_type result;\r
69 \r
70         const Iter_type end( s.end() );\r
71 \r
72         for( Iter_type i = s.begin(); i != end; ++i )\r
73         {\r
74             const Char_type c( *i );\r
75 \r
76             if( add_esc_char( c, result ) ) continue;\r
77 \r
78             const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );\r
79 \r
80             if( iswprint( unsigned_c ) )\r
81             {\r
82                 result += c;\r
83             }\r
84             else\r
85             {\r
86                 result += non_printable_to_string< String_type >( unsigned_c );\r
87             }\r
88         }\r
89 \r
90         return result;\r
91     }\r
92 \r
93     // this class generates the JSON text,\r
94     // it keeps track of the indentation level etc.\r
95     //\r
96     template< class Value_type, class Ostream_type >\r
97     class Generator\r
98     {\r
99         typedef typename Value_type::Config_type Config_type;\r
100         typedef typename Config_type::String_type String_type;\r
101         typedef typename Config_type::Object_type Object_type;\r
102         typedef typename Config_type::Array_type Array_type;\r
103         typedef typename String_type::value_type Char_type;\r
104         typedef typename Object_type::value_type Obj_member_type;\r
105 \r
106     public:\r
107 \r
108         Generator( const Value_type& value, Ostream_type& os, bool pretty )\r
109         :   os_( os )\r
110         ,   indentation_level_( 0 )\r
111         ,   pretty_( pretty )\r
112         {\r
113             output( value );\r
114         }\r
115 \r
116     private:\r
117 \r
118         void output( const Value_type& value )\r
119         {\r
120             switch( value.type() )\r
121             {\r
122                 case obj_type:   output( value.get_obj() );   break;\r
123                 case array_type: output( value.get_array() ); break;\r
124                 case str_type:   output( value.get_str() );   break;\r
125                 case bool_type:  output( value.get_bool() );  break;\r
126                 case int_type:   output_int( value );         break;\r
127                 case real_type:  os_ << std::showpoint << std::setprecision( 16 ) \r
128                                      << value.get_real();     break;\r
129                 case null_type:  os_ << "null";               break;\r
130                 default: assert( false );\r
131             }\r
132         }\r
133 \r
134         void output( const Object_type& obj )\r
135         {\r
136             output_array_or_obj( obj, '{', '}' );\r
137         }\r
138 \r
139         void output( const Array_type& arr )\r
140         {\r
141             output_array_or_obj( arr, '[', ']' );\r
142         }\r
143 \r
144         void output( const Obj_member_type& member )\r
145         {\r
146             output( Config_type::get_name( member ) ); space(); \r
147             os_ << ':'; space(); \r
148             output( Config_type::get_value( member ) );\r
149         }\r
150 \r
151         void output_int( const Value_type& value )\r
152         {\r
153             if( value.is_uint64() )\r
154             {\r
155                 os_ << value.get_uint64();\r
156             }\r
157             else\r
158             {\r
159                os_ << value.get_int64();\r
160             }\r
161         }\r
162 \r
163         void output( const String_type& s )\r
164         {\r
165             os_ << '"' << add_esc_chars( s ) << '"';\r
166         }\r
167 \r
168         void output( bool b )\r
169         {\r
170             os_ << to_str< String_type >( b ? "true" : "false" );\r
171         }\r
172 \r
173         template< class T >\r
174         void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char )\r
175         {\r
176             os_ << start_char; new_line();\r
177 \r
178             ++indentation_level_;\r
179             \r
180             for( typename T::const_iterator i = t.begin(); i != t.end(); ++i )\r
181             {\r
182                 indent(); output( *i );\r
183 \r
184                 typename T::const_iterator next = i;\r
185 \r
186                 if( ++next != t.end())\r
187                 {\r
188                     os_ << ',';\r
189                 }\r
190 \r
191                 new_line();\r
192             }\r
193 \r
194             --indentation_level_;\r
195 \r
196             indent(); os_ << end_char;\r
197         }\r
198         \r
199         void indent()\r
200         {\r
201             if( !pretty_ ) return;\r
202 \r
203             for( int i = 0; i < indentation_level_; ++i )\r
204             { \r
205                 os_ << "    ";\r
206             }\r
207         }\r
208 \r
209         void space()\r
210         {\r
211             if( pretty_ ) os_ << ' ';\r
212         }\r
213 \r
214         void new_line()\r
215         {\r
216             if( pretty_ ) os_ << '\n';\r
217         }\r
218 \r
219         Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning\r
220 \r
221         Ostream_type& os_;\r
222         int indentation_level_;\r
223         bool pretty_;\r
224     };\r
225 \r
226     template< class Value_type, class Ostream_type >\r
227     void write_stream( const Value_type& value, Ostream_type& os, bool pretty )\r
228     {\r
229         Generator< Value_type, Ostream_type >( value, os, pretty );\r
230     }\r
231 \r
232     template< class Value_type >\r
233     typename Value_type::String_type write_string( const Value_type& value, bool pretty )\r
234     {\r
235         typedef typename Value_type::String_type::value_type Char_type;\r
236 \r
237         std::basic_ostringstream< Char_type > os;\r
238 \r
239         write_stream( value, os, pretty );\r
240 \r
241         return os.str();\r
242     }\r
243 }\r
244 \r
245 #endif\r