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