jsoncons 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/jsoncons/extconf.rb +43 -0
- data/ext/jsoncons/jsoncons.cpp +161 -0
- data/ext/jsoncons/jsoncons.h +10 -0
- data/jsoncons.gemspec +44 -0
- data/lib/jsoncons/jsoncons/examples/input/address-book.json +13 -0
- data/lib/jsoncons/jsoncons/examples/input/books.json +28 -0
- data/lib/jsoncons/jsoncons/examples/input/countries.json +7 -0
- data/lib/jsoncons/jsoncons/examples/input/employees.json +30 -0
- data/lib/jsoncons/jsoncons/examples/input/jsonschema/name.json +15 -0
- data/lib/jsoncons/jsoncons/examples/input/multiple-json-objects.json +3 -0
- data/lib/jsoncons/jsoncons/examples/input/sales.csv +6 -0
- data/lib/jsoncons/jsoncons/examples/input/store.json +28 -0
- data/lib/jsoncons/jsoncons/examples/input/tasks.csv +6 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/allocator_holder.hpp +38 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/basic_json.hpp +5905 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/bigint.hpp +1611 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/byte_string.hpp +820 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/config/binary_config.hpp +226 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/config/compiler_support.hpp +375 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/config/jsoncons_config.hpp +309 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/config/version.hpp +40 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/conv_error.hpp +218 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/decode_json.hpp +209 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/decode_traits.hpp +651 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/endian.hpp +44 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/grisu3.hpp +312 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/optional.hpp +483 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/parse_number.hpp +1133 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/span.hpp +188 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/string_view.hpp +537 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/string_wrapper.hpp +370 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/write_number.hpp +567 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/encode_json.hpp +315 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/encode_traits.hpp +378 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json.hpp +18 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_array.hpp +324 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_content_handler.hpp +12 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_cursor.hpp +448 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_decoder.hpp +420 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_encoder.hpp +1587 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_error.hpp +156 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_exception.hpp +241 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_filter.hpp +653 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_fwd.hpp +23 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_object.hpp +1772 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_options.hpp +862 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_parser.hpp +2900 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_reader.hpp +731 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_traits_macros.hpp +1072 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_traits_macros_deprecated.hpp +144 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_type.hpp +206 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_type_traits.hpp +1830 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_visitor.hpp +1560 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_visitor2.hpp +2079 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/pretty_print.hpp +89 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/ser_context.hpp +62 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/sink.hpp +289 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/source.hpp +777 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/source_adaptor.hpp +148 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/staj2_cursor.hpp +1189 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/staj_cursor.hpp +1254 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/staj_iterator.hpp +449 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/tag_type.hpp +245 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/text_source_adaptor.hpp +144 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/traits_extension.hpp +884 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/typed_array_view.hpp +250 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/unicode_traits.hpp +1330 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/uri.hpp +635 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/value_converter.hpp +340 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson.hpp +23 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_cursor.hpp +320 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_decimal128.hpp +865 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_encoder.hpp +585 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_error.hpp +103 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_oid.hpp +245 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_options.hpp +75 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_parser.hpp +645 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_reader.hpp +92 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_type.hpp +44 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/decode_bson.hpp +201 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/encode_bson.hpp +144 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor.hpp +26 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_cursor.hpp +351 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_cursor2.hpp +265 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_detail.hpp +93 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_encoder.hpp +1766 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_error.hpp +105 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_options.hpp +113 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_parser.hpp +1942 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_reader.hpp +116 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/decode_cbor.hpp +203 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/encode_cbor.hpp +151 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv.hpp +17 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_cursor.hpp +358 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_encoder.hpp +954 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_error.hpp +85 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_options.hpp +973 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_parser.hpp +2099 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_reader.hpp +348 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_serializer.hpp +12 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/decode_csv.hpp +208 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/encode_csv.hpp +122 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jmespath/jmespath.hpp +5215 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jmespath/jmespath_error.hpp +215 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpatch/jsonpatch.hpp +579 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpatch/jsonpatch_error.hpp +121 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/expression.hpp +3329 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/flatten.hpp +432 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/json_location.hpp +445 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/json_query.hpp +115 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath.hpp +13 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_error.hpp +240 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_expression.hpp +2612 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp +1322 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpointer/jsonpointer.hpp +1577 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpointer/jsonpointer_error.hpp +119 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/format_validator.hpp +968 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/json_validator.hpp +120 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema.hpp +13 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema_error.hpp +105 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema_version.hpp +18 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/keyword_validator.hpp +1745 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/keyword_validator_factory.hpp +556 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_draft7.hpp +198 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_location.hpp +200 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_version.hpp +35 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/subschema.hpp +144 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/mergepatch/mergepatch.hpp +103 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/decode_msgpack.hpp +202 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/encode_msgpack.hpp +142 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack.hpp +24 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_cursor.hpp +343 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp +259 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_encoder.hpp +753 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_error.hpp +94 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_options.hpp +74 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_parser.hpp +748 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_reader.hpp +116 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_type.hpp +63 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/decode_ubjson.hpp +201 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/encode_ubjson.hpp +142 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson.hpp +23 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_cursor.hpp +307 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_encoder.hpp +502 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_error.hpp +100 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_options.hpp +87 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_parser.hpp +880 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_reader.hpp +92 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_type.hpp +43 -0
- data/lib/jsoncons/version.rb +5 -0
- data/lib/jsoncons.rb +33 -0
- data/test/jsoncons_test.rb +108 -0
- data/test/test_helper.rb +7 -0
- metadata +268 -0
|
@@ -0,0 +1,1587 @@
|
|
|
1
|
+
// Copyright 2013 Daniel Parker
|
|
2
|
+
// Distributed under the Boost license, Version 1.0.
|
|
3
|
+
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
4
|
+
|
|
5
|
+
// See https://github.com/danielaparker/jsoncons for latest version
|
|
6
|
+
|
|
7
|
+
#ifndef JSONCONS_JSON_ENCODER_HPP
|
|
8
|
+
#define JSONCONS_JSON_ENCODER_HPP
|
|
9
|
+
|
|
10
|
+
#include <array> // std::array
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <vector>
|
|
13
|
+
#include <cmath> // std::isfinite, std::isnan
|
|
14
|
+
#include <limits> // std::numeric_limits
|
|
15
|
+
#include <memory>
|
|
16
|
+
#include <utility> // std::move
|
|
17
|
+
#include <jsoncons/config/jsoncons_config.hpp>
|
|
18
|
+
#include <jsoncons/json_exception.hpp>
|
|
19
|
+
#include <jsoncons/byte_string.hpp>
|
|
20
|
+
#include <jsoncons/bigint.hpp>
|
|
21
|
+
#include <jsoncons/json_options.hpp>
|
|
22
|
+
#include <jsoncons/json_error.hpp>
|
|
23
|
+
#include <jsoncons/json_visitor.hpp>
|
|
24
|
+
#include <jsoncons/sink.hpp>
|
|
25
|
+
#include <jsoncons/detail/write_number.hpp>
|
|
26
|
+
|
|
27
|
+
namespace jsoncons {
|
|
28
|
+
namespace detail {
|
|
29
|
+
|
|
30
|
+
inline
|
|
31
|
+
bool is_control_character(uint32_t c)
|
|
32
|
+
{
|
|
33
|
+
return c <= 0x1F || c == 0x7f;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
inline
|
|
37
|
+
bool is_non_ascii_codepoint(uint32_t cp)
|
|
38
|
+
{
|
|
39
|
+
return cp >= 0x80;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
template <class CharT, class Sink>
|
|
43
|
+
std::size_t escape_string(const CharT* s, std::size_t length,
|
|
44
|
+
bool escape_all_non_ascii, bool escape_solidus,
|
|
45
|
+
Sink& sink)
|
|
46
|
+
{
|
|
47
|
+
std::size_t count = 0;
|
|
48
|
+
const CharT* begin = s;
|
|
49
|
+
const CharT* end = s + length;
|
|
50
|
+
for (const CharT* it = begin; it != end; ++it)
|
|
51
|
+
{
|
|
52
|
+
CharT c = *it;
|
|
53
|
+
switch (c)
|
|
54
|
+
{
|
|
55
|
+
case '\\':
|
|
56
|
+
sink.push_back('\\');
|
|
57
|
+
sink.push_back('\\');
|
|
58
|
+
count += 2;
|
|
59
|
+
break;
|
|
60
|
+
case '"':
|
|
61
|
+
sink.push_back('\\');
|
|
62
|
+
sink.push_back('\"');
|
|
63
|
+
count += 2;
|
|
64
|
+
break;
|
|
65
|
+
case '\b':
|
|
66
|
+
sink.push_back('\\');
|
|
67
|
+
sink.push_back('b');
|
|
68
|
+
count += 2;
|
|
69
|
+
break;
|
|
70
|
+
case '\f':
|
|
71
|
+
sink.push_back('\\');
|
|
72
|
+
sink.push_back('f');
|
|
73
|
+
count += 2;
|
|
74
|
+
break;
|
|
75
|
+
case '\n':
|
|
76
|
+
sink.push_back('\\');
|
|
77
|
+
sink.push_back('n');
|
|
78
|
+
count += 2;
|
|
79
|
+
break;
|
|
80
|
+
case '\r':
|
|
81
|
+
sink.push_back('\\');
|
|
82
|
+
sink.push_back('r');
|
|
83
|
+
count += 2;
|
|
84
|
+
break;
|
|
85
|
+
case '\t':
|
|
86
|
+
sink.push_back('\\');
|
|
87
|
+
sink.push_back('t');
|
|
88
|
+
count += 2;
|
|
89
|
+
break;
|
|
90
|
+
default:
|
|
91
|
+
if (escape_solidus && c == '/')
|
|
92
|
+
{
|
|
93
|
+
sink.push_back('\\');
|
|
94
|
+
sink.push_back('/');
|
|
95
|
+
count += 2;
|
|
96
|
+
}
|
|
97
|
+
else if (is_control_character(c) || escape_all_non_ascii)
|
|
98
|
+
{
|
|
99
|
+
// convert to codepoint
|
|
100
|
+
uint32_t cp;
|
|
101
|
+
auto r = unicode_traits::to_codepoint(it, end, cp, unicode_traits::conv_flags::strict);
|
|
102
|
+
if (r.ec != unicode_traits::conv_errc())
|
|
103
|
+
{
|
|
104
|
+
JSONCONS_THROW(ser_error(json_errc::illegal_codepoint));
|
|
105
|
+
}
|
|
106
|
+
it = r.ptr - 1;
|
|
107
|
+
if (is_non_ascii_codepoint(cp) || is_control_character(c))
|
|
108
|
+
{
|
|
109
|
+
if (cp > 0xFFFF)
|
|
110
|
+
{
|
|
111
|
+
cp -= 0x10000;
|
|
112
|
+
uint32_t first = (cp >> 10) + 0xD800;
|
|
113
|
+
uint32_t second = ((cp & 0x03FF) + 0xDC00);
|
|
114
|
+
|
|
115
|
+
sink.push_back('\\');
|
|
116
|
+
sink.push_back('u');
|
|
117
|
+
sink.push_back(jsoncons::detail::to_hex_character(first >> 12 & 0x000F));
|
|
118
|
+
sink.push_back(jsoncons::detail::to_hex_character(first >> 8 & 0x000F));
|
|
119
|
+
sink.push_back(jsoncons::detail::to_hex_character(first >> 4 & 0x000F));
|
|
120
|
+
sink.push_back(jsoncons::detail::to_hex_character(first & 0x000F));
|
|
121
|
+
sink.push_back('\\');
|
|
122
|
+
sink.push_back('u');
|
|
123
|
+
sink.push_back(jsoncons::detail::to_hex_character(second >> 12 & 0x000F));
|
|
124
|
+
sink.push_back(jsoncons::detail::to_hex_character(second >> 8 & 0x000F));
|
|
125
|
+
sink.push_back(jsoncons::detail::to_hex_character(second >> 4 & 0x000F));
|
|
126
|
+
sink.push_back(jsoncons::detail::to_hex_character(second & 0x000F));
|
|
127
|
+
count += 12;
|
|
128
|
+
}
|
|
129
|
+
else
|
|
130
|
+
{
|
|
131
|
+
sink.push_back('\\');
|
|
132
|
+
sink.push_back('u');
|
|
133
|
+
sink.push_back(jsoncons::detail::to_hex_character(cp >> 12 & 0x000F));
|
|
134
|
+
sink.push_back(jsoncons::detail::to_hex_character(cp >> 8 & 0x000F));
|
|
135
|
+
sink.push_back(jsoncons::detail::to_hex_character(cp >> 4 & 0x000F));
|
|
136
|
+
sink.push_back(jsoncons::detail::to_hex_character(cp & 0x000F));
|
|
137
|
+
count += 6;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else
|
|
141
|
+
{
|
|
142
|
+
sink.push_back(c);
|
|
143
|
+
++count;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else
|
|
147
|
+
{
|
|
148
|
+
sink.push_back(c);
|
|
149
|
+
++count;
|
|
150
|
+
}
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return count;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
inline
|
|
158
|
+
byte_string_chars_format resolve_byte_string_chars_format(byte_string_chars_format format1,
|
|
159
|
+
byte_string_chars_format format2,
|
|
160
|
+
byte_string_chars_format default_format = byte_string_chars_format::base64url)
|
|
161
|
+
{
|
|
162
|
+
byte_string_chars_format sink;
|
|
163
|
+
switch (format1)
|
|
164
|
+
{
|
|
165
|
+
case byte_string_chars_format::base16:
|
|
166
|
+
case byte_string_chars_format::base64:
|
|
167
|
+
case byte_string_chars_format::base64url:
|
|
168
|
+
sink = format1;
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
switch (format2)
|
|
172
|
+
{
|
|
173
|
+
case byte_string_chars_format::base64url:
|
|
174
|
+
case byte_string_chars_format::base64:
|
|
175
|
+
case byte_string_chars_format::base16:
|
|
176
|
+
sink = format2;
|
|
177
|
+
break;
|
|
178
|
+
default: // base64url
|
|
179
|
+
{
|
|
180
|
+
sink = default_format;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
return sink;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
} // namespace detail
|
|
190
|
+
|
|
191
|
+
template<class CharT,class Sink=jsoncons::stream_sink<CharT>,class Allocator=std::allocator<char>>
|
|
192
|
+
class basic_json_encoder final : public basic_json_visitor<CharT>
|
|
193
|
+
{
|
|
194
|
+
static const jsoncons::basic_string_view<CharT> null_constant()
|
|
195
|
+
{
|
|
196
|
+
static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "null");
|
|
197
|
+
return k;
|
|
198
|
+
}
|
|
199
|
+
static const jsoncons::basic_string_view<CharT> true_constant()
|
|
200
|
+
{
|
|
201
|
+
static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "true");
|
|
202
|
+
return k;
|
|
203
|
+
}
|
|
204
|
+
static const jsoncons::basic_string_view<CharT> false_constant()
|
|
205
|
+
{
|
|
206
|
+
static const jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT, "false");
|
|
207
|
+
return k;
|
|
208
|
+
}
|
|
209
|
+
public:
|
|
210
|
+
using allocator_type = Allocator;
|
|
211
|
+
using char_type = CharT;
|
|
212
|
+
using typename basic_json_visitor<CharT>::string_view_type;
|
|
213
|
+
using sink_type = Sink;
|
|
214
|
+
using string_type = typename basic_json_encode_options<CharT>::string_type;
|
|
215
|
+
|
|
216
|
+
private:
|
|
217
|
+
enum class container_type {object, array};
|
|
218
|
+
|
|
219
|
+
class encoding_context
|
|
220
|
+
{
|
|
221
|
+
container_type type_;
|
|
222
|
+
std::size_t count_;
|
|
223
|
+
line_split_kind line_splits_;
|
|
224
|
+
bool indent_before_;
|
|
225
|
+
bool new_line_after_;
|
|
226
|
+
std::size_t begin_pos_;
|
|
227
|
+
std::size_t data_pos_;
|
|
228
|
+
public:
|
|
229
|
+
encoding_context(container_type type, line_split_kind split_lines, bool indent_once,
|
|
230
|
+
std::size_t begin_pos, std::size_t data_pos) noexcept
|
|
231
|
+
: type_(type), count_(0), line_splits_(split_lines), indent_before_(indent_once), new_line_after_(false),
|
|
232
|
+
begin_pos_(begin_pos), data_pos_(data_pos)
|
|
233
|
+
{
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
encoding_context(const encoding_context&) = default;
|
|
237
|
+
encoding_context& operator=(const encoding_context&) = default;
|
|
238
|
+
|
|
239
|
+
void set_position(std::size_t pos)
|
|
240
|
+
{
|
|
241
|
+
data_pos_ = pos;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
std::size_t begin_pos() const
|
|
245
|
+
{
|
|
246
|
+
return begin_pos_;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
std::size_t data_pos() const
|
|
250
|
+
{
|
|
251
|
+
return data_pos_;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
std::size_t count() const
|
|
255
|
+
{
|
|
256
|
+
return count_;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
void increment_count()
|
|
260
|
+
{
|
|
261
|
+
++count_;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
bool new_line_after() const
|
|
265
|
+
{
|
|
266
|
+
return new_line_after_;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
void new_line_after(bool value)
|
|
270
|
+
{
|
|
271
|
+
new_line_after_ = value;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
bool is_object() const
|
|
275
|
+
{
|
|
276
|
+
return type_ == container_type::object;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
bool is_array() const
|
|
280
|
+
{
|
|
281
|
+
return type_ == container_type::array;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
bool is_same_line() const
|
|
285
|
+
{
|
|
286
|
+
return line_splits_ == line_split_kind::same_line;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
bool is_new_line() const
|
|
290
|
+
{
|
|
291
|
+
return line_splits_ == line_split_kind::new_line;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
bool is_multi_line() const
|
|
295
|
+
{
|
|
296
|
+
return line_splits_ == line_split_kind::multi_line;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
bool is_indent_once() const
|
|
300
|
+
{
|
|
301
|
+
return count_ == 0 ? indent_before_ : false;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
};
|
|
305
|
+
typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<encoding_context> encoding_context_allocator_type;
|
|
306
|
+
|
|
307
|
+
Sink sink_;
|
|
308
|
+
basic_json_encode_options<CharT> options_;
|
|
309
|
+
jsoncons::detail::write_double fp_;
|
|
310
|
+
|
|
311
|
+
std::vector<encoding_context,encoding_context_allocator_type> stack_;
|
|
312
|
+
int indent_amount_;
|
|
313
|
+
std::size_t column_;
|
|
314
|
+
std::basic_string<CharT> colon_str_;
|
|
315
|
+
std::basic_string<CharT> comma_str_;
|
|
316
|
+
std::basic_string<CharT> open_object_brace_str_;
|
|
317
|
+
std::basic_string<CharT> close_object_brace_str_;
|
|
318
|
+
std::basic_string<CharT> open_array_bracket_str_;
|
|
319
|
+
std::basic_string<CharT> close_array_bracket_str_;
|
|
320
|
+
int nesting_depth_;
|
|
321
|
+
|
|
322
|
+
// Noncopyable and nonmoveable
|
|
323
|
+
basic_json_encoder(const basic_json_encoder&) = delete;
|
|
324
|
+
basic_json_encoder& operator=(const basic_json_encoder&) = delete;
|
|
325
|
+
public:
|
|
326
|
+
basic_json_encoder(Sink&& sink,
|
|
327
|
+
const Allocator& alloc = Allocator())
|
|
328
|
+
: basic_json_encoder(std::forward<Sink>(sink), basic_json_encode_options<CharT>(), alloc)
|
|
329
|
+
{
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
basic_json_encoder(Sink&& sink,
|
|
333
|
+
const basic_json_encode_options<CharT>& options,
|
|
334
|
+
const Allocator& alloc = Allocator())
|
|
335
|
+
: sink_(std::forward<Sink>(sink)),
|
|
336
|
+
options_(options),
|
|
337
|
+
fp_(options.float_format(), options.precision()),
|
|
338
|
+
stack_(alloc),
|
|
339
|
+
indent_amount_(0),
|
|
340
|
+
column_(0),
|
|
341
|
+
nesting_depth_(0)
|
|
342
|
+
{
|
|
343
|
+
switch (options.spaces_around_colon())
|
|
344
|
+
{
|
|
345
|
+
case spaces_option::space_after:
|
|
346
|
+
colon_str_ = std::basic_string<CharT>({':',' '});
|
|
347
|
+
break;
|
|
348
|
+
case spaces_option::space_before:
|
|
349
|
+
colon_str_ = std::basic_string<CharT>({' ',':'});
|
|
350
|
+
break;
|
|
351
|
+
case spaces_option::space_before_and_after:
|
|
352
|
+
colon_str_ = std::basic_string<CharT>({' ',':',' '});
|
|
353
|
+
break;
|
|
354
|
+
default:
|
|
355
|
+
colon_str_.push_back(':');
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
switch (options.spaces_around_comma())
|
|
359
|
+
{
|
|
360
|
+
case spaces_option::space_after:
|
|
361
|
+
comma_str_ = std::basic_string<CharT>({',',' '});
|
|
362
|
+
break;
|
|
363
|
+
case spaces_option::space_before:
|
|
364
|
+
comma_str_ = std::basic_string<CharT>({' ',','});
|
|
365
|
+
break;
|
|
366
|
+
case spaces_option::space_before_and_after:
|
|
367
|
+
comma_str_ = std::basic_string<CharT>({' ',',',' '});
|
|
368
|
+
break;
|
|
369
|
+
default:
|
|
370
|
+
comma_str_.push_back(',');
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
if (options.pad_inside_object_braces())
|
|
374
|
+
{
|
|
375
|
+
open_object_brace_str_ = std::basic_string<CharT>({'{', ' '});
|
|
376
|
+
close_object_brace_str_ = std::basic_string<CharT>({' ', '}'});
|
|
377
|
+
}
|
|
378
|
+
else
|
|
379
|
+
{
|
|
380
|
+
open_object_brace_str_.push_back('{');
|
|
381
|
+
close_object_brace_str_.push_back('}');
|
|
382
|
+
}
|
|
383
|
+
if (options.pad_inside_array_brackets())
|
|
384
|
+
{
|
|
385
|
+
open_array_bracket_str_ = std::basic_string<CharT>({'[', ' '});
|
|
386
|
+
close_array_bracket_str_ = std::basic_string<CharT>({' ', ']'});
|
|
387
|
+
}
|
|
388
|
+
else
|
|
389
|
+
{
|
|
390
|
+
open_array_bracket_str_.push_back('[');
|
|
391
|
+
close_array_bracket_str_.push_back(']');
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
~basic_json_encoder() noexcept
|
|
396
|
+
{
|
|
397
|
+
JSONCONS_TRY
|
|
398
|
+
{
|
|
399
|
+
sink_.flush();
|
|
400
|
+
}
|
|
401
|
+
JSONCONS_CATCH(...)
|
|
402
|
+
{
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
void reset()
|
|
407
|
+
{
|
|
408
|
+
stack_.clear();
|
|
409
|
+
indent_amount_ = 0;
|
|
410
|
+
column_ = 0;
|
|
411
|
+
nesting_depth_ = 0;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
void reset(Sink&& sink)
|
|
415
|
+
{
|
|
416
|
+
sink_ = std::move(sink);
|
|
417
|
+
reset();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
private:
|
|
421
|
+
// Implementing methods
|
|
422
|
+
void visit_flush() override
|
|
423
|
+
{
|
|
424
|
+
sink_.flush();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override
|
|
428
|
+
{
|
|
429
|
+
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
|
|
430
|
+
{
|
|
431
|
+
ec = json_errc::max_nesting_depth_exceeded;
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
435
|
+
{
|
|
436
|
+
sink_.append(comma_str_.data(),comma_str_.length());
|
|
437
|
+
column_ += comma_str_.length();
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (!stack_.empty()) // object or array
|
|
441
|
+
{
|
|
442
|
+
if (stack_.back().is_object())
|
|
443
|
+
{
|
|
444
|
+
switch (options_.object_object_line_splits())
|
|
445
|
+
{
|
|
446
|
+
case line_split_kind::same_line:
|
|
447
|
+
if (column_ >= options_.line_length_limit())
|
|
448
|
+
{
|
|
449
|
+
break_line();
|
|
450
|
+
}
|
|
451
|
+
break;
|
|
452
|
+
case line_split_kind::new_line:
|
|
453
|
+
if (column_ >= options_.line_length_limit())
|
|
454
|
+
{
|
|
455
|
+
break_line();
|
|
456
|
+
}
|
|
457
|
+
break;
|
|
458
|
+
default: // multi_line
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
stack_.emplace_back(container_type::object,options_.object_object_line_splits(), false,
|
|
462
|
+
column_, column_+open_object_brace_str_.length());
|
|
463
|
+
}
|
|
464
|
+
else // array
|
|
465
|
+
{
|
|
466
|
+
switch (options_.array_object_line_splits())
|
|
467
|
+
{
|
|
468
|
+
case line_split_kind::same_line:
|
|
469
|
+
if (column_ >= options_.line_length_limit())
|
|
470
|
+
{
|
|
471
|
+
//stack_.back().new_line_after(true);
|
|
472
|
+
new_line();
|
|
473
|
+
}
|
|
474
|
+
break;
|
|
475
|
+
case line_split_kind::new_line:
|
|
476
|
+
stack_.back().new_line_after(true);
|
|
477
|
+
new_line();
|
|
478
|
+
break;
|
|
479
|
+
default: // multi_line
|
|
480
|
+
stack_.back().new_line_after(true);
|
|
481
|
+
new_line();
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
stack_.emplace_back(container_type::object,options_.array_object_line_splits(), false,
|
|
485
|
+
column_, column_+open_object_brace_str_.length());
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
else
|
|
489
|
+
{
|
|
490
|
+
stack_.emplace_back(container_type::object, line_split_kind::multi_line, false,
|
|
491
|
+
column_, column_+open_object_brace_str_.length());
|
|
492
|
+
}
|
|
493
|
+
indent();
|
|
494
|
+
|
|
495
|
+
sink_.append(open_object_brace_str_.data(), open_object_brace_str_.length());
|
|
496
|
+
column_ += open_object_brace_str_.length();
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
bool visit_end_object(const ser_context&, std::error_code&) override
|
|
501
|
+
{
|
|
502
|
+
JSONCONS_ASSERT(!stack_.empty());
|
|
503
|
+
--nesting_depth_;
|
|
504
|
+
|
|
505
|
+
unindent();
|
|
506
|
+
if (stack_.back().new_line_after())
|
|
507
|
+
{
|
|
508
|
+
new_line();
|
|
509
|
+
}
|
|
510
|
+
stack_.pop_back();
|
|
511
|
+
sink_.append(close_object_brace_str_.data(), close_object_brace_str_.length());
|
|
512
|
+
column_ += close_object_brace_str_.length();
|
|
513
|
+
|
|
514
|
+
end_value();
|
|
515
|
+
return true;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override
|
|
519
|
+
{
|
|
520
|
+
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
|
|
521
|
+
{
|
|
522
|
+
ec = json_errc::max_nesting_depth_exceeded;
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
526
|
+
{
|
|
527
|
+
sink_.append(comma_str_.data(),comma_str_.length());
|
|
528
|
+
column_ += comma_str_.length();
|
|
529
|
+
}
|
|
530
|
+
if (!stack_.empty())
|
|
531
|
+
{
|
|
532
|
+
if (stack_.back().is_object())
|
|
533
|
+
{
|
|
534
|
+
switch (options_.object_array_line_splits())
|
|
535
|
+
{
|
|
536
|
+
case line_split_kind::same_line:
|
|
537
|
+
stack_.emplace_back(container_type::array,options_.object_array_line_splits(),false,
|
|
538
|
+
column_, column_ + open_array_bracket_str_.length());
|
|
539
|
+
break;
|
|
540
|
+
case line_split_kind::new_line:
|
|
541
|
+
{
|
|
542
|
+
stack_.emplace_back(container_type::array,options_.object_array_line_splits(),true,
|
|
543
|
+
column_, column_+open_array_bracket_str_.length());
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
default: // multi_line
|
|
547
|
+
stack_.emplace_back(container_type::array,options_.object_array_line_splits(),true,
|
|
548
|
+
column_, column_+open_array_bracket_str_.length());
|
|
549
|
+
break;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
else // array
|
|
553
|
+
{
|
|
554
|
+
switch (options_.array_array_line_splits())
|
|
555
|
+
{
|
|
556
|
+
case line_split_kind::same_line:
|
|
557
|
+
if (stack_.back().is_multi_line())
|
|
558
|
+
{
|
|
559
|
+
stack_.back().new_line_after(true);
|
|
560
|
+
new_line();
|
|
561
|
+
}
|
|
562
|
+
stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false,
|
|
563
|
+
column_, column_+open_array_bracket_str_.length());
|
|
564
|
+
break;
|
|
565
|
+
case line_split_kind::new_line:
|
|
566
|
+
stack_.back().new_line_after(true);
|
|
567
|
+
new_line();
|
|
568
|
+
stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false,
|
|
569
|
+
column_, column_+open_array_bracket_str_.length());
|
|
570
|
+
break;
|
|
571
|
+
default: // multi_line
|
|
572
|
+
stack_.back().new_line_after(true);
|
|
573
|
+
new_line();
|
|
574
|
+
stack_.emplace_back(container_type::array,options_.array_array_line_splits(), false,
|
|
575
|
+
column_, column_+open_array_bracket_str_.length());
|
|
576
|
+
//new_line();
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
else
|
|
582
|
+
{
|
|
583
|
+
stack_.emplace_back(container_type::array, line_split_kind::multi_line, false,
|
|
584
|
+
column_, column_+open_array_bracket_str_.length());
|
|
585
|
+
}
|
|
586
|
+
indent();
|
|
587
|
+
sink_.append(open_array_bracket_str_.data(), open_array_bracket_str_.length());
|
|
588
|
+
column_ += open_array_bracket_str_.length();
|
|
589
|
+
return true;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
bool visit_end_array(const ser_context&, std::error_code&) override
|
|
593
|
+
{
|
|
594
|
+
JSONCONS_ASSERT(!stack_.empty());
|
|
595
|
+
--nesting_depth_;
|
|
596
|
+
|
|
597
|
+
unindent();
|
|
598
|
+
if (stack_.back().new_line_after())
|
|
599
|
+
{
|
|
600
|
+
new_line();
|
|
601
|
+
}
|
|
602
|
+
stack_.pop_back();
|
|
603
|
+
sink_.append(close_array_bracket_str_.data(), close_array_bracket_str_.length());
|
|
604
|
+
column_ += close_array_bracket_str_.length();
|
|
605
|
+
end_value();
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
|
|
610
|
+
{
|
|
611
|
+
JSONCONS_ASSERT(!stack_.empty());
|
|
612
|
+
if (stack_.back().count() > 0)
|
|
613
|
+
{
|
|
614
|
+
sink_.append(comma_str_.data(),comma_str_.length());
|
|
615
|
+
column_ += comma_str_.length();
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (stack_.back().is_multi_line())
|
|
619
|
+
{
|
|
620
|
+
stack_.back().new_line_after(true);
|
|
621
|
+
new_line();
|
|
622
|
+
}
|
|
623
|
+
else if (stack_.back().count() > 0 && column_ >= options_.line_length_limit())
|
|
624
|
+
{
|
|
625
|
+
//stack_.back().new_line_after(true);
|
|
626
|
+
new_line(stack_.back().data_pos());
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (stack_.back().count() == 0)
|
|
630
|
+
{
|
|
631
|
+
stack_.back().set_position(column_);
|
|
632
|
+
}
|
|
633
|
+
sink_.push_back('\"');
|
|
634
|
+
std::size_t length = jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
|
|
635
|
+
sink_.push_back('\"');
|
|
636
|
+
sink_.append(colon_str_.data(),colon_str_.length());
|
|
637
|
+
column_ += (length+2+colon_str_.length());
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
bool visit_null(semantic_tag, const ser_context&, std::error_code&) override
|
|
642
|
+
{
|
|
643
|
+
if (!stack_.empty())
|
|
644
|
+
{
|
|
645
|
+
if (stack_.back().is_array())
|
|
646
|
+
{
|
|
647
|
+
begin_scalar_value();
|
|
648
|
+
}
|
|
649
|
+
if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
|
|
650
|
+
{
|
|
651
|
+
break_line();
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
sink_.append(null_constant().data(), null_constant().size());
|
|
656
|
+
column_ += null_constant().size();
|
|
657
|
+
|
|
658
|
+
end_value();
|
|
659
|
+
return true;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) override
|
|
663
|
+
{
|
|
664
|
+
if (!stack_.empty())
|
|
665
|
+
{
|
|
666
|
+
if (stack_.back().is_array())
|
|
667
|
+
{
|
|
668
|
+
begin_scalar_value();
|
|
669
|
+
}
|
|
670
|
+
if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
|
|
671
|
+
{
|
|
672
|
+
break_line();
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
switch (tag)
|
|
677
|
+
{
|
|
678
|
+
case semantic_tag::bigint:
|
|
679
|
+
write_bigint_value(sv);
|
|
680
|
+
break;
|
|
681
|
+
default:
|
|
682
|
+
{
|
|
683
|
+
sink_.push_back('\"');
|
|
684
|
+
std::size_t length = jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
|
|
685
|
+
sink_.push_back('\"');
|
|
686
|
+
column_ += (length+2);
|
|
687
|
+
break;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
end_value();
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
bool visit_byte_string(const byte_string_view& b,
|
|
696
|
+
semantic_tag tag,
|
|
697
|
+
const ser_context&,
|
|
698
|
+
std::error_code&) override
|
|
699
|
+
{
|
|
700
|
+
if (!stack_.empty())
|
|
701
|
+
{
|
|
702
|
+
if (stack_.back().is_array())
|
|
703
|
+
{
|
|
704
|
+
begin_scalar_value();
|
|
705
|
+
}
|
|
706
|
+
if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
|
|
707
|
+
{
|
|
708
|
+
break_line();
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
byte_string_chars_format encoding_hint;
|
|
713
|
+
switch (tag)
|
|
714
|
+
{
|
|
715
|
+
case semantic_tag::base16:
|
|
716
|
+
encoding_hint = byte_string_chars_format::base16;
|
|
717
|
+
break;
|
|
718
|
+
case semantic_tag::base64:
|
|
719
|
+
encoding_hint = byte_string_chars_format::base64;
|
|
720
|
+
break;
|
|
721
|
+
case semantic_tag::base64url:
|
|
722
|
+
encoding_hint = byte_string_chars_format::base64url;
|
|
723
|
+
break;
|
|
724
|
+
default:
|
|
725
|
+
encoding_hint = byte_string_chars_format::none;
|
|
726
|
+
break;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(),
|
|
730
|
+
encoding_hint,
|
|
731
|
+
byte_string_chars_format::base64url);
|
|
732
|
+
switch (format)
|
|
733
|
+
{
|
|
734
|
+
case byte_string_chars_format::base16:
|
|
735
|
+
{
|
|
736
|
+
sink_.push_back('\"');
|
|
737
|
+
std::size_t length = encode_base16(b.begin(),b.end(),sink_);
|
|
738
|
+
sink_.push_back('\"');
|
|
739
|
+
column_ += (length + 2);
|
|
740
|
+
break;
|
|
741
|
+
}
|
|
742
|
+
case byte_string_chars_format::base64:
|
|
743
|
+
{
|
|
744
|
+
sink_.push_back('\"');
|
|
745
|
+
std::size_t length = encode_base64(b.begin(), b.end(), sink_);
|
|
746
|
+
sink_.push_back('\"');
|
|
747
|
+
column_ += (length + 2);
|
|
748
|
+
break;
|
|
749
|
+
}
|
|
750
|
+
case byte_string_chars_format::base64url:
|
|
751
|
+
{
|
|
752
|
+
sink_.push_back('\"');
|
|
753
|
+
std::size_t length = encode_base64url(b.begin(),b.end(),sink_);
|
|
754
|
+
sink_.push_back('\"');
|
|
755
|
+
column_ += (length + 2);
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
default:
|
|
759
|
+
{
|
|
760
|
+
JSONCONS_UNREACHABLE();
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
end_value();
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
bool visit_double(double value,
|
|
769
|
+
semantic_tag,
|
|
770
|
+
const ser_context& context,
|
|
771
|
+
std::error_code& ec) override
|
|
772
|
+
{
|
|
773
|
+
if (!stack_.empty())
|
|
774
|
+
{
|
|
775
|
+
if (stack_.back().is_array())
|
|
776
|
+
{
|
|
777
|
+
begin_scalar_value();
|
|
778
|
+
}
|
|
779
|
+
if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
|
|
780
|
+
{
|
|
781
|
+
break_line();
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
if (!std::isfinite(value))
|
|
786
|
+
{
|
|
787
|
+
if ((std::isnan)(value))
|
|
788
|
+
{
|
|
789
|
+
if (options_.enable_nan_to_num())
|
|
790
|
+
{
|
|
791
|
+
sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length());
|
|
792
|
+
column_ += options_.nan_to_num().length();
|
|
793
|
+
}
|
|
794
|
+
else if (options_.enable_nan_to_str())
|
|
795
|
+
{
|
|
796
|
+
visit_string(options_.nan_to_str(), semantic_tag::none, context, ec);
|
|
797
|
+
}
|
|
798
|
+
else
|
|
799
|
+
{
|
|
800
|
+
sink_.append(null_constant().data(), null_constant().size());
|
|
801
|
+
column_ += null_constant().size();
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
else if (value == std::numeric_limits<double>::infinity())
|
|
805
|
+
{
|
|
806
|
+
if (options_.enable_inf_to_num())
|
|
807
|
+
{
|
|
808
|
+
sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length());
|
|
809
|
+
column_ += options_.inf_to_num().length();
|
|
810
|
+
}
|
|
811
|
+
else if (options_.enable_inf_to_str())
|
|
812
|
+
{
|
|
813
|
+
visit_string(options_.inf_to_str(), semantic_tag::none, context, ec);
|
|
814
|
+
}
|
|
815
|
+
else
|
|
816
|
+
{
|
|
817
|
+
sink_.append(null_constant().data(), null_constant().size());
|
|
818
|
+
column_ += null_constant().size();
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
else
|
|
822
|
+
{
|
|
823
|
+
if (options_.enable_neginf_to_num())
|
|
824
|
+
{
|
|
825
|
+
sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length());
|
|
826
|
+
column_ += options_.neginf_to_num().length();
|
|
827
|
+
}
|
|
828
|
+
else if (options_.enable_neginf_to_str())
|
|
829
|
+
{
|
|
830
|
+
visit_string(options_.neginf_to_str(), semantic_tag::none, context, ec);
|
|
831
|
+
}
|
|
832
|
+
else
|
|
833
|
+
{
|
|
834
|
+
sink_.append(null_constant().data(), null_constant().size());
|
|
835
|
+
column_ += null_constant().size();
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
else
|
|
840
|
+
{
|
|
841
|
+
std::size_t length = fp_(value, sink_);
|
|
842
|
+
column_ += length;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
end_value();
|
|
846
|
+
return true;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
bool visit_int64(int64_t value,
|
|
850
|
+
semantic_tag,
|
|
851
|
+
const ser_context&,
|
|
852
|
+
std::error_code&) override
|
|
853
|
+
{
|
|
854
|
+
if (!stack_.empty())
|
|
855
|
+
{
|
|
856
|
+
if (stack_.back().is_array())
|
|
857
|
+
{
|
|
858
|
+
begin_scalar_value();
|
|
859
|
+
}
|
|
860
|
+
if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
|
|
861
|
+
{
|
|
862
|
+
break_line();
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
std::size_t length = jsoncons::detail::from_integer(value, sink_);
|
|
866
|
+
column_ += length;
|
|
867
|
+
end_value();
|
|
868
|
+
return true;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
bool visit_uint64(uint64_t value,
|
|
872
|
+
semantic_tag,
|
|
873
|
+
const ser_context&,
|
|
874
|
+
std::error_code&) override
|
|
875
|
+
{
|
|
876
|
+
if (!stack_.empty())
|
|
877
|
+
{
|
|
878
|
+
if (stack_.back().is_array())
|
|
879
|
+
{
|
|
880
|
+
begin_scalar_value();
|
|
881
|
+
}
|
|
882
|
+
if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
|
|
883
|
+
{
|
|
884
|
+
break_line();
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
std::size_t length = jsoncons::detail::from_integer(value, sink_);
|
|
888
|
+
column_ += length;
|
|
889
|
+
end_value();
|
|
890
|
+
return true;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
bool visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) override
|
|
894
|
+
{
|
|
895
|
+
if (!stack_.empty())
|
|
896
|
+
{
|
|
897
|
+
if (stack_.back().is_array())
|
|
898
|
+
{
|
|
899
|
+
begin_scalar_value();
|
|
900
|
+
}
|
|
901
|
+
if (!stack_.back().is_multi_line() && column_ >= options_.line_length_limit())
|
|
902
|
+
{
|
|
903
|
+
break_line();
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
if (value)
|
|
908
|
+
{
|
|
909
|
+
sink_.append(true_constant().data(), true_constant().size());
|
|
910
|
+
column_ += true_constant().size();
|
|
911
|
+
}
|
|
912
|
+
else
|
|
913
|
+
{
|
|
914
|
+
sink_.append(false_constant().data(), false_constant().size());
|
|
915
|
+
column_ += false_constant().size();
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
end_value();
|
|
919
|
+
return true;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
void begin_scalar_value()
|
|
923
|
+
{
|
|
924
|
+
if (!stack_.empty())
|
|
925
|
+
{
|
|
926
|
+
if (stack_.back().count() > 0)
|
|
927
|
+
{
|
|
928
|
+
sink_.append(comma_str_.data(),comma_str_.length());
|
|
929
|
+
column_ += comma_str_.length();
|
|
930
|
+
}
|
|
931
|
+
if (stack_.back().is_multi_line() || stack_.back().is_indent_once())
|
|
932
|
+
{
|
|
933
|
+
stack_.back().new_line_after(true);
|
|
934
|
+
new_line();
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
void write_bigint_value(const string_view_type& sv)
|
|
940
|
+
{
|
|
941
|
+
switch (options_.bigint_format())
|
|
942
|
+
{
|
|
943
|
+
case bigint_chars_format::number:
|
|
944
|
+
{
|
|
945
|
+
sink_.append(sv.data(),sv.size());
|
|
946
|
+
column_ += sv.size();
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
case bigint_chars_format::base64:
|
|
950
|
+
{
|
|
951
|
+
bigint n = bigint::from_string(sv.data(), sv.length());
|
|
952
|
+
bool is_neg = n < 0;
|
|
953
|
+
if (is_neg)
|
|
954
|
+
{
|
|
955
|
+
n = - n -1;
|
|
956
|
+
}
|
|
957
|
+
int signum;
|
|
958
|
+
std::vector<uint8_t> v;
|
|
959
|
+
n.write_bytes_be(signum, v);
|
|
960
|
+
|
|
961
|
+
sink_.push_back('\"');
|
|
962
|
+
if (is_neg)
|
|
963
|
+
{
|
|
964
|
+
sink_.push_back('~');
|
|
965
|
+
++column_;
|
|
966
|
+
}
|
|
967
|
+
std::size_t length = encode_base64(v.begin(), v.end(), sink_);
|
|
968
|
+
sink_.push_back('\"');
|
|
969
|
+
column_ += (length+2);
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
case bigint_chars_format::base64url:
|
|
973
|
+
{
|
|
974
|
+
bigint n = bigint::from_string(sv.data(), sv.length());
|
|
975
|
+
bool is_neg = n < 0;
|
|
976
|
+
if (is_neg)
|
|
977
|
+
{
|
|
978
|
+
n = - n -1;
|
|
979
|
+
}
|
|
980
|
+
int signum;
|
|
981
|
+
std::vector<uint8_t> v;
|
|
982
|
+
n.write_bytes_be(signum, v);
|
|
983
|
+
|
|
984
|
+
sink_.push_back('\"');
|
|
985
|
+
if (is_neg)
|
|
986
|
+
{
|
|
987
|
+
sink_.push_back('~');
|
|
988
|
+
++column_;
|
|
989
|
+
}
|
|
990
|
+
std::size_t length = encode_base64url(v.begin(), v.end(), sink_);
|
|
991
|
+
sink_.push_back('\"');
|
|
992
|
+
column_ += (length+2);
|
|
993
|
+
break;
|
|
994
|
+
}
|
|
995
|
+
default:
|
|
996
|
+
{
|
|
997
|
+
sink_.push_back('\"');
|
|
998
|
+
sink_.append(sv.data(),sv.size());
|
|
999
|
+
sink_.push_back('\"');
|
|
1000
|
+
column_ += (sv.size() + 2);
|
|
1001
|
+
break;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
void end_value()
|
|
1007
|
+
{
|
|
1008
|
+
if (!stack_.empty())
|
|
1009
|
+
{
|
|
1010
|
+
stack_.back().increment_count();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
void indent()
|
|
1015
|
+
{
|
|
1016
|
+
indent_amount_ += static_cast<int>(options_.indent_size());
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
void unindent()
|
|
1020
|
+
{
|
|
1021
|
+
indent_amount_ -= static_cast<int>(options_.indent_size());
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
void new_line()
|
|
1025
|
+
{
|
|
1026
|
+
sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length());
|
|
1027
|
+
for (int i = 0; i < indent_amount_; ++i)
|
|
1028
|
+
{
|
|
1029
|
+
sink_.push_back(' ');
|
|
1030
|
+
}
|
|
1031
|
+
column_ = indent_amount_;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
void new_line(std::size_t len)
|
|
1035
|
+
{
|
|
1036
|
+
sink_.append(options_.new_line_chars().data(),options_.new_line_chars().length());
|
|
1037
|
+
for (std::size_t i = 0; i < len; ++i)
|
|
1038
|
+
{
|
|
1039
|
+
sink_.push_back(' ');
|
|
1040
|
+
}
|
|
1041
|
+
column_ = len;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
void break_line()
|
|
1045
|
+
{
|
|
1046
|
+
stack_.back().new_line_after(true);
|
|
1047
|
+
new_line();
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
|
|
1051
|
+
template<class CharT,class Sink=jsoncons::stream_sink<CharT>,class Allocator=std::allocator<char>>
|
|
1052
|
+
class basic_compact_json_encoder final : public basic_json_visitor<CharT>
|
|
1053
|
+
{
|
|
1054
|
+
static const std::array<CharT, 4>& null_constant()
|
|
1055
|
+
{
|
|
1056
|
+
static constexpr std::array<CharT,4> k{'n','u','l','l'};
|
|
1057
|
+
return k;
|
|
1058
|
+
}
|
|
1059
|
+
static const std::array<CharT, 4>& true_constant()
|
|
1060
|
+
{
|
|
1061
|
+
static constexpr std::array<CharT,4> k{'t','r','u','e'};
|
|
1062
|
+
return k;
|
|
1063
|
+
}
|
|
1064
|
+
static const std::array<CharT, 5>& false_constant()
|
|
1065
|
+
{
|
|
1066
|
+
static constexpr std::array<CharT,5> k{'f','a','l','s','e'};
|
|
1067
|
+
return k;
|
|
1068
|
+
}
|
|
1069
|
+
public:
|
|
1070
|
+
using allocator_type = Allocator;
|
|
1071
|
+
using char_type = CharT;
|
|
1072
|
+
using typename basic_json_visitor<CharT>::string_view_type;
|
|
1073
|
+
using sink_type = Sink;
|
|
1074
|
+
using string_type = typename basic_json_encode_options<CharT>::string_type;
|
|
1075
|
+
|
|
1076
|
+
private:
|
|
1077
|
+
enum class container_type {object, array};
|
|
1078
|
+
|
|
1079
|
+
class encoding_context
|
|
1080
|
+
{
|
|
1081
|
+
container_type type_;
|
|
1082
|
+
std::size_t count_;
|
|
1083
|
+
public:
|
|
1084
|
+
encoding_context(container_type type) noexcept
|
|
1085
|
+
: type_(type), count_(0)
|
|
1086
|
+
{
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
std::size_t count() const
|
|
1090
|
+
{
|
|
1091
|
+
return count_;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
void increment_count()
|
|
1095
|
+
{
|
|
1096
|
+
++count_;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
bool is_array() const
|
|
1100
|
+
{
|
|
1101
|
+
return type_ == container_type::array;
|
|
1102
|
+
}
|
|
1103
|
+
};
|
|
1104
|
+
typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<encoding_context> encoding_context_allocator_type;
|
|
1105
|
+
|
|
1106
|
+
Sink sink_;
|
|
1107
|
+
basic_json_encode_options<CharT> options_;
|
|
1108
|
+
jsoncons::detail::write_double fp_;
|
|
1109
|
+
std::vector<encoding_context,encoding_context_allocator_type> stack_;
|
|
1110
|
+
int nesting_depth_;
|
|
1111
|
+
|
|
1112
|
+
// Noncopyable
|
|
1113
|
+
basic_compact_json_encoder(const basic_compact_json_encoder&) = delete;
|
|
1114
|
+
basic_compact_json_encoder& operator=(const basic_compact_json_encoder&) = delete;
|
|
1115
|
+
public:
|
|
1116
|
+
basic_compact_json_encoder(Sink&& sink,
|
|
1117
|
+
const Allocator& alloc = Allocator())
|
|
1118
|
+
: basic_compact_json_encoder(std::forward<Sink>(sink), basic_json_encode_options<CharT>(), alloc)
|
|
1119
|
+
{
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
basic_compact_json_encoder(Sink&& sink,
|
|
1123
|
+
const basic_json_encode_options<CharT>& options,
|
|
1124
|
+
const Allocator& alloc = Allocator())
|
|
1125
|
+
: sink_(std::forward<Sink>(sink)),
|
|
1126
|
+
options_(options),
|
|
1127
|
+
fp_(options.float_format(), options.precision()),
|
|
1128
|
+
stack_(alloc),
|
|
1129
|
+
nesting_depth_(0)
|
|
1130
|
+
{
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
basic_compact_json_encoder(basic_compact_json_encoder&&) = default;
|
|
1134
|
+
basic_compact_json_encoder& operator=(basic_compact_json_encoder&&) = default;
|
|
1135
|
+
|
|
1136
|
+
~basic_compact_json_encoder() noexcept
|
|
1137
|
+
{
|
|
1138
|
+
JSONCONS_TRY
|
|
1139
|
+
{
|
|
1140
|
+
sink_.flush();
|
|
1141
|
+
}
|
|
1142
|
+
JSONCONS_CATCH(...)
|
|
1143
|
+
{
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
void reset()
|
|
1148
|
+
{
|
|
1149
|
+
stack_.clear();
|
|
1150
|
+
nesting_depth_ = 0;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
void reset(Sink&& sink)
|
|
1154
|
+
{
|
|
1155
|
+
sink_ = std::move(sink);
|
|
1156
|
+
reset();
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
private:
|
|
1160
|
+
// Implementing methods
|
|
1161
|
+
void visit_flush() override
|
|
1162
|
+
{
|
|
1163
|
+
sink_.flush();
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override
|
|
1167
|
+
{
|
|
1168
|
+
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
|
|
1169
|
+
{
|
|
1170
|
+
ec = json_errc::max_nesting_depth_exceeded;
|
|
1171
|
+
return false;
|
|
1172
|
+
}
|
|
1173
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1174
|
+
{
|
|
1175
|
+
sink_.push_back(',');
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
stack_.emplace_back(container_type::object);
|
|
1179
|
+
sink_.push_back('{');
|
|
1180
|
+
return true;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
bool visit_end_object(const ser_context&, std::error_code&) override
|
|
1184
|
+
{
|
|
1185
|
+
JSONCONS_ASSERT(!stack_.empty());
|
|
1186
|
+
--nesting_depth_;
|
|
1187
|
+
|
|
1188
|
+
stack_.pop_back();
|
|
1189
|
+
sink_.push_back('}');
|
|
1190
|
+
|
|
1191
|
+
if (!stack_.empty())
|
|
1192
|
+
{
|
|
1193
|
+
stack_.back().increment_count();
|
|
1194
|
+
}
|
|
1195
|
+
return true;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override
|
|
1200
|
+
{
|
|
1201
|
+
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
|
|
1202
|
+
{
|
|
1203
|
+
ec = json_errc::max_nesting_depth_exceeded;
|
|
1204
|
+
return false;
|
|
1205
|
+
}
|
|
1206
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1207
|
+
{
|
|
1208
|
+
sink_.push_back(',');
|
|
1209
|
+
}
|
|
1210
|
+
stack_.emplace_back(container_type::array);
|
|
1211
|
+
sink_.push_back('[');
|
|
1212
|
+
return true;
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
bool visit_end_array(const ser_context&, std::error_code&) override
|
|
1216
|
+
{
|
|
1217
|
+
JSONCONS_ASSERT(!stack_.empty());
|
|
1218
|
+
--nesting_depth_;
|
|
1219
|
+
|
|
1220
|
+
stack_.pop_back();
|
|
1221
|
+
sink_.push_back(']');
|
|
1222
|
+
if (!stack_.empty())
|
|
1223
|
+
{
|
|
1224
|
+
stack_.back().increment_count();
|
|
1225
|
+
}
|
|
1226
|
+
return true;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
|
|
1230
|
+
{
|
|
1231
|
+
if (!stack_.empty() && stack_.back().count() > 0)
|
|
1232
|
+
{
|
|
1233
|
+
sink_.push_back(',');
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
sink_.push_back('\"');
|
|
1237
|
+
jsoncons::detail::escape_string(name.data(), name.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
|
|
1238
|
+
sink_.push_back('\"');
|
|
1239
|
+
sink_.push_back(':');
|
|
1240
|
+
return true;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
bool visit_null(semantic_tag, const ser_context&, std::error_code&) override
|
|
1244
|
+
{
|
|
1245
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1246
|
+
{
|
|
1247
|
+
sink_.push_back(',');
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
sink_.append(null_constant().data(), null_constant().size());
|
|
1251
|
+
|
|
1252
|
+
if (!stack_.empty())
|
|
1253
|
+
{
|
|
1254
|
+
stack_.back().increment_count();
|
|
1255
|
+
}
|
|
1256
|
+
return true;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
void write_bigint_value(const string_view_type& sv)
|
|
1260
|
+
{
|
|
1261
|
+
switch (options_.bigint_format())
|
|
1262
|
+
{
|
|
1263
|
+
case bigint_chars_format::number:
|
|
1264
|
+
{
|
|
1265
|
+
sink_.append(sv.data(),sv.size());
|
|
1266
|
+
break;
|
|
1267
|
+
}
|
|
1268
|
+
case bigint_chars_format::base64:
|
|
1269
|
+
{
|
|
1270
|
+
bigint n = bigint::from_string(sv.data(), sv.length());
|
|
1271
|
+
bool is_neg = n < 0;
|
|
1272
|
+
if (is_neg)
|
|
1273
|
+
{
|
|
1274
|
+
n = - n -1;
|
|
1275
|
+
}
|
|
1276
|
+
int signum;
|
|
1277
|
+
std::vector<uint8_t> v;
|
|
1278
|
+
n.write_bytes_be(signum, v);
|
|
1279
|
+
|
|
1280
|
+
sink_.push_back('\"');
|
|
1281
|
+
if (is_neg)
|
|
1282
|
+
{
|
|
1283
|
+
sink_.push_back('~');
|
|
1284
|
+
}
|
|
1285
|
+
encode_base64(v.begin(), v.end(), sink_);
|
|
1286
|
+
sink_.push_back('\"');
|
|
1287
|
+
break;
|
|
1288
|
+
}
|
|
1289
|
+
case bigint_chars_format::base64url:
|
|
1290
|
+
{
|
|
1291
|
+
bigint n = bigint::from_string(sv.data(), sv.length());
|
|
1292
|
+
bool is_neg = n < 0;
|
|
1293
|
+
if (is_neg)
|
|
1294
|
+
{
|
|
1295
|
+
n = - n -1;
|
|
1296
|
+
}
|
|
1297
|
+
int signum;
|
|
1298
|
+
std::vector<uint8_t> v;
|
|
1299
|
+
n.write_bytes_be(signum, v);
|
|
1300
|
+
|
|
1301
|
+
sink_.push_back('\"');
|
|
1302
|
+
if (is_neg)
|
|
1303
|
+
{
|
|
1304
|
+
sink_.push_back('~');
|
|
1305
|
+
}
|
|
1306
|
+
encode_base64url(v.begin(), v.end(), sink_);
|
|
1307
|
+
sink_.push_back('\"');
|
|
1308
|
+
break;
|
|
1309
|
+
}
|
|
1310
|
+
default:
|
|
1311
|
+
{
|
|
1312
|
+
sink_.push_back('\"');
|
|
1313
|
+
sink_.append(sv.data(),sv.size());
|
|
1314
|
+
sink_.push_back('\"');
|
|
1315
|
+
break;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) override
|
|
1321
|
+
{
|
|
1322
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1323
|
+
{
|
|
1324
|
+
sink_.push_back(',');
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
switch (tag)
|
|
1328
|
+
{
|
|
1329
|
+
case semantic_tag::bigint:
|
|
1330
|
+
write_bigint_value(sv);
|
|
1331
|
+
break;
|
|
1332
|
+
default:
|
|
1333
|
+
{
|
|
1334
|
+
sink_.push_back('\"');
|
|
1335
|
+
jsoncons::detail::escape_string(sv.data(), sv.length(),options_.escape_all_non_ascii(),options_.escape_solidus(),sink_);
|
|
1336
|
+
sink_.push_back('\"');
|
|
1337
|
+
break;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
if (!stack_.empty())
|
|
1342
|
+
{
|
|
1343
|
+
stack_.back().increment_count();
|
|
1344
|
+
}
|
|
1345
|
+
return true;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
bool visit_byte_string(const byte_string_view& b,
|
|
1349
|
+
semantic_tag tag,
|
|
1350
|
+
const ser_context&,
|
|
1351
|
+
std::error_code&) override
|
|
1352
|
+
{
|
|
1353
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1354
|
+
{
|
|
1355
|
+
sink_.push_back(',');
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
byte_string_chars_format encoding_hint;
|
|
1359
|
+
switch (tag)
|
|
1360
|
+
{
|
|
1361
|
+
case semantic_tag::base16:
|
|
1362
|
+
encoding_hint = byte_string_chars_format::base16;
|
|
1363
|
+
break;
|
|
1364
|
+
case semantic_tag::base64:
|
|
1365
|
+
encoding_hint = byte_string_chars_format::base64;
|
|
1366
|
+
break;
|
|
1367
|
+
case semantic_tag::base64url:
|
|
1368
|
+
encoding_hint = byte_string_chars_format::base64url;
|
|
1369
|
+
break;
|
|
1370
|
+
default:
|
|
1371
|
+
encoding_hint = byte_string_chars_format::none;
|
|
1372
|
+
break;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(options_.byte_string_format(),
|
|
1376
|
+
encoding_hint,
|
|
1377
|
+
byte_string_chars_format::base64url);
|
|
1378
|
+
switch (format)
|
|
1379
|
+
{
|
|
1380
|
+
case byte_string_chars_format::base16:
|
|
1381
|
+
{
|
|
1382
|
+
sink_.push_back('\"');
|
|
1383
|
+
encode_base16(b.begin(),b.end(),sink_);
|
|
1384
|
+
sink_.push_back('\"');
|
|
1385
|
+
break;
|
|
1386
|
+
}
|
|
1387
|
+
case byte_string_chars_format::base64:
|
|
1388
|
+
{
|
|
1389
|
+
sink_.push_back('\"');
|
|
1390
|
+
encode_base64(b.begin(), b.end(), sink_);
|
|
1391
|
+
sink_.push_back('\"');
|
|
1392
|
+
break;
|
|
1393
|
+
}
|
|
1394
|
+
case byte_string_chars_format::base64url:
|
|
1395
|
+
{
|
|
1396
|
+
sink_.push_back('\"');
|
|
1397
|
+
encode_base64url(b.begin(),b.end(),sink_);
|
|
1398
|
+
sink_.push_back('\"');
|
|
1399
|
+
break;
|
|
1400
|
+
}
|
|
1401
|
+
default:
|
|
1402
|
+
{
|
|
1403
|
+
JSONCONS_UNREACHABLE();
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
if (!stack_.empty())
|
|
1408
|
+
{
|
|
1409
|
+
stack_.back().increment_count();
|
|
1410
|
+
}
|
|
1411
|
+
return true;
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
bool visit_double(double value,
|
|
1415
|
+
semantic_tag,
|
|
1416
|
+
const ser_context& context,
|
|
1417
|
+
std::error_code& ec) override
|
|
1418
|
+
{
|
|
1419
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1420
|
+
{
|
|
1421
|
+
sink_.push_back(',');
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
if (JSONCONS_UNLIKELY(!std::isfinite(value)))
|
|
1425
|
+
{
|
|
1426
|
+
if ((std::isnan)(value))
|
|
1427
|
+
{
|
|
1428
|
+
if (options_.enable_nan_to_num())
|
|
1429
|
+
{
|
|
1430
|
+
sink_.append(options_.nan_to_num().data(), options_.nan_to_num().length());
|
|
1431
|
+
}
|
|
1432
|
+
else if (options_.enable_nan_to_str())
|
|
1433
|
+
{
|
|
1434
|
+
visit_string(options_.nan_to_str(), semantic_tag::none, context, ec);
|
|
1435
|
+
}
|
|
1436
|
+
else
|
|
1437
|
+
{
|
|
1438
|
+
sink_.append(null_constant().data(), null_constant().size());
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
else if (value == std::numeric_limits<double>::infinity())
|
|
1442
|
+
{
|
|
1443
|
+
if (options_.enable_inf_to_num())
|
|
1444
|
+
{
|
|
1445
|
+
sink_.append(options_.inf_to_num().data(), options_.inf_to_num().length());
|
|
1446
|
+
}
|
|
1447
|
+
else if (options_.enable_inf_to_str())
|
|
1448
|
+
{
|
|
1449
|
+
visit_string(options_.inf_to_str(), semantic_tag::none, context, ec);
|
|
1450
|
+
}
|
|
1451
|
+
else
|
|
1452
|
+
{
|
|
1453
|
+
sink_.append(null_constant().data(), null_constant().size());
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
else
|
|
1457
|
+
{
|
|
1458
|
+
if (options_.enable_neginf_to_num())
|
|
1459
|
+
{
|
|
1460
|
+
sink_.append(options_.neginf_to_num().data(), options_.neginf_to_num().length());
|
|
1461
|
+
}
|
|
1462
|
+
else if (options_.enable_neginf_to_str())
|
|
1463
|
+
{
|
|
1464
|
+
visit_string(options_.neginf_to_str(), semantic_tag::none, context, ec);
|
|
1465
|
+
}
|
|
1466
|
+
else
|
|
1467
|
+
{
|
|
1468
|
+
sink_.append(null_constant().data(), null_constant().size());
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
else
|
|
1473
|
+
{
|
|
1474
|
+
fp_(value, sink_);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
if (!stack_.empty())
|
|
1478
|
+
{
|
|
1479
|
+
stack_.back().increment_count();
|
|
1480
|
+
}
|
|
1481
|
+
return true;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
bool visit_int64(int64_t value,
|
|
1485
|
+
semantic_tag,
|
|
1486
|
+
const ser_context&,
|
|
1487
|
+
std::error_code&) override
|
|
1488
|
+
{
|
|
1489
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1490
|
+
{
|
|
1491
|
+
sink_.push_back(',');
|
|
1492
|
+
}
|
|
1493
|
+
jsoncons::detail::from_integer(value, sink_);
|
|
1494
|
+
if (!stack_.empty())
|
|
1495
|
+
{
|
|
1496
|
+
stack_.back().increment_count();
|
|
1497
|
+
}
|
|
1498
|
+
return true;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
bool visit_uint64(uint64_t value,
|
|
1502
|
+
semantic_tag,
|
|
1503
|
+
const ser_context&,
|
|
1504
|
+
std::error_code&) override
|
|
1505
|
+
{
|
|
1506
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1507
|
+
{
|
|
1508
|
+
sink_.push_back(',');
|
|
1509
|
+
}
|
|
1510
|
+
jsoncons::detail::from_integer(value, sink_);
|
|
1511
|
+
if (!stack_.empty())
|
|
1512
|
+
{
|
|
1513
|
+
stack_.back().increment_count();
|
|
1514
|
+
}
|
|
1515
|
+
return true;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
bool visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) override
|
|
1519
|
+
{
|
|
1520
|
+
if (!stack_.empty() && stack_.back().is_array() && stack_.back().count() > 0)
|
|
1521
|
+
{
|
|
1522
|
+
sink_.push_back(',');
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
if (value)
|
|
1526
|
+
{
|
|
1527
|
+
sink_.append(true_constant().data(), true_constant().size());
|
|
1528
|
+
}
|
|
1529
|
+
else
|
|
1530
|
+
{
|
|
1531
|
+
sink_.append(false_constant().data(), false_constant().size());
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
if (!stack_.empty())
|
|
1535
|
+
{
|
|
1536
|
+
stack_.back().increment_count();
|
|
1537
|
+
}
|
|
1538
|
+
return true;
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
using json_stream_encoder = basic_json_encoder<char,jsoncons::stream_sink<char>>;
|
|
1543
|
+
using wjson_stream_encoder = basic_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>>;
|
|
1544
|
+
using compact_json_stream_encoder = basic_compact_json_encoder<char,jsoncons::stream_sink<char>>;
|
|
1545
|
+
using compact_wjson_stream_encoder = basic_compact_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>>;
|
|
1546
|
+
|
|
1547
|
+
using json_string_encoder = basic_json_encoder<char,jsoncons::string_sink<std::string>>;
|
|
1548
|
+
using wjson_string_encoder = basic_json_encoder<wchar_t,jsoncons::string_sink<std::wstring>>;
|
|
1549
|
+
using compact_json_string_encoder = basic_compact_json_encoder<char,jsoncons::string_sink<std::string>>;
|
|
1550
|
+
using compact_wjson_string_encoder = basic_compact_json_encoder<wchar_t,jsoncons::string_sink<std::wstring>>;
|
|
1551
|
+
|
|
1552
|
+
#if !defined(JSONCONS_NO_DEPRECATED)
|
|
1553
|
+
template<class CharT,class Sink=jsoncons::stream_sink<CharT>>
|
|
1554
|
+
using basic_json_serializer = basic_json_encoder<CharT,Sink>;
|
|
1555
|
+
|
|
1556
|
+
template<class CharT,class Sink=jsoncons::stream_sink<CharT>>
|
|
1557
|
+
using basic_json_compressed_serializer = basic_compact_json_encoder<CharT,Sink>;
|
|
1558
|
+
|
|
1559
|
+
template<class CharT,class Sink=jsoncons::stream_sink<CharT>>
|
|
1560
|
+
using basic_json_compressed_encoder = basic_compact_json_encoder<CharT,Sink>;
|
|
1561
|
+
|
|
1562
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_json_stream_encoder") typedef basic_compact_json_encoder<char,jsoncons::stream_sink<char>> json_compressed_stream_encoder;
|
|
1563
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_wjson_stream_encoder")typedef basic_compact_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>> wjson_compressed_stream_encoder;
|
|
1564
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_json_string_encoder") typedef basic_compact_json_encoder<char,jsoncons::string_sink<char>> json_compressed_string_encoder;
|
|
1565
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_wjson_string_encoder")typedef basic_compact_json_encoder<wchar_t,jsoncons::string_sink<wchar_t>> wjson_compressed_string_encoder;
|
|
1566
|
+
|
|
1567
|
+
JSONCONS_DEPRECATED_MSG("Instead, use json_stream_encoder") typedef json_stream_encoder json_encoder;
|
|
1568
|
+
JSONCONS_DEPRECATED_MSG("Instead, use wjson_stream_encoder") typedef wjson_stream_encoder wjson_encoder;
|
|
1569
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_json_stream_encoder") typedef compact_json_stream_encoder compact_json_encoder;
|
|
1570
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_wjson_stream_encoder") typedef compact_wjson_stream_encoder wcompact_json_encoder;
|
|
1571
|
+
|
|
1572
|
+
JSONCONS_DEPRECATED_MSG("Instead, use json_stream_encoder") typedef basic_json_encoder<char,jsoncons::stream_sink<char>> json_serializer;
|
|
1573
|
+
JSONCONS_DEPRECATED_MSG("Instead, use wjson_stream_encoder") typedef basic_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>> wjson_serializer;
|
|
1574
|
+
|
|
1575
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_json_stream_encoder") typedef basic_compact_json_encoder<char,jsoncons::stream_sink<char>> json_compressed_serializer;
|
|
1576
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_wjson_stream_encoder") typedef basic_compact_json_encoder<wchar_t,jsoncons::stream_sink<wchar_t>> wjson_compressed_serializer;
|
|
1577
|
+
|
|
1578
|
+
JSONCONS_DEPRECATED_MSG("Instead, use json_string_encoder") typedef basic_json_encoder<char,jsoncons::string_sink<std::string>> json_string_serializer;
|
|
1579
|
+
JSONCONS_DEPRECATED_MSG("Instead, use wjson_string_encoder") typedef basic_json_encoder<wchar_t,jsoncons::string_sink<std::wstring>> wjson_string_serializer;
|
|
1580
|
+
|
|
1581
|
+
JSONCONS_DEPRECATED_MSG("Instead, use compact_json_string_encoder") typedef basic_compact_json_encoder<char,jsoncons::string_sink<std::string>> json_compressed_string_serializer;
|
|
1582
|
+
JSONCONS_DEPRECATED_MSG("Instead, use wcompact_json_string_encoder") typedef basic_compact_json_encoder<wchar_t,jsoncons::string_sink<std::wstring>> wjson_compressed_string_serializer;
|
|
1583
|
+
#endif
|
|
1584
|
+
|
|
1585
|
+
} // namespace jsoncons
|
|
1586
|
+
|
|
1587
|
+
#endif
|