조성현

중간저장4

Showing 46 changed files with 13937 additions and 67 deletions
...@@ -86,6 +86,9 @@ ...@@ -86,6 +86,9 @@
86 <ClCompile Include="curl_processor.cpp"> 86 <ClCompile Include="curl_processor.cpp">
87 <Filter>Source Files</Filter> 87 <Filter>Source Files</Filter>
88 </ClCompile> 88 </ClCompile>
89 + <ClCompile Include="bibtex_processor.cpp">
90 + <Filter>Source Files</Filter>
91 + </ClCompile>
89 </ItemGroup> 92 </ItemGroup>
90 <ItemGroup> 93 <ItemGroup>
91 <CustomBuild Include="PaperGraphWidget.h"> 94 <CustomBuild Include="PaperGraphWidget.h">
...@@ -117,5 +120,8 @@ ...@@ -117,5 +120,8 @@
117 <ClInclude Include="curl_processor.h"> 120 <ClInclude Include="curl_processor.h">
118 <Filter>Header Files</Filter> 121 <Filter>Header Files</Filter>
119 </ClInclude> 122 </ClInclude>
123 + <ClInclude Include="bibtex_processor.h">
124 + <Filter>Header Files</Filter>
125 + </ClInclude>
120 </ItemGroup> 126 </ItemGroup>
121 </Project> 127 </Project>
...\ No newline at end of file ...\ No newline at end of file
......
1 +#include "stdafx.h"
2 +#include "bibtex_processor.h"
3 +
4 +//////////////////////////////////////////////////////////////////
5 +// constructor, destructor
6 +//////////////////////////////////////////////////////////////////
7 +bibtex_processor::bibtex_processor() {
8 +}
9 +
10 +bibtex_processor::~bibtex_processor() {
11 +}
12 +
13 +
14 +//////////////////////////////////////////////////////////////////
15 +// methods
16 +//////////////////////////////////////////////////////////////////
17 +void bibtex_processor::read(const std::string& bibtex_string) {
18 + bibtex::read(bibtex_string, entry);
19 +}
20 +
21 +bool bibtex_processor::get_value(const std::string& field_name, std::string& return_val) {
22 + if (entry.fields.empty()) return false;
23 +
24 + bool found = false;
25 + for (auto& field: entry.fields) {
26 + if (field.first == field_name) {
27 + found = true;
28 + return_val = field.second.front();
29 + break;
30 + }
31 + }
32 + return found;
33 +}
...\ No newline at end of file ...\ No newline at end of file
1 +#pragma once
2 +#include "stdafx.h"
3 +
4 +class bibtex_processor
5 +{
6 + //private var
7 +private:
8 + bibtex::BibTeXEntry entry;
9 +
10 + //constructor, destructor
11 +public:
12 + bibtex_processor();
13 + ~bibtex_processor();
14 +
15 + //methods
16 +public:
17 + void read(const std::string& bibtex_string);
18 + bool get_value(const std::string& field_name, std::string& return_val);
19 +};
20 +
...@@ -5,18 +5,18 @@ ...@@ -5,18 +5,18 @@
5 ////////////////////////////////////////////////////////////////// 5 //////////////////////////////////////////////////////////////////
6 // private func 6 // private func
7 ////////////////////////////////////////////////////////////////// 7 //////////////////////////////////////////////////////////////////
8 -size_t curl_processor::write_callback(void *contents, size_t size, size_t nmemb, void *userp) { 8 +//size_t curl_processor::write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
9 - //copy ptr 9 +// //copy ptr
10 - std::string* p_str = (std::string*)userp; 10 +// std::string* p_str = (std::string*)userp;
11 - 11 +//
12 - //clear 12 +// //clear
13 - if (!p_str->empty()) 13 +// if (!p_str->empty())
14 - p_str->clear(); 14 +// p_str->clear();
15 - 15 +//
16 - //write 16 +// //write
17 - p_str->append((char*)contents, size*nmemb); 17 +// p_str->append((char*)contents, size*nmemb);
18 - return size*nmemb; 18 +// return size*nmemb;
19 -} 19 +//}
20 20
21 21
22 ////////////////////////////////////////////////////////////////// 22 //////////////////////////////////////////////////////////////////
...@@ -29,7 +29,7 @@ curl_processor::curl_processor() { ...@@ -29,7 +29,7 @@ curl_processor::curl_processor() {
29 } 29 }
30 30
31 //set curl option 31 //set curl option
32 - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, this->write_callback); 32 + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
33 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result_buffer); 33 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result_buffer);
34 } 34 }
35 35
......
1 -#ifndef CURL_PROCESSOR_H 1 +#pragma once
2 -#define CURL_PROCESSOR_H 2 +#include "stdafx.h"
3 -
4 -#include <stdafx.h>
5 3
6 class curl_processor 4 class curl_processor
7 { 5 {
...@@ -11,10 +9,6 @@ private: ...@@ -11,10 +9,6 @@ private:
11 CURLcode res; 9 CURLcode res;
12 std::string result_buffer; 10 std::string result_buffer;
13 11
14 - //private func
15 -private:
16 - size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp);
17 -
18 //constructor, destructor 12 //constructor, destructor
19 public: 13 public:
20 curl_processor(); 14 curl_processor();
...@@ -27,4 +21,3 @@ public: ...@@ -27,4 +21,3 @@ public:
27 bool perform(); 21 bool perform();
28 }; 22 };
29 23
30 -#endif // CURL_PROCESSOR_H
...\ No newline at end of file ...\ No newline at end of file
......
1 +// Copyright (c) 2012 Sergiu Dotenco
2 +//
3 +// Permission is hereby granted, free of charge, to any person obtaining a copy
4 +// of this software and associated documentation files (the "Software"), to deal
5 +// in the Software without restriction, including without limitation the rights
6 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 +// copies of the Software, and to permit persons to whom the Software is
8 +// furnished to do so, subject to the following conditions:
9 +//
10 +// The above copyright notice and this permission notice shall be included in
11 +// all copies or substantial portions of the Software.
12 +//
13 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 +// SOFTWARE.
20 +
21 +/**
22 + * @brief BibTeX entry.
23 + * @file bibtexentry.hpp
24 + * @author Sergiu Dotenco
25 + * @version 0.1
26 + */
27 +
28 +#ifndef BIBTEXENTRY_HPP
29 +#define BIBTEXENTRY_HPP
30 +
31 +#pragma once
32 +
33 +#include <string>
34 +#include <utility>
35 +#include <vector>
36 +
37 +#include <boost/fusion/include/adapt_struct.hpp>
38 +#include <boost/fusion/include/std_pair.hpp>
39 +#include <boost/operators.hpp>
40 +#include <boost/optional.hpp>
41 +#include <boost/spirit/include/qi.hpp>
42 +#include <boost/typeof/typeof.hpp>
43 +
44 +#ifndef BOOST_SPIRIT_AUTO
45 +#define BOOST_SPIRIT_AUTO(domain_, name, expr) \
46 + typedef boost::proto::result_of:: \
47 + deep_copy<BOOST_TYPEOF(expr)>::type name##_expr_type; \
48 + BOOST_SPIRIT_ASSERT_MATCH( \
49 + boost::spirit::domain_::domain, name##_expr_type); \
50 + BOOST_AUTO(const name, boost::proto::deep_copy(expr));
51 +#endif // BOOST_SPIRIT_AUTO
52 +
53 +namespace bibtex {
54 +
55 +namespace detail {
56 +
57 +namespace encoding = boost::spirit::standard_wide;
58 +
59 +} // namespace detail
60 +
61 +typedef std::vector<std::string> ValueVector;
62 +typedef std::pair<std::string, ValueVector> KeyValue;
63 +typedef std::vector<KeyValue> KeyValueVector;
64 +typedef detail::encoding::space_type Space;
65 +
66 +BOOST_SPIRIT_AUTO(qi, space, detail::encoding::space |
67 + '%' >> *(boost::spirit::qi::char_ - boost::spirit::qi::eol)
68 + >> boost::spirit::qi::eol)
69 +
70 +/**
71 + * @brief Single BibTeX entry.
72 + */
73 +struct BibTeXEntry
74 + : boost::equality_comparable<BibTeXEntry>
75 +{
76 + //! Entry's tag.
77 + std::string tag;
78 + //! Entry's optional key.
79 + boost::optional<std::string> key;
80 + //! Entry's key/value pairs.
81 + KeyValueVector fields;
82 +};
83 +
84 +inline bool operator==(const BibTeXEntry& lhs, const BibTeXEntry& rhs)
85 +{
86 + return lhs.tag == rhs.tag && lhs.tag == rhs.tag &&
87 + lhs.fields == rhs.fields;
88 +}
89 +
90 +} // namespace bibtex
91 +
92 +BOOST_FUSION_ADAPT_STRUCT(
93 + bibtex::BibTeXEntry,
94 + (std::string, tag)
95 + (boost::optional<std::string>, key)
96 + (bibtex::KeyValueVector, fields)
97 +)
98 +
99 +#endif // BIBTEXENTRY_HPP
1 +// Copyright (c) 2012 Sergiu Dotenco
2 +//
3 +// Permission is hereby granted, free of charge, to any person obtaining a copy
4 +// of this software and associated documentation files (the "Software"), to deal
5 +// in the Software without restriction, including without limitation the rights
6 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 +// copies of the Software, and to permit persons to whom the Software is
8 +// furnished to do so, subject to the following conditions:
9 +//
10 +// The above copyright notice and this permission notice shall be included in
11 +// all copies or substantial portions of the Software.
12 +//
13 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 +// SOFTWARE.
20 +
21 +/**
22 + * @brief Boost.Spirit based BibTeX parser.
23 + * @file bibtexreader.hpp
24 + * @author Sergiu Dotenco
25 + * @version 0.1
26 + */
27 +
28 +#ifndef BIBTEXREADER_HPP
29 +#define BIBTEXREADER_HPP
30 +
31 +#pragma once
32 +
33 +#include <istream>
34 +#include <string>
35 +
36 +#include <boost/fusion/include/vector.hpp>
37 +#include <boost/io/ios_state.hpp>
38 +#include <boost/mpl/and.hpp>
39 +#include <boost/range.hpp>
40 +#include <boost/spirit/include/phoenix.hpp>
41 +#include <boost/spirit/include/support_istream_iterator.hpp>
42 +#include <boost/utility/enable_if.hpp>
43 +
44 +#include "bibtexentry.hpp"
45 +
46 +namespace bibtex {
47 +
48 +/**
49 + * @brief Single BibTeX entry reader.
50 + *
51 + * @tparam ForwardIterator Input sequence iterator type.
52 + * @tparam Skipper Skipper type.
53 + */
54 +template <class ForwardIterator, class Skipper>
55 +class BibTeXReader
56 + : public boost::spirit::qi::grammar<ForwardIterator, BibTeXEntry(), Skipper>
57 +{
58 +public:
59 + BibTeXReader()
60 + : BibTeXReader::base_type(start_, "single BibTeX entry")
61 + {
62 + using namespace boost::spirit;
63 + namespace ph = boost::phoenix;
64 + namespace sn = detail::encoding;
65 +
66 + escapedBrace.add
67 + ("\\{", '{')
68 + ("\\}", '}')
69 + ;
70 + escapedQuote.add
71 + ("\\\"", '"')
72 + ;
73 +
74 + tag_ = +detail::encoding::alnum;
75 + entryKey_ = qi::lexeme[+(~qi::char_(',') - sn::space)];
76 + key_ = qi::lexeme[+(~qi::char_("=,})") - sn::space)];
77 +
78 + escapedText_
79 + = !qi::lit('{') >> +(escapedBrace | ~qi::char_("{}"))
80 + ;
81 +
82 + quoteText_
83 + = +(escapedQuote | ~qi::char_("\"{}"))
84 + ;
85 +
86 + innerBraceText_
87 + %=
88 + qi::as_string
89 + [
90 + qi::char_('{')
91 + >>
92 + *(innerBraceText_ | escapedText_)
93 + >>
94 + qi::char_('}')
95 + ]
96 + |
97 + escapedText_
98 + ;
99 +
100 + innerQuoteText_
101 + %=
102 + qi::as_string
103 + [
104 + qi::char_('{')
105 + >>
106 + *(innerQuoteText_ | escapedText_)
107 + >>
108 + qi::char_('}')
109 + ]
110 + |
111 + quoteText_
112 + ;
113 +
114 + quoted_
115 + = qi::lexeme
116 + [
117 + ( '"' >> *innerQuoteText_ >> '"' )
118 + |
119 + ( '{' >> *innerBraceText_ >> '}' )
120 + ]
121 + [
122 + _val = ph::accumulate(boost::spirit::_1, ph::construct<std::string>())
123 + ]
124 + ;
125 +
126 + value_
127 + = quoted_
128 + | +~qi::char_(",})#")
129 + ;
130 +
131 + values_
132 + = value_ % '#'
133 + ;
134 +
135 + field_
136 + = key_ >> '=' >> values_
137 + ;
138 +
139 + fields_ = -(field_ % ',');
140 +
141 + body_
142 + = -entryKey_ >> ',' // tolerate an empty key
143 + >> fields_
144 + >> -qi::lit(',') // accept a trailing comma
145 + ;
146 +
147 + generic_
148 + =
149 + '@' >> tag_
150 + [
151 + ph::at_c<0>(_val) = boost::spirit::_1
152 + ]
153 + >>
154 + (
155 + ('{' >> body_ >> '}')
156 + |
157 + ('(' >> body_ >> ')')
158 + )
159 + [
160 + ph::at_c<1>(_val) = ph::at_c<0>(boost::spirit::_1),
161 + ph::at_c<2>(_val) = ph::at_c<1>(boost::spirit::_1)
162 + ]
163 + ;
164 +
165 + string_
166 + =
167 + '@' >> sn::no_case
168 + [
169 + qi::string("string")
170 + [
171 + ph::at_c<0>(_val) = boost::spirit::_1
172 + ]
173 + ]
174 + >>
175 + (
176 + ('{' >> field_ >> '}')
177 + |
178 + ('(' >> field_ >> ')')
179 + )
180 + [
181 + ph::assign(ph::bind(&BibTeXEntry::fields, _val), 1, boost::spirit::_1)
182 + ]
183 + ;
184 +
185 + simple_
186 + =
187 + '@' >> sn::no_case
188 + [
189 + (
190 + sn::string("comment")
191 + |
192 + sn::string("include")
193 + |
194 + sn::string("preamble")
195 + )
196 + [
197 + ph::at_c<0>(_val) = boost::spirit::_1
198 + ]
199 + ]
200 + >>
201 + (
202 + ('{' >> values_ >> '}')
203 + |
204 + ('(' >> values_ >> ')')
205 + )
206 + [
207 + ph::assign(ph::bind(&BibTeXEntry::fields, _val), 1,
208 + ph::construct<KeyValue>
209 + (ph::construct<KeyValue::first_type>(), boost::spirit::_1))
210 + ]
211 + ;
212 +
213 + entry_
214 + = string_
215 + | simple_
216 + | generic_
217 + ;
218 +
219 + junk_
220 + = *~qi::lit('@')
221 + ;
222 +
223 + start_
224 + = junk_ >> entry_
225 + ;
226 + }
227 +
228 +private:
229 + typedef boost::spirit::qi::rule<ForwardIterator, std::string(), Skipper>
230 + StringRule;
231 + typedef boost::spirit::qi::rule<ForwardIterator, std::string()>
232 + SimpleStringRule;
233 +
234 + boost::spirit::qi::rule<ForwardIterator, BibTeXEntry(), Skipper> generic_;
235 + boost::spirit::qi::rule<ForwardIterator, BibTeXEntry(), Skipper> include_;
236 + boost::spirit::qi::rule<ForwardIterator, BibTeXEntry(), Skipper> simple_;
237 + boost::spirit::qi::rule<ForwardIterator, BibTeXEntry(), Skipper> start_;
238 + boost::spirit::qi::rule<ForwardIterator, BibTeXEntry(), Skipper> string_;
239 + boost::spirit::qi::rule<ForwardIterator, BibTeXEntry(), Skipper> entry_;
240 + boost::spirit::qi::rule<ForwardIterator, ValueVector(), Skipper> values_;
241 + boost::spirit::qi::rule<ForwardIterator, Skipper> junk_;
242 + boost::spirit::qi::rule<ForwardIterator,
243 + boost::fusion::vector<boost::optional<std::string>,
244 + KeyValueVector>(), Skipper> body_;
245 + boost::spirit::qi::rule<ForwardIterator, KeyValue(), Skipper> field_;
246 + boost::spirit::qi::rule<ForwardIterator, KeyValueVector(), Skipper>
247 + fields_;
248 + boost::spirit::qi::symbols<char, char> escapedBrace;
249 + boost::spirit::qi::symbols<char, char> escapedQuote;
250 + StringRule quoted_;
251 + StringRule entryKey_;
252 + StringRule key_;
253 + StringRule tag_;
254 + StringRule value_;
255 + SimpleStringRule innerBraceText_;
256 + SimpleStringRule escapedText_;
257 + SimpleStringRule innerQuoteText_;
258 + SimpleStringRule quoteText_;
259 +};
260 +
261 +template<class ForwardIterator, class Skipper>
262 +inline bool read(ForwardIterator first, ForwardIterator last, Skipper& skipper,
263 + BibTeXEntry& entry)
264 +{
265 + BibTeXReader<ForwardIterator, Skipper> parser;
266 + return boost::spirit::qi::phrase_parse(first, last, parser, skipper, entry);
267 +}
268 +
269 +template<class ForwardIterator, class Skipper, class Container>
270 +inline bool read(ForwardIterator first, ForwardIterator last, Skipper& skipper,
271 + Container& entries, boost::enable_if<boost::is_same<
272 + typename Container::value_type, BibTeXEntry> >* /*dummy*/ = NULL)
273 +{
274 + BibTeXReader<ForwardIterator, Skipper> parser;
275 + return boost::spirit::qi::phrase_parse(first, last, *parser, skipper,
276 + entries);
277 +}
278 +
279 +template<class ForwardRange, class Skipper>
280 +inline bool read(const ForwardRange& range, Skipper& skipper,
281 + BibTeXEntry& entry)
282 +{
283 + return read(boost::const_begin(range), boost::const_end(range), entry);
284 +}
285 +
286 +template<class ForwardRange, class Skipper, class Container>
287 +inline bool read(const ForwardRange& range, Skipper& skipper,
288 + Container& entries, boost::enable_if<boost::is_same<
289 + typename Container::value_type, BibTeXEntry> >* /*dummy*/ = NULL)
290 +{
291 + return read(boost::const_begin(range), boost::const_end(range), entries);
292 +}
293 +
294 +template<class ForwardIterator>
295 +inline bool read(ForwardIterator first, ForwardIterator last,
296 + BibTeXEntry& entry)
297 +{
298 + return read(first, last, bibtex::space, entry);
299 +}
300 +
301 +template<class ForwardIterator, class Container>
302 +inline bool read(ForwardIterator first, ForwardIterator last,
303 + Container& entries, boost::enable_if<boost::is_same<
304 + typename Container::value_type, BibTeXEntry> >* /*dummy*/ = NULL)
305 +{
306 + return read(first, last, bibtex::space, entries);
307 +}
308 +
309 +template<class ForwardRange>
310 +inline bool read(const ForwardRange& range, BibTeXEntry& entry,
311 + typename boost::enable_if<
312 + boost::has_range_iterator<ForwardRange> >::type* /*dummy*/ = NULL)
313 +{
314 + return read(range, bibtex::space, entry);
315 +}
316 +
317 +template<class ForwardRange, class Container>
318 +inline bool read(const ForwardRange& range, Container& entries,
319 + typename boost::enable_if<
320 + boost::has_range_iterator<ForwardRange> >::type* /*dummy*/ = NULL)
321 +{
322 + return read(range, bibtex::space, entries);
323 +}
324 +
325 +template<class E, class T>
326 +inline bool read(std::basic_istream<E, T>& in, BibTeXEntry& e)
327 +{
328 + boost::io::ios_flags_saver saver(in);
329 + in.unsetf(std::ios_base::skipws);
330 +
331 + typedef boost::spirit::basic_istream_iterator<E> istream_iterator;
332 + return read(istream_iterator(in), istream_iterator(), e);
333 +}
334 +
335 +template<class E, class T, class Container>
336 +inline bool read(std::basic_istream<E, T>& in, Container& entries)
337 +{
338 + boost::io::ios_flags_saver saver(in);
339 + in.unsetf(std::ios_base::skipws);
340 +
341 + typedef boost::spirit::basic_istream_iterator<E> istream_iterator;
342 + return read(istream_iterator(in), istream_iterator(), entries);
343 +}
344 +
345 +template<class E, class T>
346 +inline std::basic_istream<E, T>& operator>>(std::basic_istream<E, T>& in,
347 + BibTeXEntry& entry)
348 +{
349 + read(in, entry);
350 + return in;
351 +}
352 +
353 +template<class E, class T, class Range>
354 +inline typename boost::enable_if<
355 + boost::mpl::and_<
356 + boost::has_range_iterator<Range>,
357 + boost::is_same<typename Range::value_type, BibTeXEntry>
358 + >, std::basic_istream<E, T>
359 +>::type& operator>>(std::basic_istream<E, T>& in, Range& entries)
360 +{
361 + read(in, entries);
362 + return in;
363 +}
364 +
365 +} // namespace bibtex
366 +
367 +#endif // BIBTEXREADER_HPP
1 +// Copyright (c) 2012 Sergiu Dotenco
2 +//
3 +// Permission is hereby granted, free of charge, to any person obtaining a copy
4 +// of this software and associated documentation files (the "Software"), to deal
5 +// in the Software without restriction, including without limitation the rights
6 +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 +// copies of the Software, and to permit persons to whom the Software is
8 +// furnished to do so, subject to the following conditions:
9 +//
10 +// The above copyright notice and this permission notice shall be included in
11 +// all copies or substantial portions of the Software.
12 +//
13 +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 +// SOFTWARE.
20 +
21 +/**
22 + * @brief Boost.Spirit based BibTeX generator.
23 + * @file bibtexwriter.hpp
24 + * @author Sergiu Dotenco
25 + * @version 0.1
26 + */
27 +
28 +#ifndef BIBTEXWRITER_HPP
29 +#define BIBTEXWRITER_HPP
30 +
31 +#pragma once
32 +
33 +#include <iterator>
34 +#include <ostream>
35 +#include <string>
36 +
37 +#include <boost/algorithm/string/case_conv.hpp>
38 +#include <boost/fusion/adapted/std_pair.hpp>
39 +#include <boost/mpl/and.hpp>
40 +#include <boost/range/has_range_iterator.hpp>
41 +#include <boost/spirit/include/karma.hpp>
42 +#include <boost/spirit/include/phoenix.hpp>
43 +#include <boost/type_traits/is_same.hpp>
44 +#include <boost/utility/enable_if.hpp>
45 +
46 +#include "bibtexentry.hpp"
47 +
48 +namespace bibtex {
49 +
50 +template<class OutputIterator, class Skipper>
51 +class BibTeXWriter
52 + : public boost::spirit::karma::grammar
53 + <
54 + OutputIterator,
55 + BibTeXEntry(),
56 + Skipper
57 + >
58 +{
59 +public:
60 + BibTeXWriter()
61 + : BibTeXWriter::base_type(start_, "single BibTeX entry")
62 + {
63 + using namespace boost::spirit;
64 + namespace ph = boost::phoenix;
65 + namespace enc = detail::encoding;
66 +
67 + escapedBrace.add
68 + ('{', "\\{")
69 + ('}', "\\}")
70 + ;
71 +
72 + tag_ = +enc::alnum;
73 + key_ = +~karma::char_(',');
74 + value_ = *(escapedBrace | ~karma::char_("{}"));
75 +
76 + values_
77 + = ('{' << value_ << '}') % " # ";
78 + ;
79 +
80 + field_
81 + = enc::string
82 + << " = "
83 + << values_
84 + ;
85 +
86 + fields_
87 + = (repeat(4)[' '] << field_) % (',' << karma::eol)
88 + ;
89 +
90 + generic_
91 + = '@' << tag_ <<
92 + '{'
93 + << -key_ << ',' << karma::eol
94 + << fields_ << karma::eol <<
95 + '}'
96 + ;
97 +
98 + simple_
99 + =
100 + &
101 + (
102 + karma::string("comment")
103 + |
104 + karma::string("include")
105 + |
106 + karma::string("preamble")
107 + )
108 + [
109 + _1 = ph::bind(tolower, ph::at_c<0>(_val))
110 + ]
111 + <<
112 + '@'
113 + <<
114 + karma::string
115 + [
116 + _1 = ph::at_c<0>(_val)
117 + ]
118 + <<
119 + '{'
120 + << values_
121 + [
122 + _1 = ph::bind(&KeyValue::second,
123 + ph::front(ph::at_c<2>(_val)))
124 + ]
125 + <<
126 + '}'
127 + ;
128 +
129 + string_
130 + =
131 + &karma::string("string")
132 + [
133 + _1 = ph::bind(tolower, ph::at_c<0>(_val))
134 + ]
135 + <<
136 + '@'
137 + <<
138 + karma::string
139 + [
140 + _1 = ph::at_c<0>(_val)
141 + ]
142 + <<
143 + '{'
144 + << field_
145 + [
146 + ph::let(ph::local_names::_a = ph::front(ph::at_c<2>(_val)))
147 + [
148 + _1 = ph::construct<KeyValue>
149 + (ph::bind(&KeyValue::first, ph::local_names::_a),
150 + ph::bind(&KeyValue::second, ph::local_names::_a))
151 + ]
152 + ]
153 + <<
154 + '}'
155 + ;
156 +
157 + start_
158 + = string_
159 + | simple_
160 + | generic_
161 + ;
162 + }
163 +
164 + static std::string tolower(const std::string& in)
165 + {
166 + return boost::algorithm::to_lower_copy(in);
167 + }
168 +
169 +private:
170 + boost::spirit::karma::rule<OutputIterator, BibTeXEntry(), Skipper> start_;
171 + boost::spirit::karma::rule<OutputIterator, BibTeXEntry(), Skipper> generic_;
172 + boost::spirit::karma::rule<OutputIterator, BibTeXEntry(), Skipper> simple_;
173 + boost::spirit::karma::rule<OutputIterator, BibTeXEntry()> string_;
174 + boost::spirit::karma::rule<OutputIterator, std::string()> tag_;
175 + boost::spirit::karma::rule<OutputIterator, std::string()> key_;
176 + boost::spirit::karma::rule<OutputIterator, std::string()> value_;
177 + boost::spirit::karma::rule<OutputIterator, ValueVector(), Skipper>
178 + values_;
179 + boost::spirit::karma::rule<OutputIterator, KeyValue(), Skipper>
180 + field_;
181 + boost::spirit::karma::rule<OutputIterator, KeyValueVector(), Skipper>
182 + fields_;
183 + boost::spirit::karma::symbols<char, const char*> escapedBrace;
184 +};
185 +
186 +template<class OutputIterator, class Skipper>
187 +inline bool write(OutputIterator out, const Skipper& skipper,
188 + const BibTeXEntry& entry)
189 +{
190 + BibTeXWriter<OutputIterator, Skipper> writer;
191 + return boost::spirit::karma::generate_delimited(out, writer,
192 + boost::spirit::karma::eol, entry);
193 +}
194 +
195 +template<class OutputIterator, class Skipper, class Range>
196 +inline bool write(OutputIterator out, Skipper& skipper, const Range& range,
197 + typename boost::enable_if<boost::has_range_iterator<Range> >::type*
198 + /*dummy*/ = NULL)
199 +{
200 + BibTeXWriter<OutputIterator, Skipper> writer;
201 + return boost::spirit::karma::generate_delimited(out, *writer,
202 + boost::spirit::karma::eol, range);
203 +}
204 +
205 +template<class OutputIterator>
206 +inline bool write(OutputIterator out, const BibTeXEntry& entry)
207 +{
208 + return write(out, space, entry);
209 +}
210 +
211 +template<class OutputIterator, class Range>
212 +inline bool write(OutputIterator out, const Range& range,
213 + typename boost::enable_if<boost::has_range_iterator<Range> >::type*
214 + /*dummy*/ = NULL)
215 +{
216 + return write(out, space, range);
217 +}
218 +
219 +template<class E, class T>
220 +inline std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& out,
221 + const BibTeXEntry& entry)
222 +{
223 + write(std::ostream_iterator<E>(out), entry);
224 + return out;
225 +}
226 +
227 +template<class E, class T, class Range>
228 +inline typename boost::enable_if<
229 + boost::mpl::and_<
230 + boost::has_range_iterator<Range>,
231 + boost::is_same<typename Range::value_type, BibTeXEntry>
232 + >, std::basic_ostream<E, T>
233 +>::type& operator<<(std::basic_ostream<E, T>& out, const Range& entries)
234 +{
235 + write(std::ostream_iterator<E>(out), entries);
236 + return out;
237 +}
238 +
239 +} // namespace bibtex
240 +
241 +#endif // BIBTEXWRITER_HPP
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_ALLOCATORS_H_
16 +#define RAPIDJSON_ALLOCATORS_H_
17 +
18 +#include "rapidjson.h"
19 +
20 +RAPIDJSON_NAMESPACE_BEGIN
21 +
22 +///////////////////////////////////////////////////////////////////////////////
23 +// Allocator
24 +
25 +/*! \class rapidjson::Allocator
26 + \brief Concept for allocating, resizing and freeing memory block.
27 +
28 + Note that Malloc() and Realloc() are non-static but Free() is static.
29 +
30 + So if an allocator need to support Free(), it needs to put its pointer in
31 + the header of memory block.
32 +
33 +\code
34 +concept Allocator {
35 + static const bool kNeedFree; //!< Whether this allocator needs to call Free().
36 +
37 + // Allocate a memory block.
38 + // \param size of the memory block in bytes.
39 + // \returns pointer to the memory block.
40 + void* Malloc(size_t size);
41 +
42 + // Resize a memory block.
43 + // \param originalPtr The pointer to current memory block. Null pointer is permitted.
44 + // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
45 + // \param newSize the new size in bytes.
46 + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
47 +
48 + // Free a memory block.
49 + // \param pointer to the memory block. Null pointer is permitted.
50 + static void Free(void *ptr);
51 +};
52 +\endcode
53 +*/
54 +
55 +///////////////////////////////////////////////////////////////////////////////
56 +// CrtAllocator
57 +
58 +//! C-runtime library allocator.
59 +/*! This class is just wrapper for standard C library memory routines.
60 + \note implements Allocator concept
61 +*/
62 +class CrtAllocator {
63 +public:
64 + static const bool kNeedFree = true;
65 + void* Malloc(size_t size) {
66 + if (size) // behavior of malloc(0) is implementation defined.
67 + return std::malloc(size);
68 + else
69 + return NULL; // standardize to returning NULL.
70 + }
71 + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
72 + (void)originalSize;
73 + if (newSize == 0) {
74 + std::free(originalPtr);
75 + return NULL;
76 + }
77 + return std::realloc(originalPtr, newSize);
78 + }
79 + static void Free(void *ptr) { std::free(ptr); }
80 +};
81 +
82 +///////////////////////////////////////////////////////////////////////////////
83 +// MemoryPoolAllocator
84 +
85 +//! Default memory allocator used by the parser and DOM.
86 +/*! This allocator allocate memory blocks from pre-allocated memory chunks.
87 +
88 + It does not free memory blocks. And Realloc() only allocate new memory.
89 +
90 + The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
91 +
92 + User may also supply a buffer as the first chunk.
93 +
94 + If the user-buffer is full then additional chunks are allocated by BaseAllocator.
95 +
96 + The user-buffer is not deallocated by this allocator.
97 +
98 + \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
99 + \note implements Allocator concept
100 +*/
101 +template <typename BaseAllocator = CrtAllocator>
102 +class MemoryPoolAllocator {
103 +public:
104 + static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
105 +
106 + //! Constructor with chunkSize.
107 + /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
108 + \param baseAllocator The allocator for allocating memory chunks.
109 + */
110 + MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
111 + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
112 + {
113 + }
114 +
115 + //! Constructor with user-supplied buffer.
116 + /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
117 +
118 + The user buffer will not be deallocated when this allocator is destructed.
119 +
120 + \param buffer User supplied buffer.
121 + \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
122 + \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
123 + \param baseAllocator The allocator for allocating memory chunks.
124 + */
125 + MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
126 + chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
127 + {
128 + RAPIDJSON_ASSERT(buffer != 0);
129 + RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
130 + chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
131 + chunkHead_->capacity = size - sizeof(ChunkHeader);
132 + chunkHead_->size = 0;
133 + chunkHead_->next = 0;
134 + }
135 +
136 + //! Destructor.
137 + /*! This deallocates all memory chunks, excluding the user-supplied buffer.
138 + */
139 + ~MemoryPoolAllocator() {
140 + Clear();
141 + RAPIDJSON_DELETE(ownBaseAllocator_);
142 + }
143 +
144 + //! Deallocates all memory chunks, excluding the user-supplied buffer.
145 + void Clear() {
146 + while (chunkHead_ && chunkHead_ != userBuffer_) {
147 + ChunkHeader* next = chunkHead_->next;
148 + baseAllocator_->Free(chunkHead_);
149 + chunkHead_ = next;
150 + }
151 + if (chunkHead_ && chunkHead_ == userBuffer_)
152 + chunkHead_->size = 0; // Clear user buffer
153 + }
154 +
155 + //! Computes the total capacity of allocated memory chunks.
156 + /*! \return total capacity in bytes.
157 + */
158 + size_t Capacity() const {
159 + size_t capacity = 0;
160 + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
161 + capacity += c->capacity;
162 + return capacity;
163 + }
164 +
165 + //! Computes the memory blocks allocated.
166 + /*! \return total used bytes.
167 + */
168 + size_t Size() const {
169 + size_t size = 0;
170 + for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
171 + size += c->size;
172 + return size;
173 + }
174 +
175 + //! Allocates a memory block. (concept Allocator)
176 + void* Malloc(size_t size) {
177 + if (!size)
178 + return NULL;
179 +
180 + size = RAPIDJSON_ALIGN(size);
181 + if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
182 + if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
183 + return NULL;
184 +
185 + void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
186 + chunkHead_->size += size;
187 + return buffer;
188 + }
189 +
190 + //! Resizes a memory block (concept Allocator)
191 + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
192 + if (originalPtr == 0)
193 + return Malloc(newSize);
194 +
195 + if (newSize == 0)
196 + return NULL;
197 +
198 + originalSize = RAPIDJSON_ALIGN(originalSize);
199 + newSize = RAPIDJSON_ALIGN(newSize);
200 +
201 + // Do not shrink if new size is smaller than original
202 + if (originalSize >= newSize)
203 + return originalPtr;
204 +
205 + // Simply expand it if it is the last allocation and there is sufficient space
206 + if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
207 + size_t increment = static_cast<size_t>(newSize - originalSize);
208 + if (chunkHead_->size + increment <= chunkHead_->capacity) {
209 + chunkHead_->size += increment;
210 + return originalPtr;
211 + }
212 + }
213 +
214 + // Realloc process: allocate and copy memory, do not free original buffer.
215 + if (void* newBuffer = Malloc(newSize)) {
216 + if (originalSize)
217 + std::memcpy(newBuffer, originalPtr, originalSize);
218 + return newBuffer;
219 + }
220 + else
221 + return NULL;
222 + }
223 +
224 + //! Frees a memory block (concept Allocator)
225 + static void Free(void *ptr) { (void)ptr; } // Do nothing
226 +
227 +private:
228 + //! Copy constructor is not permitted.
229 + MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
230 + //! Copy assignment operator is not permitted.
231 + MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
232 +
233 + //! Creates a new chunk.
234 + /*! \param capacity Capacity of the chunk in bytes.
235 + \return true if success.
236 + */
237 + bool AddChunk(size_t capacity) {
238 + if (!baseAllocator_)
239 + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)();
240 + if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
241 + chunk->capacity = capacity;
242 + chunk->size = 0;
243 + chunk->next = chunkHead_;
244 + chunkHead_ = chunk;
245 + return true;
246 + }
247 + else
248 + return false;
249 + }
250 +
251 + static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
252 +
253 + //! Chunk header for perpending to each chunk.
254 + /*! Chunks are stored as a singly linked list.
255 + */
256 + struct ChunkHeader {
257 + size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
258 + size_t size; //!< Current size of allocated memory in bytes.
259 + ChunkHeader *next; //!< Next chunk in the linked list.
260 + };
261 +
262 + ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
263 + size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
264 + void *userBuffer_; //!< User supplied buffer.
265 + BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
266 + BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
267 +};
268 +
269 +RAPIDJSON_NAMESPACE_END
270 +
271 +#endif // RAPIDJSON_ENCODINGS_H_
This diff could not be displayed because it is too large.
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_ENCODEDSTREAM_H_
16 +#define RAPIDJSON_ENCODEDSTREAM_H_
17 +
18 +#include "stream.h"
19 +#include "memorystream.h"
20 +
21 +#ifdef __GNUC__
22 +RAPIDJSON_DIAG_PUSH
23 +RAPIDJSON_DIAG_OFF(effc++)
24 +#endif
25 +
26 +#ifdef __clang__
27 +RAPIDJSON_DIAG_PUSH
28 +RAPIDJSON_DIAG_OFF(padded)
29 +#endif
30 +
31 +RAPIDJSON_NAMESPACE_BEGIN
32 +
33 +//! Input byte stream wrapper with a statically bound encoding.
34 +/*!
35 + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
36 + \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
37 +*/
38 +template <typename Encoding, typename InputByteStream>
39 +class EncodedInputStream {
40 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
41 +public:
42 + typedef typename Encoding::Ch Ch;
43 +
44 + EncodedInputStream(InputByteStream& is) : is_(is) {
45 + current_ = Encoding::TakeBOM(is_);
46 + }
47 +
48 + Ch Peek() const { return current_; }
49 + Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
50 + size_t Tell() const { return is_.Tell(); }
51 +
52 + // Not implemented
53 + void Put(Ch) { RAPIDJSON_ASSERT(false); }
54 + void Flush() { RAPIDJSON_ASSERT(false); }
55 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
56 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
57 +
58 +private:
59 + EncodedInputStream(const EncodedInputStream&);
60 + EncodedInputStream& operator=(const EncodedInputStream&);
61 +
62 + InputByteStream& is_;
63 + Ch current_;
64 +};
65 +
66 +//! Specialized for UTF8 MemoryStream.
67 +template <>
68 +class EncodedInputStream<UTF8<>, MemoryStream> {
69 +public:
70 + typedef UTF8<>::Ch Ch;
71 +
72 + EncodedInputStream(MemoryStream& is) : is_(is) {
73 + if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
74 + if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
75 + if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
76 + }
77 + Ch Peek() const { return is_.Peek(); }
78 + Ch Take() { return is_.Take(); }
79 + size_t Tell() const { return is_.Tell(); }
80 +
81 + // Not implemented
82 + void Put(Ch) {}
83 + void Flush() {}
84 + Ch* PutBegin() { return 0; }
85 + size_t PutEnd(Ch*) { return 0; }
86 +
87 + MemoryStream& is_;
88 +
89 +private:
90 + EncodedInputStream(const EncodedInputStream&);
91 + EncodedInputStream& operator=(const EncodedInputStream&);
92 +};
93 +
94 +//! Output byte stream wrapper with statically bound encoding.
95 +/*!
96 + \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
97 + \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
98 +*/
99 +template <typename Encoding, typename OutputByteStream>
100 +class EncodedOutputStream {
101 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
102 +public:
103 + typedef typename Encoding::Ch Ch;
104 +
105 + EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
106 + if (putBOM)
107 + Encoding::PutBOM(os_);
108 + }
109 +
110 + void Put(Ch c) { Encoding::Put(os_, c); }
111 + void Flush() { os_.Flush(); }
112 +
113 + // Not implemented
114 + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
115 + Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
116 + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
117 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
118 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
119 +
120 +private:
121 + EncodedOutputStream(const EncodedOutputStream&);
122 + EncodedOutputStream& operator=(const EncodedOutputStream&);
123 +
124 + OutputByteStream& os_;
125 +};
126 +
127 +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
128 +
129 +//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
130 +/*!
131 + \tparam CharType Type of character for reading.
132 + \tparam InputByteStream type of input byte stream to be wrapped.
133 +*/
134 +template <typename CharType, typename InputByteStream>
135 +class AutoUTFInputStream {
136 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
137 +public:
138 + typedef CharType Ch;
139 +
140 + //! Constructor.
141 + /*!
142 + \param is input stream to be wrapped.
143 + \param type UTF encoding type if it is not detected from the stream.
144 + */
145 + AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
146 + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
147 + DetectType();
148 + static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
149 + takeFunc_ = f[type_];
150 + current_ = takeFunc_(*is_);
151 + }
152 +
153 + UTFType GetType() const { return type_; }
154 + bool HasBOM() const { return hasBOM_; }
155 +
156 + Ch Peek() const { return current_; }
157 + Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
158 + size_t Tell() const { return is_->Tell(); }
159 +
160 + // Not implemented
161 + void Put(Ch) { RAPIDJSON_ASSERT(false); }
162 + void Flush() { RAPIDJSON_ASSERT(false); }
163 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
164 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
165 +
166 +private:
167 + AutoUTFInputStream(const AutoUTFInputStream&);
168 + AutoUTFInputStream& operator=(const AutoUTFInputStream&);
169 +
170 + // Detect encoding type with BOM or RFC 4627
171 + void DetectType() {
172 + // BOM (Byte Order Mark):
173 + // 00 00 FE FF UTF-32BE
174 + // FF FE 00 00 UTF-32LE
175 + // FE FF UTF-16BE
176 + // FF FE UTF-16LE
177 + // EF BB BF UTF-8
178 +
179 + const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
180 + if (!c)
181 + return;
182 +
183 + unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
184 + hasBOM_ = false;
185 + if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
186 + else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
187 + else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
188 + else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
189 + else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
190 +
191 + // RFC 4627: Section 3
192 + // "Since the first two characters of a JSON text will always be ASCII
193 + // characters [RFC0020], it is possible to determine whether an octet
194 + // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
195 + // at the pattern of nulls in the first four octets."
196 + // 00 00 00 xx UTF-32BE
197 + // 00 xx 00 xx UTF-16BE
198 + // xx 00 00 00 UTF-32LE
199 + // xx 00 xx 00 UTF-16LE
200 + // xx xx xx xx UTF-8
201 +
202 + if (!hasBOM_) {
203 + int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
204 + switch (pattern) {
205 + case 0x08: type_ = kUTF32BE; break;
206 + case 0x0A: type_ = kUTF16BE; break;
207 + case 0x01: type_ = kUTF32LE; break;
208 + case 0x05: type_ = kUTF16LE; break;
209 + case 0x0F: type_ = kUTF8; break;
210 + default: break; // Use type defined by user.
211 + }
212 + }
213 +
214 + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
215 + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
216 + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
217 + }
218 +
219 + typedef Ch (*TakeFunc)(InputByteStream& is);
220 + InputByteStream* is_;
221 + UTFType type_;
222 + Ch current_;
223 + TakeFunc takeFunc_;
224 + bool hasBOM_;
225 +};
226 +
227 +//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
228 +/*!
229 + \tparam CharType Type of character for writing.
230 + \tparam OutputByteStream type of output byte stream to be wrapped.
231 +*/
232 +template <typename CharType, typename OutputByteStream>
233 +class AutoUTFOutputStream {
234 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
235 +public:
236 + typedef CharType Ch;
237 +
238 + //! Constructor.
239 + /*!
240 + \param os output stream to be wrapped.
241 + \param type UTF encoding type.
242 + \param putBOM Whether to write BOM at the beginning of the stream.
243 + */
244 + AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
245 + RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
246 +
247 + // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
248 + if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
249 + if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
250 +
251 + static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
252 + putFunc_ = f[type_];
253 +
254 + if (putBOM)
255 + PutBOM();
256 + }
257 +
258 + UTFType GetType() const { return type_; }
259 +
260 + void Put(Ch c) { putFunc_(*os_, c); }
261 + void Flush() { os_->Flush(); }
262 +
263 + // Not implemented
264 + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
265 + Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
266 + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
267 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
268 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
269 +
270 +private:
271 + AutoUTFOutputStream(const AutoUTFOutputStream&);
272 + AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
273 +
274 + void PutBOM() {
275 + typedef void (*PutBOMFunc)(OutputByteStream&);
276 + static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
277 + f[type_](*os_);
278 + }
279 +
280 + typedef void (*PutFunc)(OutputByteStream&, Ch);
281 +
282 + OutputByteStream* os_;
283 + UTFType type_;
284 + PutFunc putFunc_;
285 +};
286 +
287 +#undef RAPIDJSON_ENCODINGS_FUNC
288 +
289 +RAPIDJSON_NAMESPACE_END
290 +
291 +#ifdef __clang__
292 +RAPIDJSON_DIAG_POP
293 +#endif
294 +
295 +#ifdef __GNUC__
296 +RAPIDJSON_DIAG_POP
297 +#endif
298 +
299 +#endif // RAPIDJSON_FILESTREAM_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_ENCODINGS_H_
16 +#define RAPIDJSON_ENCODINGS_H_
17 +
18 +#include "rapidjson.h"
19 +
20 +#ifdef _MSC_VER
21 +RAPIDJSON_DIAG_PUSH
22 +RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
23 +RAPIDJSON_DIAG_OFF(4702) // unreachable code
24 +#elif defined(__GNUC__)
25 +RAPIDJSON_DIAG_PUSH
26 +RAPIDJSON_DIAG_OFF(effc++)
27 +RAPIDJSON_DIAG_OFF(overflow)
28 +#endif
29 +
30 +RAPIDJSON_NAMESPACE_BEGIN
31 +
32 +///////////////////////////////////////////////////////////////////////////////
33 +// Encoding
34 +
35 +/*! \class rapidjson::Encoding
36 + \brief Concept for encoding of Unicode characters.
37 +
38 +\code
39 +concept Encoding {
40 + typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
41 +
42 + enum { supportUnicode = 1 }; // or 0 if not supporting unicode
43 +
44 + //! \brief Encode a Unicode codepoint to an output stream.
45 + //! \param os Output stream.
46 + //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
47 + template<typename OutputStream>
48 + static void Encode(OutputStream& os, unsigned codepoint);
49 +
50 + //! \brief Decode a Unicode codepoint from an input stream.
51 + //! \param is Input stream.
52 + //! \param codepoint Output of the unicode codepoint.
53 + //! \return true if a valid codepoint can be decoded from the stream.
54 + template <typename InputStream>
55 + static bool Decode(InputStream& is, unsigned* codepoint);
56 +
57 + //! \brief Validate one Unicode codepoint from an encoded stream.
58 + //! \param is Input stream to obtain codepoint.
59 + //! \param os Output for copying one codepoint.
60 + //! \return true if it is valid.
61 + //! \note This function just validating and copying the codepoint without actually decode it.
62 + template <typename InputStream, typename OutputStream>
63 + static bool Validate(InputStream& is, OutputStream& os);
64 +
65 + // The following functions are deal with byte streams.
66 +
67 + //! Take a character from input byte stream, skip BOM if exist.
68 + template <typename InputByteStream>
69 + static CharType TakeBOM(InputByteStream& is);
70 +
71 + //! Take a character from input byte stream.
72 + template <typename InputByteStream>
73 + static Ch Take(InputByteStream& is);
74 +
75 + //! Put BOM to output byte stream.
76 + template <typename OutputByteStream>
77 + static void PutBOM(OutputByteStream& os);
78 +
79 + //! Put a character to output byte stream.
80 + template <typename OutputByteStream>
81 + static void Put(OutputByteStream& os, Ch c);
82 +};
83 +\endcode
84 +*/
85 +
86 +///////////////////////////////////////////////////////////////////////////////
87 +// UTF8
88 +
89 +//! UTF-8 encoding.
90 +/*! http://en.wikipedia.org/wiki/UTF-8
91 + http://tools.ietf.org/html/rfc3629
92 + \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
93 + \note implements Encoding concept
94 +*/
95 +template<typename CharType = char>
96 +struct UTF8 {
97 + typedef CharType Ch;
98 +
99 + enum { supportUnicode = 1 };
100 +
101 + template<typename OutputStream>
102 + static void Encode(OutputStream& os, unsigned codepoint) {
103 + if (codepoint <= 0x7F)
104 + os.Put(static_cast<Ch>(codepoint & 0xFF));
105 + else if (codepoint <= 0x7FF) {
106 + os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
107 + os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
108 + }
109 + else if (codepoint <= 0xFFFF) {
110 + os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
111 + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
112 + os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
113 + }
114 + else {
115 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
116 + os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
117 + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
118 + os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
119 + os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
120 + }
121 + }
122 +
123 + template<typename OutputStream>
124 + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
125 + if (codepoint <= 0x7F)
126 + PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
127 + else if (codepoint <= 0x7FF) {
128 + PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
129 + PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
130 + }
131 + else if (codepoint <= 0xFFFF) {
132 + PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
133 + PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
134 + PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
135 + }
136 + else {
137 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
138 + PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
139 + PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
140 + PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
141 + PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
142 + }
143 + }
144 +
145 + template <typename InputStream>
146 + static bool Decode(InputStream& is, unsigned* codepoint) {
147 +#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
148 +#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
149 +#define TAIL() COPY(); TRANS(0x70)
150 + typename InputStream::Ch c = is.Take();
151 + if (!(c & 0x80)) {
152 + *codepoint = static_cast<unsigned char>(c);
153 + return true;
154 + }
155 +
156 + unsigned char type = GetRange(static_cast<unsigned char>(c));
157 + if (type >= 32) {
158 + *codepoint = 0;
159 + } else {
160 + *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
161 + }
162 + bool result = true;
163 + switch (type) {
164 + case 2: TAIL(); return result;
165 + case 3: TAIL(); TAIL(); return result;
166 + case 4: COPY(); TRANS(0x50); TAIL(); return result;
167 + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
168 + case 6: TAIL(); TAIL(); TAIL(); return result;
169 + case 10: COPY(); TRANS(0x20); TAIL(); return result;
170 + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
171 + default: return false;
172 + }
173 +#undef COPY
174 +#undef TRANS
175 +#undef TAIL
176 + }
177 +
178 + template <typename InputStream, typename OutputStream>
179 + static bool Validate(InputStream& is, OutputStream& os) {
180 +#define COPY() os.Put(c = is.Take())
181 +#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
182 +#define TAIL() COPY(); TRANS(0x70)
183 + Ch c;
184 + COPY();
185 + if (!(c & 0x80))
186 + return true;
187 +
188 + bool result = true;
189 + switch (GetRange(static_cast<unsigned char>(c))) {
190 + case 2: TAIL(); return result;
191 + case 3: TAIL(); TAIL(); return result;
192 + case 4: COPY(); TRANS(0x50); TAIL(); return result;
193 + case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
194 + case 6: TAIL(); TAIL(); TAIL(); return result;
195 + case 10: COPY(); TRANS(0x20); TAIL(); return result;
196 + case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
197 + default: return false;
198 + }
199 +#undef COPY
200 +#undef TRANS
201 +#undef TAIL
202 + }
203 +
204 + static unsigned char GetRange(unsigned char c) {
205 + // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
206 + // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
207 + static const unsigned char type[] = {
208 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
209 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
210 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
211 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
212 + 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
213 + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
214 + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
215 + 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
216 + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
217 + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
218 + };
219 + return type[c];
220 + }
221 +
222 + template <typename InputByteStream>
223 + static CharType TakeBOM(InputByteStream& is) {
224 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
225 + typename InputByteStream::Ch c = Take(is);
226 + if (static_cast<unsigned char>(c) != 0xEFu) return c;
227 + c = is.Take();
228 + if (static_cast<unsigned char>(c) != 0xBBu) return c;
229 + c = is.Take();
230 + if (static_cast<unsigned char>(c) != 0xBFu) return c;
231 + c = is.Take();
232 + return c;
233 + }
234 +
235 + template <typename InputByteStream>
236 + static Ch Take(InputByteStream& is) {
237 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
238 + return static_cast<Ch>(is.Take());
239 + }
240 +
241 + template <typename OutputByteStream>
242 + static void PutBOM(OutputByteStream& os) {
243 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
244 + os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
245 + os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
246 + os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
247 + }
248 +
249 + template <typename OutputByteStream>
250 + static void Put(OutputByteStream& os, Ch c) {
251 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
252 + os.Put(static_cast<typename OutputByteStream::Ch>(c));
253 + }
254 +};
255 +
256 +///////////////////////////////////////////////////////////////////////////////
257 +// UTF16
258 +
259 +//! UTF-16 encoding.
260 +/*! http://en.wikipedia.org/wiki/UTF-16
261 + http://tools.ietf.org/html/rfc2781
262 + \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
263 + \note implements Encoding concept
264 +
265 + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
266 + For streaming, use UTF16LE and UTF16BE, which handle endianness.
267 +*/
268 +template<typename CharType = wchar_t>
269 +struct UTF16 {
270 + typedef CharType Ch;
271 + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
272 +
273 + enum { supportUnicode = 1 };
274 +
275 + template<typename OutputStream>
276 + static void Encode(OutputStream& os, unsigned codepoint) {
277 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
278 + if (codepoint <= 0xFFFF) {
279 + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
280 + os.Put(static_cast<typename OutputStream::Ch>(codepoint));
281 + }
282 + else {
283 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
284 + unsigned v = codepoint - 0x10000;
285 + os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
286 + os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
287 + }
288 + }
289 +
290 +
291 + template<typename OutputStream>
292 + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
293 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
294 + if (codepoint <= 0xFFFF) {
295 + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
296 + PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
297 + }
298 + else {
299 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
300 + unsigned v = codepoint - 0x10000;
301 + PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
302 + PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
303 + }
304 + }
305 +
306 + template <typename InputStream>
307 + static bool Decode(InputStream& is, unsigned* codepoint) {
308 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
309 + typename InputStream::Ch c = is.Take();
310 + if (c < 0xD800 || c > 0xDFFF) {
311 + *codepoint = static_cast<unsigned>(c);
312 + return true;
313 + }
314 + else if (c <= 0xDBFF) {
315 + *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
316 + c = is.Take();
317 + *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
318 + *codepoint += 0x10000;
319 + return c >= 0xDC00 && c <= 0xDFFF;
320 + }
321 + return false;
322 + }
323 +
324 + template <typename InputStream, typename OutputStream>
325 + static bool Validate(InputStream& is, OutputStream& os) {
326 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
327 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
328 + typename InputStream::Ch c;
329 + os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
330 + if (c < 0xD800 || c > 0xDFFF)
331 + return true;
332 + else if (c <= 0xDBFF) {
333 + os.Put(c = is.Take());
334 + return c >= 0xDC00 && c <= 0xDFFF;
335 + }
336 + return false;
337 + }
338 +};
339 +
340 +//! UTF-16 little endian encoding.
341 +template<typename CharType = wchar_t>
342 +struct UTF16LE : UTF16<CharType> {
343 + template <typename InputByteStream>
344 + static CharType TakeBOM(InputByteStream& is) {
345 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
346 + CharType c = Take(is);
347 + return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
348 + }
349 +
350 + template <typename InputByteStream>
351 + static CharType Take(InputByteStream& is) {
352 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
353 + unsigned c = static_cast<uint8_t>(is.Take());
354 + c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
355 + return static_cast<CharType>(c);
356 + }
357 +
358 + template <typename OutputByteStream>
359 + static void PutBOM(OutputByteStream& os) {
360 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
361 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
362 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
363 + }
364 +
365 + template <typename OutputByteStream>
366 + static void Put(OutputByteStream& os, CharType c) {
367 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
368 + os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
369 + os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
370 + }
371 +};
372 +
373 +//! UTF-16 big endian encoding.
374 +template<typename CharType = wchar_t>
375 +struct UTF16BE : UTF16<CharType> {
376 + template <typename InputByteStream>
377 + static CharType TakeBOM(InputByteStream& is) {
378 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
379 + CharType c = Take(is);
380 + return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
381 + }
382 +
383 + template <typename InputByteStream>
384 + static CharType Take(InputByteStream& is) {
385 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
386 + unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
387 + c |= static_cast<uint8_t>(is.Take());
388 + return static_cast<CharType>(c);
389 + }
390 +
391 + template <typename OutputByteStream>
392 + static void PutBOM(OutputByteStream& os) {
393 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
394 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
395 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
396 + }
397 +
398 + template <typename OutputByteStream>
399 + static void Put(OutputByteStream& os, CharType c) {
400 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
401 + os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
402 + os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
403 + }
404 +};
405 +
406 +///////////////////////////////////////////////////////////////////////////////
407 +// UTF32
408 +
409 +//! UTF-32 encoding.
410 +/*! http://en.wikipedia.org/wiki/UTF-32
411 + \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
412 + \note implements Encoding concept
413 +
414 + \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
415 + For streaming, use UTF32LE and UTF32BE, which handle endianness.
416 +*/
417 +template<typename CharType = unsigned>
418 +struct UTF32 {
419 + typedef CharType Ch;
420 + RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
421 +
422 + enum { supportUnicode = 1 };
423 +
424 + template<typename OutputStream>
425 + static void Encode(OutputStream& os, unsigned codepoint) {
426 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
427 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
428 + os.Put(codepoint);
429 + }
430 +
431 + template<typename OutputStream>
432 + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
433 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
434 + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
435 + PutUnsafe(os, codepoint);
436 + }
437 +
438 + template <typename InputStream>
439 + static bool Decode(InputStream& is, unsigned* codepoint) {
440 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
441 + Ch c = is.Take();
442 + *codepoint = c;
443 + return c <= 0x10FFFF;
444 + }
445 +
446 + template <typename InputStream, typename OutputStream>
447 + static bool Validate(InputStream& is, OutputStream& os) {
448 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
449 + Ch c;
450 + os.Put(c = is.Take());
451 + return c <= 0x10FFFF;
452 + }
453 +};
454 +
455 +//! UTF-32 little endian enocoding.
456 +template<typename CharType = unsigned>
457 +struct UTF32LE : UTF32<CharType> {
458 + template <typename InputByteStream>
459 + static CharType TakeBOM(InputByteStream& is) {
460 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
461 + CharType c = Take(is);
462 + return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
463 + }
464 +
465 + template <typename InputByteStream>
466 + static CharType Take(InputByteStream& is) {
467 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
468 + unsigned c = static_cast<uint8_t>(is.Take());
469 + c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
470 + c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
471 + c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
472 + return static_cast<CharType>(c);
473 + }
474 +
475 + template <typename OutputByteStream>
476 + static void PutBOM(OutputByteStream& os) {
477 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
478 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
479 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
480 + os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
481 + os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
482 + }
483 +
484 + template <typename OutputByteStream>
485 + static void Put(OutputByteStream& os, CharType c) {
486 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
487 + os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
488 + os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
489 + os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
490 + os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
491 + }
492 +};
493 +
494 +//! UTF-32 big endian encoding.
495 +template<typename CharType = unsigned>
496 +struct UTF32BE : UTF32<CharType> {
497 + template <typename InputByteStream>
498 + static CharType TakeBOM(InputByteStream& is) {
499 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
500 + CharType c = Take(is);
501 + return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
502 + }
503 +
504 + template <typename InputByteStream>
505 + static CharType Take(InputByteStream& is) {
506 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
507 + unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
508 + c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
509 + c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
510 + c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
511 + return static_cast<CharType>(c);
512 + }
513 +
514 + template <typename OutputByteStream>
515 + static void PutBOM(OutputByteStream& os) {
516 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
517 + os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
518 + os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
519 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
520 + os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
521 + }
522 +
523 + template <typename OutputByteStream>
524 + static void Put(OutputByteStream& os, CharType c) {
525 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
526 + os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
527 + os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
528 + os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
529 + os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
530 + }
531 +};
532 +
533 +///////////////////////////////////////////////////////////////////////////////
534 +// ASCII
535 +
536 +//! ASCII encoding.
537 +/*! http://en.wikipedia.org/wiki/ASCII
538 + \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
539 + \note implements Encoding concept
540 +*/
541 +template<typename CharType = char>
542 +struct ASCII {
543 + typedef CharType Ch;
544 +
545 + enum { supportUnicode = 0 };
546 +
547 + template<typename OutputStream>
548 + static void Encode(OutputStream& os, unsigned codepoint) {
549 + RAPIDJSON_ASSERT(codepoint <= 0x7F);
550 + os.Put(static_cast<Ch>(codepoint & 0xFF));
551 + }
552 +
553 + template<typename OutputStream>
554 + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
555 + RAPIDJSON_ASSERT(codepoint <= 0x7F);
556 + PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
557 + }
558 +
559 + template <typename InputStream>
560 + static bool Decode(InputStream& is, unsigned* codepoint) {
561 + uint8_t c = static_cast<uint8_t>(is.Take());
562 + *codepoint = c;
563 + return c <= 0X7F;
564 + }
565 +
566 + template <typename InputStream, typename OutputStream>
567 + static bool Validate(InputStream& is, OutputStream& os) {
568 + uint8_t c = static_cast<uint8_t>(is.Take());
569 + os.Put(static_cast<typename OutputStream::Ch>(c));
570 + return c <= 0x7F;
571 + }
572 +
573 + template <typename InputByteStream>
574 + static CharType TakeBOM(InputByteStream& is) {
575 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
576 + uint8_t c = static_cast<uint8_t>(Take(is));
577 + return static_cast<Ch>(c);
578 + }
579 +
580 + template <typename InputByteStream>
581 + static Ch Take(InputByteStream& is) {
582 + RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
583 + return static_cast<Ch>(is.Take());
584 + }
585 +
586 + template <typename OutputByteStream>
587 + static void PutBOM(OutputByteStream& os) {
588 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
589 + (void)os;
590 + }
591 +
592 + template <typename OutputByteStream>
593 + static void Put(OutputByteStream& os, Ch c) {
594 + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
595 + os.Put(static_cast<typename OutputByteStream::Ch>(c));
596 + }
597 +};
598 +
599 +///////////////////////////////////////////////////////////////////////////////
600 +// AutoUTF
601 +
602 +//! Runtime-specified UTF encoding type of a stream.
603 +enum UTFType {
604 + kUTF8 = 0, //!< UTF-8.
605 + kUTF16LE = 1, //!< UTF-16 little endian.
606 + kUTF16BE = 2, //!< UTF-16 big endian.
607 + kUTF32LE = 3, //!< UTF-32 little endian.
608 + kUTF32BE = 4 //!< UTF-32 big endian.
609 +};
610 +
611 +//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
612 +/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
613 +*/
614 +template<typename CharType>
615 +struct AutoUTF {
616 + typedef CharType Ch;
617 +
618 + enum { supportUnicode = 1 };
619 +
620 +#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
621 +
622 + template<typename OutputStream>
623 + static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
624 + typedef void (*EncodeFunc)(OutputStream&, unsigned);
625 + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
626 + (*f[os.GetType()])(os, codepoint);
627 + }
628 +
629 + template<typename OutputStream>
630 + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
631 + typedef void (*EncodeFunc)(OutputStream&, unsigned);
632 + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
633 + (*f[os.GetType()])(os, codepoint);
634 + }
635 +
636 + template <typename InputStream>
637 + static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
638 + typedef bool (*DecodeFunc)(InputStream&, unsigned*);
639 + static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
640 + return (*f[is.GetType()])(is, codepoint);
641 + }
642 +
643 + template <typename InputStream, typename OutputStream>
644 + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
645 + typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
646 + static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
647 + return (*f[is.GetType()])(is, os);
648 + }
649 +
650 +#undef RAPIDJSON_ENCODINGS_FUNC
651 +};
652 +
653 +///////////////////////////////////////////////////////////////////////////////
654 +// Transcoder
655 +
656 +//! Encoding conversion.
657 +template<typename SourceEncoding, typename TargetEncoding>
658 +struct Transcoder {
659 + //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
660 + template<typename InputStream, typename OutputStream>
661 + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
662 + unsigned codepoint;
663 + if (!SourceEncoding::Decode(is, &codepoint))
664 + return false;
665 + TargetEncoding::Encode(os, codepoint);
666 + return true;
667 + }
668 +
669 + template<typename InputStream, typename OutputStream>
670 + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
671 + unsigned codepoint;
672 + if (!SourceEncoding::Decode(is, &codepoint))
673 + return false;
674 + TargetEncoding::EncodeUnsafe(os, codepoint);
675 + return true;
676 + }
677 +
678 + //! Validate one Unicode codepoint from an encoded stream.
679 + template<typename InputStream, typename OutputStream>
680 + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
681 + return Transcode(is, os); // Since source/target encoding is different, must transcode.
682 + }
683 +};
684 +
685 +// Forward declaration.
686 +template<typename Stream>
687 +inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
688 +
689 +//! Specialization of Transcoder with same source and target encoding.
690 +template<typename Encoding>
691 +struct Transcoder<Encoding, Encoding> {
692 + template<typename InputStream, typename OutputStream>
693 + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
694 + os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
695 + return true;
696 + }
697 +
698 + template<typename InputStream, typename OutputStream>
699 + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
700 + PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
701 + return true;
702 + }
703 +
704 + template<typename InputStream, typename OutputStream>
705 + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
706 + return Encoding::Validate(is, os); // source/target encoding are the same
707 + }
708 +};
709 +
710 +RAPIDJSON_NAMESPACE_END
711 +
712 +#if defined(__GNUC__) || defined(_MSC_VER)
713 +RAPIDJSON_DIAG_POP
714 +#endif
715 +
716 +#endif // RAPIDJSON_ENCODINGS_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_ERROR_EN_H_
16 +#define RAPIDJSON_ERROR_EN_H_
17 +
18 +#include "error.h"
19 +
20 +#ifdef __clang__
21 +RAPIDJSON_DIAG_PUSH
22 +RAPIDJSON_DIAG_OFF(switch-enum)
23 +RAPIDJSON_DIAG_OFF(covered-switch-default)
24 +#endif
25 +
26 +RAPIDJSON_NAMESPACE_BEGIN
27 +
28 +//! Maps error code of parsing into error message.
29 +/*!
30 + \ingroup RAPIDJSON_ERRORS
31 + \param parseErrorCode Error code obtained in parsing.
32 + \return the error message.
33 + \note User can make a copy of this function for localization.
34 + Using switch-case is safer for future modification of error codes.
35 +*/
36 +inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
37 + switch (parseErrorCode) {
38 + case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
39 +
40 + case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
41 + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
42 +
43 + case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
44 +
45 + case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
46 + case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
47 + case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
48 +
49 + case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
50 +
51 + case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
52 + case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
53 + case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
54 + case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
55 + case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
56 +
57 + case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
58 + case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
59 + case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
60 +
61 + case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
62 + case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
63 +
64 + default: return RAPIDJSON_ERROR_STRING("Unknown error.");
65 + }
66 +}
67 +
68 +RAPIDJSON_NAMESPACE_END
69 +
70 +#ifdef __clang__
71 +RAPIDJSON_DIAG_POP
72 +#endif
73 +
74 +#endif // RAPIDJSON_ERROR_EN_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_ERROR_ERROR_H_
16 +#define RAPIDJSON_ERROR_ERROR_H_
17 +
18 +#include "../rapidjson.h"
19 +
20 +#ifdef __clang__
21 +RAPIDJSON_DIAG_PUSH
22 +RAPIDJSON_DIAG_OFF(padded)
23 +#endif
24 +
25 +/*! \file error.h */
26 +
27 +/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
28 +
29 +///////////////////////////////////////////////////////////////////////////////
30 +// RAPIDJSON_ERROR_CHARTYPE
31 +
32 +//! Character type of error messages.
33 +/*! \ingroup RAPIDJSON_ERRORS
34 + The default character type is \c char.
35 + On Windows, user can define this macro as \c TCHAR for supporting both
36 + unicode/non-unicode settings.
37 +*/
38 +#ifndef RAPIDJSON_ERROR_CHARTYPE
39 +#define RAPIDJSON_ERROR_CHARTYPE char
40 +#endif
41 +
42 +///////////////////////////////////////////////////////////////////////////////
43 +// RAPIDJSON_ERROR_STRING
44 +
45 +//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
46 +/*! \ingroup RAPIDJSON_ERRORS
47 + By default this conversion macro does nothing.
48 + On Windows, user can define this macro as \c _T(x) for supporting both
49 + unicode/non-unicode settings.
50 +*/
51 +#ifndef RAPIDJSON_ERROR_STRING
52 +#define RAPIDJSON_ERROR_STRING(x) x
53 +#endif
54 +
55 +RAPIDJSON_NAMESPACE_BEGIN
56 +
57 +///////////////////////////////////////////////////////////////////////////////
58 +// ParseErrorCode
59 +
60 +//! Error code of parsing.
61 +/*! \ingroup RAPIDJSON_ERRORS
62 + \see GenericReader::Parse, GenericReader::GetParseErrorCode
63 +*/
64 +enum ParseErrorCode {
65 + kParseErrorNone = 0, //!< No error.
66 +
67 + kParseErrorDocumentEmpty, //!< The document is empty.
68 + kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
69 +
70 + kParseErrorValueInvalid, //!< Invalid value.
71 +
72 + kParseErrorObjectMissName, //!< Missing a name for object member.
73 + kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
74 + kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
75 +
76 + kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
77 +
78 + kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
79 + kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
80 + kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
81 + kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
82 + kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
83 +
84 + kParseErrorNumberTooBig, //!< Number too big to be stored in double.
85 + kParseErrorNumberMissFraction, //!< Miss fraction part in number.
86 + kParseErrorNumberMissExponent, //!< Miss exponent in number.
87 +
88 + kParseErrorTermination, //!< Parsing was terminated.
89 + kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
90 +};
91 +
92 +//! Result of parsing (wraps ParseErrorCode)
93 +/*!
94 + \ingroup RAPIDJSON_ERRORS
95 + \code
96 + Document doc;
97 + ParseResult ok = doc.Parse("[42]");
98 + if (!ok) {
99 + fprintf(stderr, "JSON parse error: %s (%u)",
100 + GetParseError_En(ok.Code()), ok.Offset());
101 + exit(EXIT_FAILURE);
102 + }
103 + \endcode
104 + \see GenericReader::Parse, GenericDocument::Parse
105 +*/
106 +struct ParseResult {
107 +public:
108 + //! Default constructor, no error.
109 + ParseResult() : code_(kParseErrorNone), offset_(0) {}
110 + //! Constructor to set an error.
111 + ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
112 +
113 + //! Get the error code.
114 + ParseErrorCode Code() const { return code_; }
115 + //! Get the error offset, if \ref IsError(), 0 otherwise.
116 + size_t Offset() const { return offset_; }
117 +
118 + //! Conversion to \c bool, returns \c true, iff !\ref IsError().
119 + operator bool() const { return !IsError(); }
120 + //! Whether the result is an error.
121 + bool IsError() const { return code_ != kParseErrorNone; }
122 +
123 + bool operator==(const ParseResult& that) const { return code_ == that.code_; }
124 + bool operator==(ParseErrorCode code) const { return code_ == code; }
125 + friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
126 +
127 + //! Reset error code.
128 + void Clear() { Set(kParseErrorNone); }
129 + //! Update error code and offset.
130 + void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
131 +
132 +private:
133 + ParseErrorCode code_;
134 + size_t offset_;
135 +};
136 +
137 +//! Function pointer type of GetParseError().
138 +/*! \ingroup RAPIDJSON_ERRORS
139 +
140 + This is the prototype for \c GetParseError_X(), where \c X is a locale.
141 + User can dynamically change locale in runtime, e.g.:
142 +\code
143 + GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
144 + const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
145 +\endcode
146 +*/
147 +typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
148 +
149 +RAPIDJSON_NAMESPACE_END
150 +
151 +#ifdef __clang__
152 +RAPIDJSON_DIAG_POP
153 +#endif
154 +
155 +#endif // RAPIDJSON_ERROR_ERROR_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_FILEREADSTREAM_H_
16 +#define RAPIDJSON_FILEREADSTREAM_H_
17 +
18 +#include "stream.h"
19 +#include <cstdio>
20 +
21 +#ifdef __clang__
22 +RAPIDJSON_DIAG_PUSH
23 +RAPIDJSON_DIAG_OFF(padded)
24 +RAPIDJSON_DIAG_OFF(unreachable-code)
25 +RAPIDJSON_DIAG_OFF(missing-noreturn)
26 +#endif
27 +
28 +RAPIDJSON_NAMESPACE_BEGIN
29 +
30 +//! File byte stream for input using fread().
31 +/*!
32 + \note implements Stream concept
33 +*/
34 +class FileReadStream {
35 +public:
36 + typedef char Ch; //!< Character type (byte).
37 +
38 + //! Constructor.
39 + /*!
40 + \param fp File pointer opened for read.
41 + \param buffer user-supplied buffer.
42 + \param bufferSize size of buffer in bytes. Must >=4 bytes.
43 + */
44 + FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
45 + RAPIDJSON_ASSERT(fp_ != 0);
46 + RAPIDJSON_ASSERT(bufferSize >= 4);
47 + Read();
48 + }
49 +
50 + Ch Peek() const { return *current_; }
51 + Ch Take() { Ch c = *current_; Read(); return c; }
52 + size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
53 +
54 + // Not implemented
55 + void Put(Ch) { RAPIDJSON_ASSERT(false); }
56 + void Flush() { RAPIDJSON_ASSERT(false); }
57 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
58 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
59 +
60 + // For encoding detection only.
61 + const Ch* Peek4() const {
62 + return (current_ + 4 <= bufferLast_) ? current_ : 0;
63 + }
64 +
65 +private:
66 + void Read() {
67 + if (current_ < bufferLast_)
68 + ++current_;
69 + else if (!eof_) {
70 + count_ += readCount_;
71 + readCount_ = fread(buffer_, 1, bufferSize_, fp_);
72 + bufferLast_ = buffer_ + readCount_ - 1;
73 + current_ = buffer_;
74 +
75 + if (readCount_ < bufferSize_) {
76 + buffer_[readCount_] = '\0';
77 + ++bufferLast_;
78 + eof_ = true;
79 + }
80 + }
81 + }
82 +
83 + std::FILE* fp_;
84 + Ch *buffer_;
85 + size_t bufferSize_;
86 + Ch *bufferLast_;
87 + Ch *current_;
88 + size_t readCount_;
89 + size_t count_; //!< Number of characters read
90 + bool eof_;
91 +};
92 +
93 +RAPIDJSON_NAMESPACE_END
94 +
95 +#ifdef __clang__
96 +RAPIDJSON_DIAG_POP
97 +#endif
98 +
99 +#endif // RAPIDJSON_FILESTREAM_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_FILEWRITESTREAM_H_
16 +#define RAPIDJSON_FILEWRITESTREAM_H_
17 +
18 +#include "stream.h"
19 +#include <cstdio>
20 +
21 +#ifdef __clang__
22 +RAPIDJSON_DIAG_PUSH
23 +RAPIDJSON_DIAG_OFF(unreachable-code)
24 +#endif
25 +
26 +RAPIDJSON_NAMESPACE_BEGIN
27 +
28 +//! Wrapper of C file stream for input using fread().
29 +/*!
30 + \note implements Stream concept
31 +*/
32 +class FileWriteStream {
33 +public:
34 + typedef char Ch; //!< Character type. Only support char.
35 +
36 + FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
37 + RAPIDJSON_ASSERT(fp_ != 0);
38 + }
39 +
40 + void Put(char c) {
41 + if (current_ >= bufferEnd_)
42 + Flush();
43 +
44 + *current_++ = c;
45 + }
46 +
47 + void PutN(char c, size_t n) {
48 + size_t avail = static_cast<size_t>(bufferEnd_ - current_);
49 + while (n > avail) {
50 + std::memset(current_, c, avail);
51 + current_ += avail;
52 + Flush();
53 + n -= avail;
54 + avail = static_cast<size_t>(bufferEnd_ - current_);
55 + }
56 +
57 + if (n > 0) {
58 + std::memset(current_, c, n);
59 + current_ += n;
60 + }
61 + }
62 +
63 + void Flush() {
64 + if (current_ != buffer_) {
65 + size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
66 + if (result < static_cast<size_t>(current_ - buffer_)) {
67 + // failure deliberately ignored at this time
68 + // added to avoid warn_unused_result build errors
69 + }
70 + current_ = buffer_;
71 + }
72 + }
73 +
74 + // Not implemented
75 + char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
76 + char Take() { RAPIDJSON_ASSERT(false); return 0; }
77 + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
78 + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
79 + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
80 +
81 +private:
82 + // Prohibit copy constructor & assignment operator.
83 + FileWriteStream(const FileWriteStream&);
84 + FileWriteStream& operator=(const FileWriteStream&);
85 +
86 + std::FILE* fp_;
87 + char *buffer_;
88 + char *bufferEnd_;
89 + char *current_;
90 +};
91 +
92 +//! Implement specialized version of PutN() with memset() for better performance.
93 +template<>
94 +inline void PutN(FileWriteStream& stream, char c, size_t n) {
95 + stream.PutN(c, n);
96 +}
97 +
98 +RAPIDJSON_NAMESPACE_END
99 +
100 +#ifdef __clang__
101 +RAPIDJSON_DIAG_POP
102 +#endif
103 +
104 +#endif // RAPIDJSON_FILESTREAM_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_FWD_H_
16 +#define RAPIDJSON_FWD_H_
17 +
18 +#include "rapidjson.h"
19 +
20 +RAPIDJSON_NAMESPACE_BEGIN
21 +
22 +// encodings.h
23 +
24 +template<typename CharType> struct UTF8;
25 +template<typename CharType> struct UTF16;
26 +template<typename CharType> struct UTF16BE;
27 +template<typename CharType> struct UTF16LE;
28 +template<typename CharType> struct UTF32;
29 +template<typename CharType> struct UTF32BE;
30 +template<typename CharType> struct UTF32LE;
31 +template<typename CharType> struct ASCII;
32 +template<typename CharType> struct AutoUTF;
33 +
34 +template<typename SourceEncoding, typename TargetEncoding>
35 +struct Transcoder;
36 +
37 +// allocators.h
38 +
39 +class CrtAllocator;
40 +
41 +template <typename BaseAllocator>
42 +class MemoryPoolAllocator;
43 +
44 +// stream.h
45 +
46 +template <typename Encoding>
47 +struct GenericStringStream;
48 +
49 +typedef GenericStringStream<UTF8<char> > StringStream;
50 +
51 +template <typename Encoding>
52 +struct GenericInsituStringStream;
53 +
54 +typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
55 +
56 +// stringbuffer.h
57 +
58 +template <typename Encoding, typename Allocator>
59 +class GenericStringBuffer;
60 +
61 +typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
62 +
63 +// filereadstream.h
64 +
65 +class FileReadStream;
66 +
67 +// filewritestream.h
68 +
69 +class FileWriteStream;
70 +
71 +// memorybuffer.h
72 +
73 +template <typename Allocator>
74 +struct GenericMemoryBuffer;
75 +
76 +typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
77 +
78 +// memorystream.h
79 +
80 +struct MemoryStream;
81 +
82 +// reader.h
83 +
84 +template<typename Encoding, typename Derived>
85 +struct BaseReaderHandler;
86 +
87 +template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
88 +class GenericReader;
89 +
90 +typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
91 +
92 +// writer.h
93 +
94 +template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
95 +class Writer;
96 +
97 +// prettywriter.h
98 +
99 +template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
100 +class PrettyWriter;
101 +
102 +// document.h
103 +
104 +template <typename Encoding, typename Allocator>
105 +struct GenericMember;
106 +
107 +template <bool Const, typename Encoding, typename Allocator>
108 +class GenericMemberIterator;
109 +
110 +template<typename CharType>
111 +struct GenericStringRef;
112 +
113 +template <typename Encoding, typename Allocator>
114 +class GenericValue;
115 +
116 +typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
117 +
118 +template <typename Encoding, typename Allocator, typename StackAllocator>
119 +class GenericDocument;
120 +
121 +typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
122 +
123 +// pointer.h
124 +
125 +template <typename ValueType, typename Allocator>
126 +class GenericPointer;
127 +
128 +typedef GenericPointer<Value, CrtAllocator> Pointer;
129 +
130 +// schema.h
131 +
132 +template <typename SchemaDocumentType>
133 +class IGenericRemoteSchemaDocumentProvider;
134 +
135 +template <typename ValueT, typename Allocator>
136 +class GenericSchemaDocument;
137 +
138 +typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
139 +typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
140 +
141 +template <
142 + typename SchemaDocumentType,
143 + typename OutputHandler,
144 + typename StateAllocator>
145 +class GenericSchemaValidator;
146 +
147 +typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
148 +
149 +RAPIDJSON_NAMESPACE_END
150 +
151 +#endif // RAPIDJSON_RAPIDJSONFWD_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_BIGINTEGER_H_
16 +#define RAPIDJSON_BIGINTEGER_H_
17 +
18 +#include "../rapidjson.h"
19 +
20 +#if defined(_MSC_VER) && defined(_M_AMD64)
21 +#include <intrin.h> // for _umul128
22 +#pragma intrinsic(_umul128)
23 +#endif
24 +
25 +RAPIDJSON_NAMESPACE_BEGIN
26 +namespace internal {
27 +
28 +class BigInteger {
29 +public:
30 + typedef uint64_t Type;
31 +
32 + BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
33 + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
34 + }
35 +
36 + explicit BigInteger(uint64_t u) : count_(1) {
37 + digits_[0] = u;
38 + }
39 +
40 + BigInteger(const char* decimals, size_t length) : count_(1) {
41 + RAPIDJSON_ASSERT(length > 0);
42 + digits_[0] = 0;
43 + size_t i = 0;
44 + const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
45 + while (length >= kMaxDigitPerIteration) {
46 + AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
47 + length -= kMaxDigitPerIteration;
48 + i += kMaxDigitPerIteration;
49 + }
50 +
51 + if (length > 0)
52 + AppendDecimal64(decimals + i, decimals + i + length);
53 + }
54 +
55 + BigInteger& operator=(const BigInteger &rhs)
56 + {
57 + if (this != &rhs) {
58 + count_ = rhs.count_;
59 + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
60 + }
61 + return *this;
62 + }
63 +
64 + BigInteger& operator=(uint64_t u) {
65 + digits_[0] = u;
66 + count_ = 1;
67 + return *this;
68 + }
69 +
70 + BigInteger& operator+=(uint64_t u) {
71 + Type backup = digits_[0];
72 + digits_[0] += u;
73 + for (size_t i = 0; i < count_ - 1; i++) {
74 + if (digits_[i] >= backup)
75 + return *this; // no carry
76 + backup = digits_[i + 1];
77 + digits_[i + 1] += 1;
78 + }
79 +
80 + // Last carry
81 + if (digits_[count_ - 1] < backup)
82 + PushBack(1);
83 +
84 + return *this;
85 + }
86 +
87 + BigInteger& operator*=(uint64_t u) {
88 + if (u == 0) return *this = 0;
89 + if (u == 1) return *this;
90 + if (*this == 1) return *this = u;
91 +
92 + uint64_t k = 0;
93 + for (size_t i = 0; i < count_; i++) {
94 + uint64_t hi;
95 + digits_[i] = MulAdd64(digits_[i], u, k, &hi);
96 + k = hi;
97 + }
98 +
99 + if (k > 0)
100 + PushBack(k);
101 +
102 + return *this;
103 + }
104 +
105 + BigInteger& operator*=(uint32_t u) {
106 + if (u == 0) return *this = 0;
107 + if (u == 1) return *this;
108 + if (*this == 1) return *this = u;
109 +
110 + uint64_t k = 0;
111 + for (size_t i = 0; i < count_; i++) {
112 + const uint64_t c = digits_[i] >> 32;
113 + const uint64_t d = digits_[i] & 0xFFFFFFFF;
114 + const uint64_t uc = u * c;
115 + const uint64_t ud = u * d;
116 + const uint64_t p0 = ud + k;
117 + const uint64_t p1 = uc + (p0 >> 32);
118 + digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
119 + k = p1 >> 32;
120 + }
121 +
122 + if (k > 0)
123 + PushBack(k);
124 +
125 + return *this;
126 + }
127 +
128 + BigInteger& operator<<=(size_t shift) {
129 + if (IsZero() || shift == 0) return *this;
130 +
131 + size_t offset = shift / kTypeBit;
132 + size_t interShift = shift % kTypeBit;
133 + RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
134 +
135 + if (interShift == 0) {
136 + std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
137 + count_ += offset;
138 + }
139 + else {
140 + digits_[count_] = 0;
141 + for (size_t i = count_; i > 0; i--)
142 + digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
143 + digits_[offset] = digits_[0] << interShift;
144 + count_ += offset;
145 + if (digits_[count_])
146 + count_++;
147 + }
148 +
149 + std::memset(digits_, 0, offset * sizeof(Type));
150 +
151 + return *this;
152 + }
153 +
154 + bool operator==(const BigInteger& rhs) const {
155 + return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
156 + }
157 +
158 + bool operator==(const Type rhs) const {
159 + return count_ == 1 && digits_[0] == rhs;
160 + }
161 +
162 + BigInteger& MultiplyPow5(unsigned exp) {
163 + static const uint32_t kPow5[12] = {
164 + 5,
165 + 5 * 5,
166 + 5 * 5 * 5,
167 + 5 * 5 * 5 * 5,
168 + 5 * 5 * 5 * 5 * 5,
169 + 5 * 5 * 5 * 5 * 5 * 5,
170 + 5 * 5 * 5 * 5 * 5 * 5 * 5,
171 + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
172 + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
173 + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
174 + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
175 + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
176 + };
177 + if (exp == 0) return *this;
178 + for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
179 + for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
180 + if (exp > 0) *this *= kPow5[exp - 1];
181 + return *this;
182 + }
183 +
184 + // Compute absolute difference of this and rhs.
185 + // Assume this != rhs
186 + bool Difference(const BigInteger& rhs, BigInteger* out) const {
187 + int cmp = Compare(rhs);
188 + RAPIDJSON_ASSERT(cmp != 0);
189 + const BigInteger *a, *b; // Makes a > b
190 + bool ret;
191 + if (cmp < 0) { a = &rhs; b = this; ret = true; }
192 + else { a = this; b = &rhs; ret = false; }
193 +
194 + Type borrow = 0;
195 + for (size_t i = 0; i < a->count_; i++) {
196 + Type d = a->digits_[i] - borrow;
197 + if (i < b->count_)
198 + d -= b->digits_[i];
199 + borrow = (d > a->digits_[i]) ? 1 : 0;
200 + out->digits_[i] = d;
201 + if (d != 0)
202 + out->count_ = i + 1;
203 + }
204 +
205 + return ret;
206 + }
207 +
208 + int Compare(const BigInteger& rhs) const {
209 + if (count_ != rhs.count_)
210 + return count_ < rhs.count_ ? -1 : 1;
211 +
212 + for (size_t i = count_; i-- > 0;)
213 + if (digits_[i] != rhs.digits_[i])
214 + return digits_[i] < rhs.digits_[i] ? -1 : 1;
215 +
216 + return 0;
217 + }
218 +
219 + size_t GetCount() const { return count_; }
220 + Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
221 + bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
222 +
223 +private:
224 + void AppendDecimal64(const char* begin, const char* end) {
225 + uint64_t u = ParseUint64(begin, end);
226 + if (IsZero())
227 + *this = u;
228 + else {
229 + unsigned exp = static_cast<unsigned>(end - begin);
230 + (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
231 + }
232 + }
233 +
234 + void PushBack(Type digit) {
235 + RAPIDJSON_ASSERT(count_ < kCapacity);
236 + digits_[count_++] = digit;
237 + }
238 +
239 + static uint64_t ParseUint64(const char* begin, const char* end) {
240 + uint64_t r = 0;
241 + for (const char* p = begin; p != end; ++p) {
242 + RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
243 + r = r * 10u + static_cast<unsigned>(*p - '0');
244 + }
245 + return r;
246 + }
247 +
248 + // Assume a * b + k < 2^128
249 + static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
250 +#if defined(_MSC_VER) && defined(_M_AMD64)
251 + uint64_t low = _umul128(a, b, outHigh) + k;
252 + if (low < k)
253 + (*outHigh)++;
254 + return low;
255 +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
256 + __extension__ typedef unsigned __int128 uint128;
257 + uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
258 + p += k;
259 + *outHigh = static_cast<uint64_t>(p >> 64);
260 + return static_cast<uint64_t>(p);
261 +#else
262 + const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
263 + uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
264 + x1 += (x0 >> 32); // can't give carry
265 + x1 += x2;
266 + if (x1 < x2)
267 + x3 += (static_cast<uint64_t>(1) << 32);
268 + uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
269 + uint64_t hi = x3 + (x1 >> 32);
270 +
271 + lo += k;
272 + if (lo < k)
273 + hi++;
274 + *outHigh = hi;
275 + return lo;
276 +#endif
277 + }
278 +
279 + static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
280 + static const size_t kCapacity = kBitCount / sizeof(Type);
281 + static const size_t kTypeBit = sizeof(Type) * 8;
282 +
283 + Type digits_[kCapacity];
284 + size_t count_;
285 +};
286 +
287 +} // namespace internal
288 +RAPIDJSON_NAMESPACE_END
289 +
290 +#endif // RAPIDJSON_BIGINTEGER_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
16 +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
17 +// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
18 +
19 +#ifndef RAPIDJSON_DIYFP_H_
20 +#define RAPIDJSON_DIYFP_H_
21 +
22 +#include "../rapidjson.h"
23 +
24 +#if defined(_MSC_VER) && defined(_M_AMD64)
25 +#include <intrin.h>
26 +#pragma intrinsic(_BitScanReverse64)
27 +#pragma intrinsic(_umul128)
28 +#endif
29 +
30 +RAPIDJSON_NAMESPACE_BEGIN
31 +namespace internal {
32 +
33 +#ifdef __GNUC__
34 +RAPIDJSON_DIAG_PUSH
35 +RAPIDJSON_DIAG_OFF(effc++)
36 +#endif
37 +
38 +#ifdef __clang__
39 +RAPIDJSON_DIAG_PUSH
40 +RAPIDJSON_DIAG_OFF(padded)
41 +#endif
42 +
43 +struct DiyFp {
44 + DiyFp() : f(), e() {}
45 +
46 + DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
47 +
48 + explicit DiyFp(double d) {
49 + union {
50 + double d;
51 + uint64_t u64;
52 + } u = { d };
53 +
54 + int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
55 + uint64_t significand = (u.u64 & kDpSignificandMask);
56 + if (biased_e != 0) {
57 + f = significand + kDpHiddenBit;
58 + e = biased_e - kDpExponentBias;
59 + }
60 + else {
61 + f = significand;
62 + e = kDpMinExponent + 1;
63 + }
64 + }
65 +
66 + DiyFp operator-(const DiyFp& rhs) const {
67 + return DiyFp(f - rhs.f, e);
68 + }
69 +
70 + DiyFp operator*(const DiyFp& rhs) const {
71 +#if defined(_MSC_VER) && defined(_M_AMD64)
72 + uint64_t h;
73 + uint64_t l = _umul128(f, rhs.f, &h);
74 + if (l & (uint64_t(1) << 63)) // rounding
75 + h++;
76 + return DiyFp(h, e + rhs.e + 64);
77 +#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
78 + __extension__ typedef unsigned __int128 uint128;
79 + uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
80 + uint64_t h = static_cast<uint64_t>(p >> 64);
81 + uint64_t l = static_cast<uint64_t>(p);
82 + if (l & (uint64_t(1) << 63)) // rounding
83 + h++;
84 + return DiyFp(h, e + rhs.e + 64);
85 +#else
86 + const uint64_t M32 = 0xFFFFFFFF;
87 + const uint64_t a = f >> 32;
88 + const uint64_t b = f & M32;
89 + const uint64_t c = rhs.f >> 32;
90 + const uint64_t d = rhs.f & M32;
91 + const uint64_t ac = a * c;
92 + const uint64_t bc = b * c;
93 + const uint64_t ad = a * d;
94 + const uint64_t bd = b * d;
95 + uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
96 + tmp += 1U << 31; /// mult_round
97 + return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
98 +#endif
99 + }
100 +
101 + DiyFp Normalize() const {
102 +#if defined(_MSC_VER) && defined(_M_AMD64)
103 + unsigned long index;
104 + _BitScanReverse64(&index, f);
105 + return DiyFp(f << (63 - index), e - (63 - index));
106 +#elif defined(__GNUC__) && __GNUC__ >= 4
107 + int s = __builtin_clzll(f);
108 + return DiyFp(f << s, e - s);
109 +#else
110 + DiyFp res = *this;
111 + while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
112 + res.f <<= 1;
113 + res.e--;
114 + }
115 + return res;
116 +#endif
117 + }
118 +
119 + DiyFp NormalizeBoundary() const {
120 + DiyFp res = *this;
121 + while (!(res.f & (kDpHiddenBit << 1))) {
122 + res.f <<= 1;
123 + res.e--;
124 + }
125 + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
126 + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
127 + return res;
128 + }
129 +
130 + void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
131 + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
132 + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
133 + mi.f <<= mi.e - pl.e;
134 + mi.e = pl.e;
135 + *plus = pl;
136 + *minus = mi;
137 + }
138 +
139 + double ToDouble() const {
140 + union {
141 + double d;
142 + uint64_t u64;
143 + }u;
144 + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
145 + static_cast<uint64_t>(e + kDpExponentBias);
146 + u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
147 + return u.d;
148 + }
149 +
150 + static const int kDiySignificandSize = 64;
151 + static const int kDpSignificandSize = 52;
152 + static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
153 + static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
154 + static const int kDpMinExponent = -kDpExponentBias;
155 + static const int kDpDenormalExponent = -kDpExponentBias + 1;
156 + static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
157 + static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
158 + static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
159 +
160 + uint64_t f;
161 + int e;
162 +};
163 +
164 +inline DiyFp GetCachedPowerByIndex(size_t index) {
165 + // 10^-348, 10^-340, ..., 10^340
166 + static const uint64_t kCachedPowers_F[] = {
167 + RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
168 + RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
169 + RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
170 + RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
171 + RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
172 + RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
173 + RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
174 + RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
175 + RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
176 + RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
177 + RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
178 + RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
179 + RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
180 + RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
181 + RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
182 + RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
183 + RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
184 + RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
185 + RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
186 + RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
187 + RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
188 + RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
189 + RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
190 + RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
191 + RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
192 + RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
193 + RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
194 + RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
195 + RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
196 + RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
197 + RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
198 + RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
199 + RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
200 + RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
201 + RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
202 + RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
203 + RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
204 + RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
205 + RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
206 + RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
207 + RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
208 + RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
209 + RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
210 + RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
211 + };
212 + static const int16_t kCachedPowers_E[] = {
213 + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
214 + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
215 + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
216 + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
217 + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
218 + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
219 + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
220 + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
221 + 907, 933, 960, 986, 1013, 1039, 1066
222 + };
223 + return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
224 +}
225 +
226 +inline DiyFp GetCachedPower(int e, int* K) {
227 +
228 + //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
229 + double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
230 + int k = static_cast<int>(dk);
231 + if (dk - k > 0.0)
232 + k++;
233 +
234 + unsigned index = static_cast<unsigned>((k >> 3) + 1);
235 + *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
236 +
237 + return GetCachedPowerByIndex(index);
238 +}
239 +
240 +inline DiyFp GetCachedPower10(int exp, int *outExp) {
241 + unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
242 + *outExp = -348 + static_cast<int>(index) * 8;
243 + return GetCachedPowerByIndex(index);
244 + }
245 +
246 +#ifdef __GNUC__
247 +RAPIDJSON_DIAG_POP
248 +#endif
249 +
250 +#ifdef __clang__
251 +RAPIDJSON_DIAG_POP
252 +RAPIDJSON_DIAG_OFF(padded)
253 +#endif
254 +
255 +} // namespace internal
256 +RAPIDJSON_NAMESPACE_END
257 +
258 +#endif // RAPIDJSON_DIYFP_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
16 +// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
17 +// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
18 +
19 +#ifndef RAPIDJSON_DTOA_
20 +#define RAPIDJSON_DTOA_
21 +
22 +#include "itoa.h" // GetDigitsLut()
23 +#include "diyfp.h"
24 +#include "ieee754.h"
25 +
26 +RAPIDJSON_NAMESPACE_BEGIN
27 +namespace internal {
28 +
29 +#ifdef __GNUC__
30 +RAPIDJSON_DIAG_PUSH
31 +RAPIDJSON_DIAG_OFF(effc++)
32 +RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
33 +#endif
34 +
35 +inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
36 + while (rest < wp_w && delta - rest >= ten_kappa &&
37 + (rest + ten_kappa < wp_w || /// closer
38 + wp_w - rest > rest + ten_kappa - wp_w)) {
39 + buffer[len - 1]--;
40 + rest += ten_kappa;
41 + }
42 +}
43 +
44 +inline int CountDecimalDigit32(uint32_t n) {
45 + // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
46 + if (n < 10) return 1;
47 + if (n < 100) return 2;
48 + if (n < 1000) return 3;
49 + if (n < 10000) return 4;
50 + if (n < 100000) return 5;
51 + if (n < 1000000) return 6;
52 + if (n < 10000000) return 7;
53 + if (n < 100000000) return 8;
54 + // Will not reach 10 digits in DigitGen()
55 + //if (n < 1000000000) return 9;
56 + //return 10;
57 + return 9;
58 +}
59 +
60 +inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
61 + static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
62 + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
63 + const DiyFp wp_w = Mp - W;
64 + uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
65 + uint64_t p2 = Mp.f & (one.f - 1);
66 + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
67 + *len = 0;
68 +
69 + while (kappa > 0) {
70 + uint32_t d = 0;
71 + switch (kappa) {
72 + case 9: d = p1 / 100000000; p1 %= 100000000; break;
73 + case 8: d = p1 / 10000000; p1 %= 10000000; break;
74 + case 7: d = p1 / 1000000; p1 %= 1000000; break;
75 + case 6: d = p1 / 100000; p1 %= 100000; break;
76 + case 5: d = p1 / 10000; p1 %= 10000; break;
77 + case 4: d = p1 / 1000; p1 %= 1000; break;
78 + case 3: d = p1 / 100; p1 %= 100; break;
79 + case 2: d = p1 / 10; p1 %= 10; break;
80 + case 1: d = p1; p1 = 0; break;
81 + default:;
82 + }
83 + if (d || *len)
84 + buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
85 + kappa--;
86 + uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
87 + if (tmp <= delta) {
88 + *K += kappa;
89 + GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
90 + return;
91 + }
92 + }
93 +
94 + // kappa = 0
95 + for (;;) {
96 + p2 *= 10;
97 + delta *= 10;
98 + char d = static_cast<char>(p2 >> -one.e);
99 + if (d || *len)
100 + buffer[(*len)++] = static_cast<char>('0' + d);
101 + p2 &= one.f - 1;
102 + kappa--;
103 + if (p2 < delta) {
104 + *K += kappa;
105 + int index = -kappa;
106 + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
107 + return;
108 + }
109 + }
110 +}
111 +
112 +inline void Grisu2(double value, char* buffer, int* length, int* K) {
113 + const DiyFp v(value);
114 + DiyFp w_m, w_p;
115 + v.NormalizedBoundaries(&w_m, &w_p);
116 +
117 + const DiyFp c_mk = GetCachedPower(w_p.e, K);
118 + const DiyFp W = v.Normalize() * c_mk;
119 + DiyFp Wp = w_p * c_mk;
120 + DiyFp Wm = w_m * c_mk;
121 + Wm.f++;
122 + Wp.f--;
123 + DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
124 +}
125 +
126 +inline char* WriteExponent(int K, char* buffer) {
127 + if (K < 0) {
128 + *buffer++ = '-';
129 + K = -K;
130 + }
131 +
132 + if (K >= 100) {
133 + *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
134 + K %= 100;
135 + const char* d = GetDigitsLut() + K * 2;
136 + *buffer++ = d[0];
137 + *buffer++ = d[1];
138 + }
139 + else if (K >= 10) {
140 + const char* d = GetDigitsLut() + K * 2;
141 + *buffer++ = d[0];
142 + *buffer++ = d[1];
143 + }
144 + else
145 + *buffer++ = static_cast<char>('0' + static_cast<char>(K));
146 +
147 + return buffer;
148 +}
149 +
150 +inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
151 + const int kk = length + k; // 10^(kk-1) <= v < 10^kk
152 +
153 + if (0 <= k && kk <= 21) {
154 + // 1234e7 -> 12340000000
155 + for (int i = length; i < kk; i++)
156 + buffer[i] = '0';
157 + buffer[kk] = '.';
158 + buffer[kk + 1] = '0';
159 + return &buffer[kk + 2];
160 + }
161 + else if (0 < kk && kk <= 21) {
162 + // 1234e-2 -> 12.34
163 + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
164 + buffer[kk] = '.';
165 + if (0 > k + maxDecimalPlaces) {
166 + // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
167 + // Remove extra trailing zeros (at least one) after truncation.
168 + for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
169 + if (buffer[i] != '0')
170 + return &buffer[i + 1];
171 + return &buffer[kk + 2]; // Reserve one zero
172 + }
173 + else
174 + return &buffer[length + 1];
175 + }
176 + else if (-6 < kk && kk <= 0) {
177 + // 1234e-6 -> 0.001234
178 + const int offset = 2 - kk;
179 + std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
180 + buffer[0] = '0';
181 + buffer[1] = '.';
182 + for (int i = 2; i < offset; i++)
183 + buffer[i] = '0';
184 + if (length - kk > maxDecimalPlaces) {
185 + // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
186 + // Remove extra trailing zeros (at least one) after truncation.
187 + for (int i = maxDecimalPlaces + 1; i > 2; i--)
188 + if (buffer[i] != '0')
189 + return &buffer[i + 1];
190 + return &buffer[3]; // Reserve one zero
191 + }
192 + else
193 + return &buffer[length + offset];
194 + }
195 + else if (kk < -maxDecimalPlaces) {
196 + // Truncate to zero
197 + buffer[0] = '0';
198 + buffer[1] = '.';
199 + buffer[2] = '0';
200 + return &buffer[3];
201 + }
202 + else if (length == 1) {
203 + // 1e30
204 + buffer[1] = 'e';
205 + return WriteExponent(kk - 1, &buffer[2]);
206 + }
207 + else {
208 + // 1234e30 -> 1.234e33
209 + std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
210 + buffer[1] = '.';
211 + buffer[length + 1] = 'e';
212 + return WriteExponent(kk - 1, &buffer[0 + length + 2]);
213 + }
214 +}
215 +
216 +inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
217 + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
218 + Double d(value);
219 + if (d.IsZero()) {
220 + if (d.Sign())
221 + *buffer++ = '-'; // -0.0, Issue #289
222 + buffer[0] = '0';
223 + buffer[1] = '.';
224 + buffer[2] = '0';
225 + return &buffer[3];
226 + }
227 + else {
228 + if (value < 0) {
229 + *buffer++ = '-';
230 + value = -value;
231 + }
232 + int length, K;
233 + Grisu2(value, buffer, &length, &K);
234 + return Prettify(buffer, length, K, maxDecimalPlaces);
235 + }
236 +}
237 +
238 +#ifdef __GNUC__
239 +RAPIDJSON_DIAG_POP
240 +#endif
241 +
242 +} // namespace internal
243 +RAPIDJSON_NAMESPACE_END
244 +
245 +#endif // RAPIDJSON_DTOA_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_IEEE754_
16 +#define RAPIDJSON_IEEE754_
17 +
18 +#include "../rapidjson.h"
19 +
20 +RAPIDJSON_NAMESPACE_BEGIN
21 +namespace internal {
22 +
23 +class Double {
24 +public:
25 + Double() {}
26 + Double(double d) : d_(d) {}
27 + Double(uint64_t u) : u_(u) {}
28 +
29 + double Value() const { return d_; }
30 + uint64_t Uint64Value() const { return u_; }
31 +
32 + double NextPositiveDouble() const {
33 + RAPIDJSON_ASSERT(!Sign());
34 + return Double(u_ + 1).Value();
35 + }
36 +
37 + bool Sign() const { return (u_ & kSignMask) != 0; }
38 + uint64_t Significand() const { return u_ & kSignificandMask; }
39 + int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
40 +
41 + bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
42 + bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
43 + bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
44 + bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
45 + bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
46 +
47 + uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
48 + int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
49 + uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
50 +
51 + static int EffectiveSignificandSize(int order) {
52 + if (order >= -1021)
53 + return 53;
54 + else if (order <= -1074)
55 + return 0;
56 + else
57 + return order + 1074;
58 + }
59 +
60 +private:
61 + static const int kSignificandSize = 52;
62 + static const int kExponentBias = 0x3FF;
63 + static const int kDenormalExponent = 1 - kExponentBias;
64 + static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
65 + static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
66 + static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
67 + static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
68 +
69 + union {
70 + double d_;
71 + uint64_t u_;
72 + };
73 +};
74 +
75 +} // namespace internal
76 +RAPIDJSON_NAMESPACE_END
77 +
78 +#endif // RAPIDJSON_IEEE754_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_ITOA_
16 +#define RAPIDJSON_ITOA_
17 +
18 +#include "../rapidjson.h"
19 +
20 +RAPIDJSON_NAMESPACE_BEGIN
21 +namespace internal {
22 +
23 +inline const char* GetDigitsLut() {
24 + static const char cDigitsLut[200] = {
25 + '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
26 + '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
27 + '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
28 + '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
29 + '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
30 + '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
31 + '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
32 + '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
33 + '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
34 + '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
35 + };
36 + return cDigitsLut;
37 +}
38 +
39 +inline char* u32toa(uint32_t value, char* buffer) {
40 + const char* cDigitsLut = GetDigitsLut();
41 +
42 + if (value < 10000) {
43 + const uint32_t d1 = (value / 100) << 1;
44 + const uint32_t d2 = (value % 100) << 1;
45 +
46 + if (value >= 1000)
47 + *buffer++ = cDigitsLut[d1];
48 + if (value >= 100)
49 + *buffer++ = cDigitsLut[d1 + 1];
50 + if (value >= 10)
51 + *buffer++ = cDigitsLut[d2];
52 + *buffer++ = cDigitsLut[d2 + 1];
53 + }
54 + else if (value < 100000000) {
55 + // value = bbbbcccc
56 + const uint32_t b = value / 10000;
57 + const uint32_t c = value % 10000;
58 +
59 + const uint32_t d1 = (b / 100) << 1;
60 + const uint32_t d2 = (b % 100) << 1;
61 +
62 + const uint32_t d3 = (c / 100) << 1;
63 + const uint32_t d4 = (c % 100) << 1;
64 +
65 + if (value >= 10000000)
66 + *buffer++ = cDigitsLut[d1];
67 + if (value >= 1000000)
68 + *buffer++ = cDigitsLut[d1 + 1];
69 + if (value >= 100000)
70 + *buffer++ = cDigitsLut[d2];
71 + *buffer++ = cDigitsLut[d2 + 1];
72 +
73 + *buffer++ = cDigitsLut[d3];
74 + *buffer++ = cDigitsLut[d3 + 1];
75 + *buffer++ = cDigitsLut[d4];
76 + *buffer++ = cDigitsLut[d4 + 1];
77 + }
78 + else {
79 + // value = aabbbbcccc in decimal
80 +
81 + const uint32_t a = value / 100000000; // 1 to 42
82 + value %= 100000000;
83 +
84 + if (a >= 10) {
85 + const unsigned i = a << 1;
86 + *buffer++ = cDigitsLut[i];
87 + *buffer++ = cDigitsLut[i + 1];
88 + }
89 + else
90 + *buffer++ = static_cast<char>('0' + static_cast<char>(a));
91 +
92 + const uint32_t b = value / 10000; // 0 to 9999
93 + const uint32_t c = value % 10000; // 0 to 9999
94 +
95 + const uint32_t d1 = (b / 100) << 1;
96 + const uint32_t d2 = (b % 100) << 1;
97 +
98 + const uint32_t d3 = (c / 100) << 1;
99 + const uint32_t d4 = (c % 100) << 1;
100 +
101 + *buffer++ = cDigitsLut[d1];
102 + *buffer++ = cDigitsLut[d1 + 1];
103 + *buffer++ = cDigitsLut[d2];
104 + *buffer++ = cDigitsLut[d2 + 1];
105 + *buffer++ = cDigitsLut[d3];
106 + *buffer++ = cDigitsLut[d3 + 1];
107 + *buffer++ = cDigitsLut[d4];
108 + *buffer++ = cDigitsLut[d4 + 1];
109 + }
110 + return buffer;
111 +}
112 +
113 +inline char* i32toa(int32_t value, char* buffer) {
114 + uint32_t u = static_cast<uint32_t>(value);
115 + if (value < 0) {
116 + *buffer++ = '-';
117 + u = ~u + 1;
118 + }
119 +
120 + return u32toa(u, buffer);
121 +}
122 +
123 +inline char* u64toa(uint64_t value, char* buffer) {
124 + const char* cDigitsLut = GetDigitsLut();
125 + const uint64_t kTen8 = 100000000;
126 + const uint64_t kTen9 = kTen8 * 10;
127 + const uint64_t kTen10 = kTen8 * 100;
128 + const uint64_t kTen11 = kTen8 * 1000;
129 + const uint64_t kTen12 = kTen8 * 10000;
130 + const uint64_t kTen13 = kTen8 * 100000;
131 + const uint64_t kTen14 = kTen8 * 1000000;
132 + const uint64_t kTen15 = kTen8 * 10000000;
133 + const uint64_t kTen16 = kTen8 * kTen8;
134 +
135 + if (value < kTen8) {
136 + uint32_t v = static_cast<uint32_t>(value);
137 + if (v < 10000) {
138 + const uint32_t d1 = (v / 100) << 1;
139 + const uint32_t d2 = (v % 100) << 1;
140 +
141 + if (v >= 1000)
142 + *buffer++ = cDigitsLut[d1];
143 + if (v >= 100)
144 + *buffer++ = cDigitsLut[d1 + 1];
145 + if (v >= 10)
146 + *buffer++ = cDigitsLut[d2];
147 + *buffer++ = cDigitsLut[d2 + 1];
148 + }
149 + else {
150 + // value = bbbbcccc
151 + const uint32_t b = v / 10000;
152 + const uint32_t c = v % 10000;
153 +
154 + const uint32_t d1 = (b / 100) << 1;
155 + const uint32_t d2 = (b % 100) << 1;
156 +
157 + const uint32_t d3 = (c / 100) << 1;
158 + const uint32_t d4 = (c % 100) << 1;
159 +
160 + if (value >= 10000000)
161 + *buffer++ = cDigitsLut[d1];
162 + if (value >= 1000000)
163 + *buffer++ = cDigitsLut[d1 + 1];
164 + if (value >= 100000)
165 + *buffer++ = cDigitsLut[d2];
166 + *buffer++ = cDigitsLut[d2 + 1];
167 +
168 + *buffer++ = cDigitsLut[d3];
169 + *buffer++ = cDigitsLut[d3 + 1];
170 + *buffer++ = cDigitsLut[d4];
171 + *buffer++ = cDigitsLut[d4 + 1];
172 + }
173 + }
174 + else if (value < kTen16) {
175 + const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
176 + const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
177 +
178 + const uint32_t b0 = v0 / 10000;
179 + const uint32_t c0 = v0 % 10000;
180 +
181 + const uint32_t d1 = (b0 / 100) << 1;
182 + const uint32_t d2 = (b0 % 100) << 1;
183 +
184 + const uint32_t d3 = (c0 / 100) << 1;
185 + const uint32_t d4 = (c0 % 100) << 1;
186 +
187 + const uint32_t b1 = v1 / 10000;
188 + const uint32_t c1 = v1 % 10000;
189 +
190 + const uint32_t d5 = (b1 / 100) << 1;
191 + const uint32_t d6 = (b1 % 100) << 1;
192 +
193 + const uint32_t d7 = (c1 / 100) << 1;
194 + const uint32_t d8 = (c1 % 100) << 1;
195 +
196 + if (value >= kTen15)
197 + *buffer++ = cDigitsLut[d1];
198 + if (value >= kTen14)
199 + *buffer++ = cDigitsLut[d1 + 1];
200 + if (value >= kTen13)
201 + *buffer++ = cDigitsLut[d2];
202 + if (value >= kTen12)
203 + *buffer++ = cDigitsLut[d2 + 1];
204 + if (value >= kTen11)
205 + *buffer++ = cDigitsLut[d3];
206 + if (value >= kTen10)
207 + *buffer++ = cDigitsLut[d3 + 1];
208 + if (value >= kTen9)
209 + *buffer++ = cDigitsLut[d4];
210 + if (value >= kTen8)
211 + *buffer++ = cDigitsLut[d4 + 1];
212 +
213 + *buffer++ = cDigitsLut[d5];
214 + *buffer++ = cDigitsLut[d5 + 1];
215 + *buffer++ = cDigitsLut[d6];
216 + *buffer++ = cDigitsLut[d6 + 1];
217 + *buffer++ = cDigitsLut[d7];
218 + *buffer++ = cDigitsLut[d7 + 1];
219 + *buffer++ = cDigitsLut[d8];
220 + *buffer++ = cDigitsLut[d8 + 1];
221 + }
222 + else {
223 + const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
224 + value %= kTen16;
225 +
226 + if (a < 10)
227 + *buffer++ = static_cast<char>('0' + static_cast<char>(a));
228 + else if (a < 100) {
229 + const uint32_t i = a << 1;
230 + *buffer++ = cDigitsLut[i];
231 + *buffer++ = cDigitsLut[i + 1];
232 + }
233 + else if (a < 1000) {
234 + *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
235 +
236 + const uint32_t i = (a % 100) << 1;
237 + *buffer++ = cDigitsLut[i];
238 + *buffer++ = cDigitsLut[i + 1];
239 + }
240 + else {
241 + const uint32_t i = (a / 100) << 1;
242 + const uint32_t j = (a % 100) << 1;
243 + *buffer++ = cDigitsLut[i];
244 + *buffer++ = cDigitsLut[i + 1];
245 + *buffer++ = cDigitsLut[j];
246 + *buffer++ = cDigitsLut[j + 1];
247 + }
248 +
249 + const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
250 + const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
251 +
252 + const uint32_t b0 = v0 / 10000;
253 + const uint32_t c0 = v0 % 10000;
254 +
255 + const uint32_t d1 = (b0 / 100) << 1;
256 + const uint32_t d2 = (b0 % 100) << 1;
257 +
258 + const uint32_t d3 = (c0 / 100) << 1;
259 + const uint32_t d4 = (c0 % 100) << 1;
260 +
261 + const uint32_t b1 = v1 / 10000;
262 + const uint32_t c1 = v1 % 10000;
263 +
264 + const uint32_t d5 = (b1 / 100) << 1;
265 + const uint32_t d6 = (b1 % 100) << 1;
266 +
267 + const uint32_t d7 = (c1 / 100) << 1;
268 + const uint32_t d8 = (c1 % 100) << 1;
269 +
270 + *buffer++ = cDigitsLut[d1];
271 + *buffer++ = cDigitsLut[d1 + 1];
272 + *buffer++ = cDigitsLut[d2];
273 + *buffer++ = cDigitsLut[d2 + 1];
274 + *buffer++ = cDigitsLut[d3];
275 + *buffer++ = cDigitsLut[d3 + 1];
276 + *buffer++ = cDigitsLut[d4];
277 + *buffer++ = cDigitsLut[d4 + 1];
278 + *buffer++ = cDigitsLut[d5];
279 + *buffer++ = cDigitsLut[d5 + 1];
280 + *buffer++ = cDigitsLut[d6];
281 + *buffer++ = cDigitsLut[d6 + 1];
282 + *buffer++ = cDigitsLut[d7];
283 + *buffer++ = cDigitsLut[d7 + 1];
284 + *buffer++ = cDigitsLut[d8];
285 + *buffer++ = cDigitsLut[d8 + 1];
286 + }
287 +
288 + return buffer;
289 +}
290 +
291 +inline char* i64toa(int64_t value, char* buffer) {
292 + uint64_t u = static_cast<uint64_t>(value);
293 + if (value < 0) {
294 + *buffer++ = '-';
295 + u = ~u + 1;
296 + }
297 +
298 + return u64toa(u, buffer);
299 +}
300 +
301 +} // namespace internal
302 +RAPIDJSON_NAMESPACE_END
303 +
304 +#endif // RAPIDJSON_ITOA_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_INTERNAL_META_H_
16 +#define RAPIDJSON_INTERNAL_META_H_
17 +
18 +#include "../rapidjson.h"
19 +
20 +#ifdef __GNUC__
21 +RAPIDJSON_DIAG_PUSH
22 +RAPIDJSON_DIAG_OFF(effc++)
23 +#endif
24 +#if defined(_MSC_VER)
25 +RAPIDJSON_DIAG_PUSH
26 +RAPIDJSON_DIAG_OFF(6334)
27 +#endif
28 +
29 +#if RAPIDJSON_HAS_CXX11_TYPETRAITS
30 +#include <type_traits>
31 +#endif
32 +
33 +//@cond RAPIDJSON_INTERNAL
34 +RAPIDJSON_NAMESPACE_BEGIN
35 +namespace internal {
36 +
37 +// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
38 +template <typename T> struct Void { typedef void Type; };
39 +
40 +///////////////////////////////////////////////////////////////////////////////
41 +// BoolType, TrueType, FalseType
42 +//
43 +template <bool Cond> struct BoolType {
44 + static const bool Value = Cond;
45 + typedef BoolType Type;
46 +};
47 +typedef BoolType<true> TrueType;
48 +typedef BoolType<false> FalseType;
49 +
50 +
51 +///////////////////////////////////////////////////////////////////////////////
52 +// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
53 +//
54 +
55 +template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
56 +template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
57 +template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
58 +template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
59 +
60 +template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
61 +template <> struct AndExprCond<true, true> : TrueType {};
62 +template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
63 +template <> struct OrExprCond<false, false> : FalseType {};
64 +
65 +template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
66 +template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
67 +template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
68 +template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
69 +
70 +
71 +///////////////////////////////////////////////////////////////////////////////
72 +// AddConst, MaybeAddConst, RemoveConst
73 +template <typename T> struct AddConst { typedef const T Type; };
74 +template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
75 +template <typename T> struct RemoveConst { typedef T Type; };
76 +template <typename T> struct RemoveConst<const T> { typedef T Type; };
77 +
78 +
79 +///////////////////////////////////////////////////////////////////////////////
80 +// IsSame, IsConst, IsMoreConst, IsPointer
81 +//
82 +template <typename T, typename U> struct IsSame : FalseType {};
83 +template <typename T> struct IsSame<T, T> : TrueType {};
84 +
85 +template <typename T> struct IsConst : FalseType {};
86 +template <typename T> struct IsConst<const T> : TrueType {};
87 +
88 +template <typename CT, typename T>
89 +struct IsMoreConst
90 + : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
91 + BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
92 +
93 +template <typename T> struct IsPointer : FalseType {};
94 +template <typename T> struct IsPointer<T*> : TrueType {};
95 +
96 +///////////////////////////////////////////////////////////////////////////////
97 +// IsBaseOf
98 +//
99 +#if RAPIDJSON_HAS_CXX11_TYPETRAITS
100 +
101 +template <typename B, typename D> struct IsBaseOf
102 + : BoolType< ::std::is_base_of<B,D>::value> {};
103 +
104 +#else // simplified version adopted from Boost
105 +
106 +template<typename B, typename D> struct IsBaseOfImpl {
107 + RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
108 + RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
109 +
110 + typedef char (&Yes)[1];
111 + typedef char (&No) [2];
112 +
113 + template <typename T>
114 + static Yes Check(const D*, T);
115 + static No Check(const B*, int);
116 +
117 + struct Host {
118 + operator const B*() const;
119 + operator const D*();
120 + };
121 +
122 + enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
123 +};
124 +
125 +template <typename B, typename D> struct IsBaseOf
126 + : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
127 +
128 +#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
129 +
130 +
131 +//////////////////////////////////////////////////////////////////////////
132 +// EnableIf / DisableIf
133 +//
134 +template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
135 +template <typename T> struct EnableIfCond<false, T> { /* empty */ };
136 +
137 +template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
138 +template <typename T> struct DisableIfCond<true, T> { /* empty */ };
139 +
140 +template <typename Condition, typename T = void>
141 +struct EnableIf : EnableIfCond<Condition::Value, T> {};
142 +
143 +template <typename Condition, typename T = void>
144 +struct DisableIf : DisableIfCond<Condition::Value, T> {};
145 +
146 +// SFINAE helpers
147 +struct SfinaeTag {};
148 +template <typename T> struct RemoveSfinaeTag;
149 +template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
150 +
151 +#define RAPIDJSON_REMOVEFPTR_(type) \
152 + typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
153 + < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
154 +
155 +#define RAPIDJSON_ENABLEIF(cond) \
156 + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
157 + <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
158 +
159 +#define RAPIDJSON_DISABLEIF(cond) \
160 + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
161 + <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
162 +
163 +#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
164 + typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
165 + <RAPIDJSON_REMOVEFPTR_(cond), \
166 + RAPIDJSON_REMOVEFPTR_(returntype)>::Type
167 +
168 +#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
169 + typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
170 + <RAPIDJSON_REMOVEFPTR_(cond), \
171 + RAPIDJSON_REMOVEFPTR_(returntype)>::Type
172 +
173 +} // namespace internal
174 +RAPIDJSON_NAMESPACE_END
175 +//@endcond
176 +
177 +#if defined(__GNUC__) || defined(_MSC_VER)
178 +RAPIDJSON_DIAG_POP
179 +#endif
180 +
181 +#endif // RAPIDJSON_INTERNAL_META_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_POW10_
16 +#define RAPIDJSON_POW10_
17 +
18 +#include "../rapidjson.h"
19 +
20 +RAPIDJSON_NAMESPACE_BEGIN
21 +namespace internal {
22 +
23 +//! Computes integer powers of 10 in double (10.0^n).
24 +/*! This function uses lookup table for fast and accurate results.
25 + \param n non-negative exponent. Must <= 308.
26 + \return 10.0^n
27 +*/
28 +inline double Pow10(int n) {
29 + static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
30 + 1e+0,
31 + 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
32 + 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
33 + 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
34 + 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
35 + 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
36 + 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
37 + 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
38 + 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
39 + 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
40 + 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
41 + 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
42 + 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
43 + 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
44 + 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
45 + 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
46 + 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
47 + };
48 + RAPIDJSON_ASSERT(n >= 0 && n <= 308);
49 + return e[n];
50 +}
51 +
52 +} // namespace internal
53 +RAPIDJSON_NAMESPACE_END
54 +
55 +#endif // RAPIDJSON_POW10_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_INTERNAL_REGEX_H_
16 +#define RAPIDJSON_INTERNAL_REGEX_H_
17 +
18 +#include "../allocators.h"
19 +#include "../stream.h"
20 +#include "stack.h"
21 +
22 +#ifdef __clang__
23 +RAPIDJSON_DIAG_PUSH
24 +RAPIDJSON_DIAG_OFF(padded)
25 +RAPIDJSON_DIAG_OFF(switch-enum)
26 +RAPIDJSON_DIAG_OFF(implicit-fallthrough)
27 +#endif
28 +
29 +#ifdef __GNUC__
30 +RAPIDJSON_DIAG_PUSH
31 +RAPIDJSON_DIAG_OFF(effc++)
32 +#if __GNUC__ >= 7
33 +RAPIDJSON_DIAG_OFF(implicit-fallthrough)
34 +#endif
35 +#endif
36 +
37 +#ifdef _MSC_VER
38 +RAPIDJSON_DIAG_PUSH
39 +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
40 +#endif
41 +
42 +#ifndef RAPIDJSON_REGEX_VERBOSE
43 +#define RAPIDJSON_REGEX_VERBOSE 0
44 +#endif
45 +
46 +RAPIDJSON_NAMESPACE_BEGIN
47 +namespace internal {
48 +
49 +///////////////////////////////////////////////////////////////////////////////
50 +// DecodedStream
51 +
52 +template <typename SourceStream, typename Encoding>
53 +class DecodedStream {
54 +public:
55 + DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
56 + unsigned Peek() { return codepoint_; }
57 + unsigned Take() {
58 + unsigned c = codepoint_;
59 + if (c) // No further decoding when '\0'
60 + Decode();
61 + return c;
62 + }
63 +
64 +private:
65 + void Decode() {
66 + if (!Encoding::Decode(ss_, &codepoint_))
67 + codepoint_ = 0;
68 + }
69 +
70 + SourceStream& ss_;
71 + unsigned codepoint_;
72 +};
73 +
74 +///////////////////////////////////////////////////////////////////////////////
75 +// GenericRegex
76 +
77 +static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
78 +static const SizeType kRegexInvalidRange = ~SizeType(0);
79 +
80 +template <typename Encoding, typename Allocator>
81 +class GenericRegexSearch;
82 +
83 +//! Regular expression engine with subset of ECMAscript grammar.
84 +/*!
85 + Supported regular expression syntax:
86 + - \c ab Concatenation
87 + - \c a|b Alternation
88 + - \c a? Zero or one
89 + - \c a* Zero or more
90 + - \c a+ One or more
91 + - \c a{3} Exactly 3 times
92 + - \c a{3,} At least 3 times
93 + - \c a{3,5} 3 to 5 times
94 + - \c (ab) Grouping
95 + - \c ^a At the beginning
96 + - \c a$ At the end
97 + - \c . Any character
98 + - \c [abc] Character classes
99 + - \c [a-c] Character class range
100 + - \c [a-z0-9_] Character class combination
101 + - \c [^abc] Negated character classes
102 + - \c [^a-c] Negated character class range
103 + - \c [\b] Backspace (U+0008)
104 + - \c \\| \\\\ ... Escape characters
105 + - \c \\f Form feed (U+000C)
106 + - \c \\n Line feed (U+000A)
107 + - \c \\r Carriage return (U+000D)
108 + - \c \\t Tab (U+0009)
109 + - \c \\v Vertical tab (U+000B)
110 +
111 + \note This is a Thompson NFA engine, implemented with reference to
112 + Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
113 + https://swtch.com/~rsc/regexp/regexp1.html
114 +*/
115 +template <typename Encoding, typename Allocator = CrtAllocator>
116 +class GenericRegex {
117 +public:
118 + typedef Encoding EncodingType;
119 + typedef typename Encoding::Ch Ch;
120 + template <typename, typename> friend class GenericRegexSearch;
121 +
122 + GenericRegex(const Ch* source, Allocator* allocator = 0) :
123 + states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
124 + anchorBegin_(), anchorEnd_()
125 + {
126 + GenericStringStream<Encoding> ss(source);
127 + DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
128 + Parse(ds);
129 + }
130 +
131 + ~GenericRegex() {}
132 +
133 + bool IsValid() const {
134 + return root_ != kRegexInvalidState;
135 + }
136 +
137 +private:
138 + enum Operator {
139 + kZeroOrOne,
140 + kZeroOrMore,
141 + kOneOrMore,
142 + kConcatenation,
143 + kAlternation,
144 + kLeftParenthesis
145 + };
146 +
147 + static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
148 + static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
149 + static const unsigned kRangeNegationFlag = 0x80000000;
150 +
151 + struct Range {
152 + unsigned start; //
153 + unsigned end;
154 + SizeType next;
155 + };
156 +
157 + struct State {
158 + SizeType out; //!< Equals to kInvalid for matching state
159 + SizeType out1; //!< Equals to non-kInvalid for split
160 + SizeType rangeStart;
161 + unsigned codepoint;
162 + };
163 +
164 + struct Frag {
165 + Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
166 + SizeType start;
167 + SizeType out; //!< link-list of all output states
168 + SizeType minIndex;
169 + };
170 +
171 + State& GetState(SizeType index) {
172 + RAPIDJSON_ASSERT(index < stateCount_);
173 + return states_.template Bottom<State>()[index];
174 + }
175 +
176 + const State& GetState(SizeType index) const {
177 + RAPIDJSON_ASSERT(index < stateCount_);
178 + return states_.template Bottom<State>()[index];
179 + }
180 +
181 + Range& GetRange(SizeType index) {
182 + RAPIDJSON_ASSERT(index < rangeCount_);
183 + return ranges_.template Bottom<Range>()[index];
184 + }
185 +
186 + const Range& GetRange(SizeType index) const {
187 + RAPIDJSON_ASSERT(index < rangeCount_);
188 + return ranges_.template Bottom<Range>()[index];
189 + }
190 +
191 + template <typename InputStream>
192 + void Parse(DecodedStream<InputStream, Encoding>& ds) {
193 + Allocator allocator;
194 + Stack<Allocator> operandStack(&allocator, 256); // Frag
195 + Stack<Allocator> operatorStack(&allocator, 256); // Operator
196 + Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
197 +
198 + *atomCountStack.template Push<unsigned>() = 0;
199 +
200 + unsigned codepoint;
201 + while (ds.Peek() != 0) {
202 + switch (codepoint = ds.Take()) {
203 + case '^':
204 + anchorBegin_ = true;
205 + break;
206 +
207 + case '$':
208 + anchorEnd_ = true;
209 + break;
210 +
211 + case '|':
212 + while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
213 + if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
214 + return;
215 + *operatorStack.template Push<Operator>() = kAlternation;
216 + *atomCountStack.template Top<unsigned>() = 0;
217 + break;
218 +
219 + case '(':
220 + *operatorStack.template Push<Operator>() = kLeftParenthesis;
221 + *atomCountStack.template Push<unsigned>() = 0;
222 + break;
223 +
224 + case ')':
225 + while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
226 + if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
227 + return;
228 + if (operatorStack.Empty())
229 + return;
230 + operatorStack.template Pop<Operator>(1);
231 + atomCountStack.template Pop<unsigned>(1);
232 + ImplicitConcatenation(atomCountStack, operatorStack);
233 + break;
234 +
235 + case '?':
236 + if (!Eval(operandStack, kZeroOrOne))
237 + return;
238 + break;
239 +
240 + case '*':
241 + if (!Eval(operandStack, kZeroOrMore))
242 + return;
243 + break;
244 +
245 + case '+':
246 + if (!Eval(operandStack, kOneOrMore))
247 + return;
248 + break;
249 +
250 + case '{':
251 + {
252 + unsigned n, m;
253 + if (!ParseUnsigned(ds, &n))
254 + return;
255 +
256 + if (ds.Peek() == ',') {
257 + ds.Take();
258 + if (ds.Peek() == '}')
259 + m = kInfinityQuantifier;
260 + else if (!ParseUnsigned(ds, &m) || m < n)
261 + return;
262 + }
263 + else
264 + m = n;
265 +
266 + if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
267 + return;
268 + ds.Take();
269 + }
270 + break;
271 +
272 + case '.':
273 + PushOperand(operandStack, kAnyCharacterClass);
274 + ImplicitConcatenation(atomCountStack, operatorStack);
275 + break;
276 +
277 + case '[':
278 + {
279 + SizeType range;
280 + if (!ParseRange(ds, &range))
281 + return;
282 + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
283 + GetState(s).rangeStart = range;
284 + *operandStack.template Push<Frag>() = Frag(s, s, s);
285 + }
286 + ImplicitConcatenation(atomCountStack, operatorStack);
287 + break;
288 +
289 + case '\\': // Escape character
290 + if (!CharacterEscape(ds, &codepoint))
291 + return; // Unsupported escape character
292 + // fall through to default
293 +
294 + default: // Pattern character
295 + PushOperand(operandStack, codepoint);
296 + ImplicitConcatenation(atomCountStack, operatorStack);
297 + }
298 + }
299 +
300 + while (!operatorStack.Empty())
301 + if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
302 + return;
303 +
304 + // Link the operand to matching state.
305 + if (operandStack.GetSize() == sizeof(Frag)) {
306 + Frag* e = operandStack.template Pop<Frag>(1);
307 + Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
308 + root_ = e->start;
309 +
310 +#if RAPIDJSON_REGEX_VERBOSE
311 + printf("root: %d\n", root_);
312 + for (SizeType i = 0; i < stateCount_ ; i++) {
313 + State& s = GetState(i);
314 + printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
315 + }
316 + printf("\n");
317 +#endif
318 + }
319 + }
320 +
321 + SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
322 + State* s = states_.template Push<State>();
323 + s->out = out;
324 + s->out1 = out1;
325 + s->codepoint = codepoint;
326 + s->rangeStart = kRegexInvalidRange;
327 + return stateCount_++;
328 + }
329 +
330 + void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
331 + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
332 + *operandStack.template Push<Frag>() = Frag(s, s, s);
333 + }
334 +
335 + void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
336 + if (*atomCountStack.template Top<unsigned>())
337 + *operatorStack.template Push<Operator>() = kConcatenation;
338 + (*atomCountStack.template Top<unsigned>())++;
339 + }
340 +
341 + SizeType Append(SizeType l1, SizeType l2) {
342 + SizeType old = l1;
343 + while (GetState(l1).out != kRegexInvalidState)
344 + l1 = GetState(l1).out;
345 + GetState(l1).out = l2;
346 + return old;
347 + }
348 +
349 + void Patch(SizeType l, SizeType s) {
350 + for (SizeType next; l != kRegexInvalidState; l = next) {
351 + next = GetState(l).out;
352 + GetState(l).out = s;
353 + }
354 + }
355 +
356 + bool Eval(Stack<Allocator>& operandStack, Operator op) {
357 + switch (op) {
358 + case kConcatenation:
359 + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
360 + {
361 + Frag e2 = *operandStack.template Pop<Frag>(1);
362 + Frag e1 = *operandStack.template Pop<Frag>(1);
363 + Patch(e1.out, e2.start);
364 + *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
365 + }
366 + return true;
367 +
368 + case kAlternation:
369 + if (operandStack.GetSize() >= sizeof(Frag) * 2) {
370 + Frag e2 = *operandStack.template Pop<Frag>(1);
371 + Frag e1 = *operandStack.template Pop<Frag>(1);
372 + SizeType s = NewState(e1.start, e2.start, 0);
373 + *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
374 + return true;
375 + }
376 + return false;
377 +
378 + case kZeroOrOne:
379 + if (operandStack.GetSize() >= sizeof(Frag)) {
380 + Frag e = *operandStack.template Pop<Frag>(1);
381 + SizeType s = NewState(kRegexInvalidState, e.start, 0);
382 + *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
383 + return true;
384 + }
385 + return false;
386 +
387 + case kZeroOrMore:
388 + if (operandStack.GetSize() >= sizeof(Frag)) {
389 + Frag e = *operandStack.template Pop<Frag>(1);
390 + SizeType s = NewState(kRegexInvalidState, e.start, 0);
391 + Patch(e.out, s);
392 + *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
393 + return true;
394 + }
395 + return false;
396 +
397 + default:
398 + RAPIDJSON_ASSERT(op == kOneOrMore);
399 + if (operandStack.GetSize() >= sizeof(Frag)) {
400 + Frag e = *operandStack.template Pop<Frag>(1);
401 + SizeType s = NewState(kRegexInvalidState, e.start, 0);
402 + Patch(e.out, s);
403 + *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
404 + return true;
405 + }
406 + return false;
407 + }
408 + }
409 +
410 + bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
411 + RAPIDJSON_ASSERT(n <= m);
412 + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
413 +
414 + if (n == 0) {
415 + if (m == 0) // a{0} not support
416 + return false;
417 + else if (m == kInfinityQuantifier)
418 + Eval(operandStack, kZeroOrMore); // a{0,} -> a*
419 + else {
420 + Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
421 + for (unsigned i = 0; i < m - 1; i++)
422 + CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
423 + for (unsigned i = 0; i < m - 1; i++)
424 + Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
425 + }
426 + return true;
427 + }
428 +
429 + for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
430 + CloneTopOperand(operandStack);
431 +
432 + if (m == kInfinityQuantifier)
433 + Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
434 + else if (m > n) {
435 + CloneTopOperand(operandStack); // a{3,5} -> a a a a
436 + Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
437 + for (unsigned i = n; i < m - 1; i++)
438 + CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
439 + for (unsigned i = n; i < m; i++)
440 + Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
441 + }
442 +
443 + for (unsigned i = 0; i < n - 1; i++)
444 + Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
445 +
446 + return true;
447 + }
448 +
449 + static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
450 +
451 + void CloneTopOperand(Stack<Allocator>& operandStack) {
452 + const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
453 + SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
454 + State* s = states_.template Push<State>(count);
455 + memcpy(s, &GetState(src.minIndex), count * sizeof(State));
456 + for (SizeType j = 0; j < count; j++) {
457 + if (s[j].out != kRegexInvalidState)
458 + s[j].out += count;
459 + if (s[j].out1 != kRegexInvalidState)
460 + s[j].out1 += count;
461 + }
462 + *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
463 + stateCount_ += count;
464 + }
465 +
466 + template <typename InputStream>
467 + bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
468 + unsigned r = 0;
469 + if (ds.Peek() < '0' || ds.Peek() > '9')
470 + return false;
471 + while (ds.Peek() >= '0' && ds.Peek() <= '9') {
472 + if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
473 + return false; // overflow
474 + r = r * 10 + (ds.Take() - '0');
475 + }
476 + *u = r;
477 + return true;
478 + }
479 +
480 + template <typename InputStream>
481 + bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
482 + bool isBegin = true;
483 + bool negate = false;
484 + int step = 0;
485 + SizeType start = kRegexInvalidRange;
486 + SizeType current = kRegexInvalidRange;
487 + unsigned codepoint;
488 + while ((codepoint = ds.Take()) != 0) {
489 + if (isBegin) {
490 + isBegin = false;
491 + if (codepoint == '^') {
492 + negate = true;
493 + continue;
494 + }
495 + }
496 +
497 + switch (codepoint) {
498 + case ']':
499 + if (start == kRegexInvalidRange)
500 + return false; // Error: nothing inside []
501 + if (step == 2) { // Add trailing '-'
502 + SizeType r = NewRange('-');
503 + RAPIDJSON_ASSERT(current != kRegexInvalidRange);
504 + GetRange(current).next = r;
505 + }
506 + if (negate)
507 + GetRange(start).start |= kRangeNegationFlag;
508 + *range = start;
509 + return true;
510 +
511 + case '\\':
512 + if (ds.Peek() == 'b') {
513 + ds.Take();
514 + codepoint = 0x0008; // Escape backspace character
515 + }
516 + else if (!CharacterEscape(ds, &codepoint))
517 + return false;
518 + // fall through to default
519 +
520 + default:
521 + switch (step) {
522 + case 1:
523 + if (codepoint == '-') {
524 + step++;
525 + break;
526 + }
527 + // fall through to step 0 for other characters
528 +
529 + case 0:
530 + {
531 + SizeType r = NewRange(codepoint);
532 + if (current != kRegexInvalidRange)
533 + GetRange(current).next = r;
534 + if (start == kRegexInvalidRange)
535 + start = r;
536 + current = r;
537 + }
538 + step = 1;
539 + break;
540 +
541 + default:
542 + RAPIDJSON_ASSERT(step == 2);
543 + GetRange(current).end = codepoint;
544 + step = 0;
545 + }
546 + }
547 + }
548 + return false;
549 + }
550 +
551 + SizeType NewRange(unsigned codepoint) {
552 + Range* r = ranges_.template Push<Range>();
553 + r->start = r->end = codepoint;
554 + r->next = kRegexInvalidRange;
555 + return rangeCount_++;
556 + }
557 +
558 + template <typename InputStream>
559 + bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
560 + unsigned codepoint;
561 + switch (codepoint = ds.Take()) {
562 + case '^':
563 + case '$':
564 + case '|':
565 + case '(':
566 + case ')':
567 + case '?':
568 + case '*':
569 + case '+':
570 + case '.':
571 + case '[':
572 + case ']':
573 + case '{':
574 + case '}':
575 + case '\\':
576 + *escapedCodepoint = codepoint; return true;
577 + case 'f': *escapedCodepoint = 0x000C; return true;
578 + case 'n': *escapedCodepoint = 0x000A; return true;
579 + case 'r': *escapedCodepoint = 0x000D; return true;
580 + case 't': *escapedCodepoint = 0x0009; return true;
581 + case 'v': *escapedCodepoint = 0x000B; return true;
582 + default:
583 + return false; // Unsupported escape character
584 + }
585 + }
586 +
587 + Stack<Allocator> states_;
588 + Stack<Allocator> ranges_;
589 + SizeType root_;
590 + SizeType stateCount_;
591 + SizeType rangeCount_;
592 +
593 + static const unsigned kInfinityQuantifier = ~0u;
594 +
595 + // For SearchWithAnchoring()
596 + bool anchorBegin_;
597 + bool anchorEnd_;
598 +};
599 +
600 +template <typename RegexType, typename Allocator = CrtAllocator>
601 +class GenericRegexSearch {
602 +public:
603 + typedef typename RegexType::EncodingType Encoding;
604 + typedef typename Encoding::Ch Ch;
605 +
606 + GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
607 + regex_(regex), allocator_(allocator), ownAllocator_(0),
608 + state0_(allocator, 0), state1_(allocator, 0), stateSet_()
609 + {
610 + RAPIDJSON_ASSERT(regex_.IsValid());
611 + if (!allocator_)
612 + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
613 + stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
614 + state0_.template Reserve<SizeType>(regex_.stateCount_);
615 + state1_.template Reserve<SizeType>(regex_.stateCount_);
616 + }
617 +
618 + ~GenericRegexSearch() {
619 + Allocator::Free(stateSet_);
620 + RAPIDJSON_DELETE(ownAllocator_);
621 + }
622 +
623 + template <typename InputStream>
624 + bool Match(InputStream& is) {
625 + return SearchWithAnchoring(is, true, true);
626 + }
627 +
628 + bool Match(const Ch* s) {
629 + GenericStringStream<Encoding> is(s);
630 + return Match(is);
631 + }
632 +
633 + template <typename InputStream>
634 + bool Search(InputStream& is) {
635 + return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
636 + }
637 +
638 + bool Search(const Ch* s) {
639 + GenericStringStream<Encoding> is(s);
640 + return Search(is);
641 + }
642 +
643 +private:
644 + typedef typename RegexType::State State;
645 + typedef typename RegexType::Range Range;
646 +
647 + template <typename InputStream>
648 + bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
649 + DecodedStream<InputStream, Encoding> ds(is);
650 +
651 + state0_.Clear();
652 + Stack<Allocator> *current = &state0_, *next = &state1_;
653 + const size_t stateSetSize = GetStateSetSize();
654 + std::memset(stateSet_, 0, stateSetSize);
655 +
656 + bool matched = AddState(*current, regex_.root_);
657 + unsigned codepoint;
658 + while (!current->Empty() && (codepoint = ds.Take()) != 0) {
659 + std::memset(stateSet_, 0, stateSetSize);
660 + next->Clear();
661 + matched = false;
662 + for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
663 + const State& sr = regex_.GetState(*s);
664 + if (sr.codepoint == codepoint ||
665 + sr.codepoint == RegexType::kAnyCharacterClass ||
666 + (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
667 + {
668 + matched = AddState(*next, sr.out) || matched;
669 + if (!anchorEnd && matched)
670 + return true;
671 + }
672 + if (!anchorBegin)
673 + AddState(*next, regex_.root_);
674 + }
675 + internal::Swap(current, next);
676 + }
677 +
678 + return matched;
679 + }
680 +
681 + size_t GetStateSetSize() const {
682 + return (regex_.stateCount_ + 31) / 32 * 4;
683 + }
684 +
685 + // Return whether the added states is a match state
686 + bool AddState(Stack<Allocator>& l, SizeType index) {
687 + RAPIDJSON_ASSERT(index != kRegexInvalidState);
688 +
689 + const State& s = regex_.GetState(index);
690 + if (s.out1 != kRegexInvalidState) { // Split
691 + bool matched = AddState(l, s.out);
692 + return AddState(l, s.out1) || matched;
693 + }
694 + else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
695 + stateSet_[index >> 5] |= (1u << (index & 31));
696 + *l.template PushUnsafe<SizeType>() = index;
697 + }
698 + return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
699 + }
700 +
701 + bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
702 + bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
703 + while (rangeIndex != kRegexInvalidRange) {
704 + const Range& r = regex_.GetRange(rangeIndex);
705 + if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
706 + return yes;
707 + rangeIndex = r.next;
708 + }
709 + return !yes;
710 + }
711 +
712 + const RegexType& regex_;
713 + Allocator* allocator_;
714 + Allocator* ownAllocator_;
715 + Stack<Allocator> state0_;
716 + Stack<Allocator> state1_;
717 + uint32_t* stateSet_;
718 +};
719 +
720 +typedef GenericRegex<UTF8<> > Regex;
721 +typedef GenericRegexSearch<Regex> RegexSearch;
722 +
723 +} // namespace internal
724 +RAPIDJSON_NAMESPACE_END
725 +
726 +#ifdef __clang__
727 +RAPIDJSON_DIAG_POP
728 +#endif
729 +
730 +#ifdef _MSC_VER
731 +RAPIDJSON_DIAG_POP
732 +#endif
733 +
734 +#endif // RAPIDJSON_INTERNAL_REGEX_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_INTERNAL_STACK_H_
16 +#define RAPIDJSON_INTERNAL_STACK_H_
17 +
18 +#include "../allocators.h"
19 +#include "swap.h"
20 +
21 +#if defined(__clang__)
22 +RAPIDJSON_DIAG_PUSH
23 +RAPIDJSON_DIAG_OFF(c++98-compat)
24 +#endif
25 +
26 +RAPIDJSON_NAMESPACE_BEGIN
27 +namespace internal {
28 +
29 +///////////////////////////////////////////////////////////////////////////////
30 +// Stack
31 +
32 +//! A type-unsafe stack for storing different types of data.
33 +/*! \tparam Allocator Allocator for allocating stack memory.
34 +*/
35 +template <typename Allocator>
36 +class Stack {
37 +public:
38 + // Optimization note: Do not allocate memory for stack_ in constructor.
39 + // Do it lazily when first Push() -> Expand() -> Resize().
40 + Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
41 + }
42 +
43 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
44 + Stack(Stack&& rhs)
45 + : allocator_(rhs.allocator_),
46 + ownAllocator_(rhs.ownAllocator_),
47 + stack_(rhs.stack_),
48 + stackTop_(rhs.stackTop_),
49 + stackEnd_(rhs.stackEnd_),
50 + initialCapacity_(rhs.initialCapacity_)
51 + {
52 + rhs.allocator_ = 0;
53 + rhs.ownAllocator_ = 0;
54 + rhs.stack_ = 0;
55 + rhs.stackTop_ = 0;
56 + rhs.stackEnd_ = 0;
57 + rhs.initialCapacity_ = 0;
58 + }
59 +#endif
60 +
61 + ~Stack() {
62 + Destroy();
63 + }
64 +
65 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
66 + Stack& operator=(Stack&& rhs) {
67 + if (&rhs != this)
68 + {
69 + Destroy();
70 +
71 + allocator_ = rhs.allocator_;
72 + ownAllocator_ = rhs.ownAllocator_;
73 + stack_ = rhs.stack_;
74 + stackTop_ = rhs.stackTop_;
75 + stackEnd_ = rhs.stackEnd_;
76 + initialCapacity_ = rhs.initialCapacity_;
77 +
78 + rhs.allocator_ = 0;
79 + rhs.ownAllocator_ = 0;
80 + rhs.stack_ = 0;
81 + rhs.stackTop_ = 0;
82 + rhs.stackEnd_ = 0;
83 + rhs.initialCapacity_ = 0;
84 + }
85 + return *this;
86 + }
87 +#endif
88 +
89 + void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
90 + internal::Swap(allocator_, rhs.allocator_);
91 + internal::Swap(ownAllocator_, rhs.ownAllocator_);
92 + internal::Swap(stack_, rhs.stack_);
93 + internal::Swap(stackTop_, rhs.stackTop_);
94 + internal::Swap(stackEnd_, rhs.stackEnd_);
95 + internal::Swap(initialCapacity_, rhs.initialCapacity_);
96 + }
97 +
98 + void Clear() { stackTop_ = stack_; }
99 +
100 + void ShrinkToFit() {
101 + if (Empty()) {
102 + // If the stack is empty, completely deallocate the memory.
103 + Allocator::Free(stack_);
104 + stack_ = 0;
105 + stackTop_ = 0;
106 + stackEnd_ = 0;
107 + }
108 + else
109 + Resize(GetSize());
110 + }
111 +
112 + // Optimization note: try to minimize the size of this function for force inline.
113 + // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
114 + template<typename T>
115 + RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
116 + // Expand the stack if needed
117 + if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
118 + Expand<T>(count);
119 + }
120 +
121 + template<typename T>
122 + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
123 + Reserve<T>(count);
124 + return PushUnsafe<T>(count);
125 + }
126 +
127 + template<typename T>
128 + RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
129 + RAPIDJSON_ASSERT(stackTop_);
130 + RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
131 + T* ret = reinterpret_cast<T*>(stackTop_);
132 + stackTop_ += sizeof(T) * count;
133 + return ret;
134 + }
135 +
136 + template<typename T>
137 + T* Pop(size_t count) {
138 + RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
139 + stackTop_ -= count * sizeof(T);
140 + return reinterpret_cast<T*>(stackTop_);
141 + }
142 +
143 + template<typename T>
144 + T* Top() {
145 + RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
146 + return reinterpret_cast<T*>(stackTop_ - sizeof(T));
147 + }
148 +
149 + template<typename T>
150 + const T* Top() const {
151 + RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
152 + return reinterpret_cast<T*>(stackTop_ - sizeof(T));
153 + }
154 +
155 + template<typename T>
156 + T* End() { return reinterpret_cast<T*>(stackTop_); }
157 +
158 + template<typename T>
159 + const T* End() const { return reinterpret_cast<T*>(stackTop_); }
160 +
161 + template<typename T>
162 + T* Bottom() { return reinterpret_cast<T*>(stack_); }
163 +
164 + template<typename T>
165 + const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
166 +
167 + bool HasAllocator() const {
168 + return allocator_ != 0;
169 + }
170 +
171 + Allocator& GetAllocator() {
172 + RAPIDJSON_ASSERT(allocator_);
173 + return *allocator_;
174 + }
175 +
176 + bool Empty() const { return stackTop_ == stack_; }
177 + size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
178 + size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
179 +
180 +private:
181 + template<typename T>
182 + void Expand(size_t count) {
183 + // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
184 + size_t newCapacity;
185 + if (stack_ == 0) {
186 + if (!allocator_)
187 + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
188 + newCapacity = initialCapacity_;
189 + } else {
190 + newCapacity = GetCapacity();
191 + newCapacity += (newCapacity + 1) / 2;
192 + }
193 + size_t newSize = GetSize() + sizeof(T) * count;
194 + if (newCapacity < newSize)
195 + newCapacity = newSize;
196 +
197 + Resize(newCapacity);
198 + }
199 +
200 + void Resize(size_t newCapacity) {
201 + const size_t size = GetSize(); // Backup the current size
202 + stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
203 + stackTop_ = stack_ + size;
204 + stackEnd_ = stack_ + newCapacity;
205 + }
206 +
207 + void Destroy() {
208 + Allocator::Free(stack_);
209 + RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
210 + }
211 +
212 + // Prohibit copy constructor & assignment operator.
213 + Stack(const Stack&);
214 + Stack& operator=(const Stack&);
215 +
216 + Allocator* allocator_;
217 + Allocator* ownAllocator_;
218 + char *stack_;
219 + char *stackTop_;
220 + char *stackEnd_;
221 + size_t initialCapacity_;
222 +};
223 +
224 +} // namespace internal
225 +RAPIDJSON_NAMESPACE_END
226 +
227 +#if defined(__clang__)
228 +RAPIDJSON_DIAG_POP
229 +#endif
230 +
231 +#endif // RAPIDJSON_STACK_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
16 +#define RAPIDJSON_INTERNAL_STRFUNC_H_
17 +
18 +#include "../stream.h"
19 +#include <cwchar>
20 +
21 +RAPIDJSON_NAMESPACE_BEGIN
22 +namespace internal {
23 +
24 +//! Custom strlen() which works on different character types.
25 +/*! \tparam Ch Character type (e.g. char, wchar_t, short)
26 + \param s Null-terminated input string.
27 + \return Number of characters in the string.
28 + \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
29 +*/
30 +template <typename Ch>
31 +inline SizeType StrLen(const Ch* s) {
32 + RAPIDJSON_ASSERT(s != 0);
33 + const Ch* p = s;
34 + while (*p) ++p;
35 + return SizeType(p - s);
36 +}
37 +
38 +template <>
39 +inline SizeType StrLen(const char* s) {
40 + return SizeType(std::strlen(s));
41 +}
42 +
43 +template <>
44 +inline SizeType StrLen(const wchar_t* s) {
45 + return SizeType(std::wcslen(s));
46 +}
47 +
48 +//! Returns number of code points in a encoded string.
49 +template<typename Encoding>
50 +bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
51 + RAPIDJSON_ASSERT(s != 0);
52 + RAPIDJSON_ASSERT(outCount != 0);
53 + GenericStringStream<Encoding> is(s);
54 + const typename Encoding::Ch* end = s + length;
55 + SizeType count = 0;
56 + while (is.src_ < end) {
57 + unsigned codepoint;
58 + if (!Encoding::Decode(is, &codepoint))
59 + return false;
60 + count++;
61 + }
62 + *outCount = count;
63 + return true;
64 +}
65 +
66 +} // namespace internal
67 +RAPIDJSON_NAMESPACE_END
68 +
69 +#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_STRTOD_
16 +#define RAPIDJSON_STRTOD_
17 +
18 +#include "ieee754.h"
19 +#include "biginteger.h"
20 +#include "diyfp.h"
21 +#include "pow10.h"
22 +
23 +RAPIDJSON_NAMESPACE_BEGIN
24 +namespace internal {
25 +
26 +inline double FastPath(double significand, int exp) {
27 + if (exp < -308)
28 + return 0.0;
29 + else if (exp >= 0)
30 + return significand * internal::Pow10(exp);
31 + else
32 + return significand / internal::Pow10(-exp);
33 +}
34 +
35 +inline double StrtodNormalPrecision(double d, int p) {
36 + if (p < -308) {
37 + // Prevent expSum < -308, making Pow10(p) = 0
38 + d = FastPath(d, -308);
39 + d = FastPath(d, p + 308);
40 + }
41 + else
42 + d = FastPath(d, p);
43 + return d;
44 +}
45 +
46 +template <typename T>
47 +inline T Min3(T a, T b, T c) {
48 + T m = a;
49 + if (m > b) m = b;
50 + if (m > c) m = c;
51 + return m;
52 +}
53 +
54 +inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
55 + const Double db(b);
56 + const uint64_t bInt = db.IntegerSignificand();
57 + const int bExp = db.IntegerExponent();
58 + const int hExp = bExp - 1;
59 +
60 + int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
61 +
62 + // Adjust for decimal exponent
63 + if (dExp >= 0) {
64 + dS_Exp2 += dExp;
65 + dS_Exp5 += dExp;
66 + }
67 + else {
68 + bS_Exp2 -= dExp;
69 + bS_Exp5 -= dExp;
70 + hS_Exp2 -= dExp;
71 + hS_Exp5 -= dExp;
72 + }
73 +
74 + // Adjust for binary exponent
75 + if (bExp >= 0)
76 + bS_Exp2 += bExp;
77 + else {
78 + dS_Exp2 -= bExp;
79 + hS_Exp2 -= bExp;
80 + }
81 +
82 + // Adjust for half ulp exponent
83 + if (hExp >= 0)
84 + hS_Exp2 += hExp;
85 + else {
86 + dS_Exp2 -= hExp;
87 + bS_Exp2 -= hExp;
88 + }
89 +
90 + // Remove common power of two factor from all three scaled values
91 + int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
92 + dS_Exp2 -= common_Exp2;
93 + bS_Exp2 -= common_Exp2;
94 + hS_Exp2 -= common_Exp2;
95 +
96 + BigInteger dS = d;
97 + dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
98 +
99 + BigInteger bS(bInt);
100 + bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
101 +
102 + BigInteger hS(1);
103 + hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
104 +
105 + BigInteger delta(0);
106 + dS.Difference(bS, &delta);
107 +
108 + return delta.Compare(hS);
109 +}
110 +
111 +inline bool StrtodFast(double d, int p, double* result) {
112 + // Use fast path for string-to-double conversion if possible
113 + // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
114 + if (p > 22 && p < 22 + 16) {
115 + // Fast Path Cases In Disguise
116 + d *= internal::Pow10(p - 22);
117 + p = 22;
118 + }
119 +
120 + if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
121 + *result = FastPath(d, p);
122 + return true;
123 + }
124 + else
125 + return false;
126 +}
127 +
128 +// Compute an approximation and see if it is within 1/2 ULP
129 +inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
130 + uint64_t significand = 0;
131 + size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
132 + for (; i < length; i++) {
133 + if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
134 + (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
135 + break;
136 + significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
137 + }
138 +
139 + if (i < length && decimals[i] >= '5') // Rounding
140 + significand++;
141 +
142 + size_t remaining = length - i;
143 + const int kUlpShift = 3;
144 + const int kUlp = 1 << kUlpShift;
145 + int64_t error = (remaining == 0) ? 0 : kUlp / 2;
146 +
147 + DiyFp v(significand, 0);
148 + v = v.Normalize();
149 + error <<= -v.e;
150 +
151 + const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
152 +
153 + int actualExp;
154 + DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
155 + if (actualExp != dExp) {
156 + static const DiyFp kPow10[] = {
157 + DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
158 + DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
159 + DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
160 + DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
161 + DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
162 + DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
163 + DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
164 + };
165 + int adjustment = dExp - actualExp - 1;
166 + RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
167 + v = v * kPow10[adjustment];
168 + if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
169 + error += kUlp / 2;
170 + }
171 +
172 + v = v * cachedPower;
173 +
174 + error += kUlp + (error == 0 ? 0 : 1);
175 +
176 + const int oldExp = v.e;
177 + v = v.Normalize();
178 + error <<= oldExp - v.e;
179 +
180 + const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
181 + int precisionSize = 64 - effectiveSignificandSize;
182 + if (precisionSize + kUlpShift >= 64) {
183 + int scaleExp = (precisionSize + kUlpShift) - 63;
184 + v.f >>= scaleExp;
185 + v.e += scaleExp;
186 + error = (error >> scaleExp) + 1 + kUlp;
187 + precisionSize -= scaleExp;
188 + }
189 +
190 + DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
191 + const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
192 + const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
193 + if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
194 + rounded.f++;
195 + if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
196 + rounded.f >>= 1;
197 + rounded.e++;
198 + }
199 + }
200 +
201 + *result = rounded.ToDouble();
202 +
203 + return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
204 +}
205 +
206 +inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
207 + const BigInteger dInt(decimals, length);
208 + const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
209 + Double a(approx);
210 + int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
211 + if (cmp < 0)
212 + return a.Value(); // within half ULP
213 + else if (cmp == 0) {
214 + // Round towards even
215 + if (a.Significand() & 1)
216 + return a.NextPositiveDouble();
217 + else
218 + return a.Value();
219 + }
220 + else // adjustment
221 + return a.NextPositiveDouble();
222 +}
223 +
224 +inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
225 + RAPIDJSON_ASSERT(d >= 0.0);
226 + RAPIDJSON_ASSERT(length >= 1);
227 +
228 + double result;
229 + if (StrtodFast(d, p, &result))
230 + return result;
231 +
232 + // Trim leading zeros
233 + while (*decimals == '0' && length > 1) {
234 + length--;
235 + decimals++;
236 + decimalPosition--;
237 + }
238 +
239 + // Trim trailing zeros
240 + while (decimals[length - 1] == '0' && length > 1) {
241 + length--;
242 + decimalPosition--;
243 + exp++;
244 + }
245 +
246 + // Trim right-most digits
247 + const int kMaxDecimalDigit = 780;
248 + if (static_cast<int>(length) > kMaxDecimalDigit) {
249 + int delta = (static_cast<int>(length) - kMaxDecimalDigit);
250 + exp += delta;
251 + decimalPosition -= static_cast<unsigned>(delta);
252 + length = kMaxDecimalDigit;
253 + }
254 +
255 + // If too small, underflow to zero
256 + if (int(length) + exp < -324)
257 + return 0.0;
258 +
259 + if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
260 + return result;
261 +
262 + // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
263 + return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
264 +}
265 +
266 +} // namespace internal
267 +RAPIDJSON_NAMESPACE_END
268 +
269 +#endif // RAPIDJSON_STRTOD_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_INTERNAL_SWAP_H_
16 +#define RAPIDJSON_INTERNAL_SWAP_H_
17 +
18 +#include "../rapidjson.h"
19 +
20 +#if defined(__clang__)
21 +RAPIDJSON_DIAG_PUSH
22 +RAPIDJSON_DIAG_OFF(c++98-compat)
23 +#endif
24 +
25 +RAPIDJSON_NAMESPACE_BEGIN
26 +namespace internal {
27 +
28 +//! Custom swap() to avoid dependency on C++ <algorithm> header
29 +/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
30 + \note This has the same semantics as std::swap().
31 +*/
32 +template <typename T>
33 +inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
34 + T tmp = a;
35 + a = b;
36 + b = tmp;
37 +}
38 +
39 +} // namespace internal
40 +RAPIDJSON_NAMESPACE_END
41 +
42 +#if defined(__clang__)
43 +RAPIDJSON_DIAG_POP
44 +#endif
45 +
46 +#endif // RAPIDJSON_INTERNAL_SWAP_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
16 +#define RAPIDJSON_ISTREAMWRAPPER_H_
17 +
18 +#include "stream.h"
19 +#include <iosfwd>
20 +
21 +#ifdef __clang__
22 +RAPIDJSON_DIAG_PUSH
23 +RAPIDJSON_DIAG_OFF(padded)
24 +#endif
25 +
26 +#ifdef _MSC_VER
27 +RAPIDJSON_DIAG_PUSH
28 +RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
29 +#endif
30 +
31 +RAPIDJSON_NAMESPACE_BEGIN
32 +
33 +//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
34 +/*!
35 + The classes can be wrapped including but not limited to:
36 +
37 + - \c std::istringstream
38 + - \c std::stringstream
39 + - \c std::wistringstream
40 + - \c std::wstringstream
41 + - \c std::ifstream
42 + - \c std::fstream
43 + - \c std::wifstream
44 + - \c std::wfstream
45 +
46 + \tparam StreamType Class derived from \c std::basic_istream.
47 +*/
48 +
49 +template <typename StreamType>
50 +class BasicIStreamWrapper {
51 +public:
52 + typedef typename StreamType::char_type Ch;
53 + BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
54 +
55 + Ch Peek() const {
56 + typename StreamType::int_type c = stream_.peek();
57 + return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : static_cast<Ch>('\0');
58 + }
59 +
60 + Ch Take() {
61 + typename StreamType::int_type c = stream_.get();
62 + if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
63 + count_++;
64 + return static_cast<Ch>(c);
65 + }
66 + else
67 + return '\0';
68 + }
69 +
70 + // tellg() may return -1 when failed. So we count by ourself.
71 + size_t Tell() const { return count_; }
72 +
73 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
74 + void Put(Ch) { RAPIDJSON_ASSERT(false); }
75 + void Flush() { RAPIDJSON_ASSERT(false); }
76 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
77 +
78 + // For encoding detection only.
79 + const Ch* Peek4() const {
80 + RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
81 + int i;
82 + bool hasError = false;
83 + for (i = 0; i < 4; ++i) {
84 + typename StreamType::int_type c = stream_.get();
85 + if (c == StreamType::traits_type::eof()) {
86 + hasError = true;
87 + stream_.clear();
88 + break;
89 + }
90 + peekBuffer_[i] = static_cast<Ch>(c);
91 + }
92 + for (--i; i >= 0; --i)
93 + stream_.putback(peekBuffer_[i]);
94 + return !hasError ? peekBuffer_ : 0;
95 + }
96 +
97 +private:
98 + BasicIStreamWrapper(const BasicIStreamWrapper&);
99 + BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
100 +
101 + StreamType& stream_;
102 + size_t count_; //!< Number of characters read. Note:
103 + mutable Ch peekBuffer_[4];
104 +};
105 +
106 +typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
107 +typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
108 +
109 +#if defined(__clang__) || defined(_MSC_VER)
110 +RAPIDJSON_DIAG_POP
111 +#endif
112 +
113 +RAPIDJSON_NAMESPACE_END
114 +
115 +#endif // RAPIDJSON_ISTREAMWRAPPER_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_MEMORYBUFFER_H_
16 +#define RAPIDJSON_MEMORYBUFFER_H_
17 +
18 +#include "stream.h"
19 +#include "internal/stack.h"
20 +
21 +RAPIDJSON_NAMESPACE_BEGIN
22 +
23 +//! Represents an in-memory output byte stream.
24 +/*!
25 + This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
26 +
27 + It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
28 +
29 + Differences between MemoryBuffer and StringBuffer:
30 + 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
31 + 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
32 +
33 + \tparam Allocator type for allocating memory buffer.
34 + \note implements Stream concept
35 +*/
36 +template <typename Allocator = CrtAllocator>
37 +struct GenericMemoryBuffer {
38 + typedef char Ch; // byte
39 +
40 + GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
41 +
42 + void Put(Ch c) { *stack_.template Push<Ch>() = c; }
43 + void Flush() {}
44 +
45 + void Clear() { stack_.Clear(); }
46 + void ShrinkToFit() { stack_.ShrinkToFit(); }
47 + Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
48 + void Pop(size_t count) { stack_.template Pop<Ch>(count); }
49 +
50 + const Ch* GetBuffer() const {
51 + return stack_.template Bottom<Ch>();
52 + }
53 +
54 + size_t GetSize() const { return stack_.GetSize(); }
55 +
56 + static const size_t kDefaultCapacity = 256;
57 + mutable internal::Stack<Allocator> stack_;
58 +};
59 +
60 +typedef GenericMemoryBuffer<> MemoryBuffer;
61 +
62 +//! Implement specialized version of PutN() with memset() for better performance.
63 +template<>
64 +inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
65 + std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
66 +}
67 +
68 +RAPIDJSON_NAMESPACE_END
69 +
70 +#endif // RAPIDJSON_MEMORYBUFFER_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_MEMORYSTREAM_H_
16 +#define RAPIDJSON_MEMORYSTREAM_H_
17 +
18 +#include "stream.h"
19 +
20 +#ifdef __clang__
21 +RAPIDJSON_DIAG_PUSH
22 +RAPIDJSON_DIAG_OFF(unreachable-code)
23 +RAPIDJSON_DIAG_OFF(missing-noreturn)
24 +#endif
25 +
26 +RAPIDJSON_NAMESPACE_BEGIN
27 +
28 +//! Represents an in-memory input byte stream.
29 +/*!
30 + This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
31 +
32 + It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
33 +
34 + Differences between MemoryStream and StringStream:
35 + 1. StringStream has encoding but MemoryStream is a byte stream.
36 + 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
37 + 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
38 + \note implements Stream concept
39 +*/
40 +struct MemoryStream {
41 + typedef char Ch; // byte
42 +
43 + MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
44 +
45 + Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
46 + Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
47 + size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
48 +
49 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
50 + void Put(Ch) { RAPIDJSON_ASSERT(false); }
51 + void Flush() { RAPIDJSON_ASSERT(false); }
52 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
53 +
54 + // For encoding detection only.
55 + const Ch* Peek4() const {
56 + return Tell() + 4 <= size_ ? src_ : 0;
57 + }
58 +
59 + const Ch* src_; //!< Current read position.
60 + const Ch* begin_; //!< Original head of the string.
61 + const Ch* end_; //!< End of stream.
62 + size_t size_; //!< Size of the stream.
63 +};
64 +
65 +RAPIDJSON_NAMESPACE_END
66 +
67 +#ifdef __clang__
68 +RAPIDJSON_DIAG_POP
69 +#endif
70 +
71 +#endif // RAPIDJSON_MEMORYBUFFER_H_
1 +// ISO C9x compliant inttypes.h for Microsoft Visual Studio
2 +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
3 +//
4 +// Copyright (c) 2006-2013 Alexander Chemeris
5 +//
6 +// Redistribution and use in source and binary forms, with or without
7 +// modification, are permitted provided that the following conditions are met:
8 +//
9 +// 1. Redistributions of source code must retain the above copyright notice,
10 +// this list of conditions and the following disclaimer.
11 +//
12 +// 2. Redistributions in binary form must reproduce the above copyright
13 +// notice, this list of conditions and the following disclaimer in the
14 +// documentation and/or other materials provided with the distribution.
15 +//
16 +// 3. Neither the name of the product nor the names of its contributors may
17 +// be used to endorse or promote products derived from this software
18 +// without specific prior written permission.
19 +//
20 +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
21 +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
23 +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 +//
31 +///////////////////////////////////////////////////////////////////////////////
32 +
33 +// The above software in this distribution may have been modified by
34 +// THL A29 Limited ("Tencent Modifications").
35 +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
36 +
37 +#ifndef _MSC_VER // [
38 +#error "Use this header only with Microsoft Visual C++ compilers!"
39 +#endif // _MSC_VER ]
40 +
41 +#ifndef _MSC_INTTYPES_H_ // [
42 +#define _MSC_INTTYPES_H_
43 +
44 +#if _MSC_VER > 1000
45 +#pragma once
46 +#endif
47 +
48 +#include "stdint.h"
49 +
50 +// miloyip: VC supports inttypes.h since VC2013
51 +#if _MSC_VER >= 1800
52 +#include <inttypes.h>
53 +#else
54 +
55 +// 7.8 Format conversion of integer types
56 +
57 +typedef struct {
58 + intmax_t quot;
59 + intmax_t rem;
60 +} imaxdiv_t;
61 +
62 +// 7.8.1 Macros for format specifiers
63 +
64 +#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
65 +
66 +// The fprintf macros for signed integers are:
67 +#define PRId8 "d"
68 +#define PRIi8 "i"
69 +#define PRIdLEAST8 "d"
70 +#define PRIiLEAST8 "i"
71 +#define PRIdFAST8 "d"
72 +#define PRIiFAST8 "i"
73 +
74 +#define PRId16 "hd"
75 +#define PRIi16 "hi"
76 +#define PRIdLEAST16 "hd"
77 +#define PRIiLEAST16 "hi"
78 +#define PRIdFAST16 "hd"
79 +#define PRIiFAST16 "hi"
80 +
81 +#define PRId32 "I32d"
82 +#define PRIi32 "I32i"
83 +#define PRIdLEAST32 "I32d"
84 +#define PRIiLEAST32 "I32i"
85 +#define PRIdFAST32 "I32d"
86 +#define PRIiFAST32 "I32i"
87 +
88 +#define PRId64 "I64d"
89 +#define PRIi64 "I64i"
90 +#define PRIdLEAST64 "I64d"
91 +#define PRIiLEAST64 "I64i"
92 +#define PRIdFAST64 "I64d"
93 +#define PRIiFAST64 "I64i"
94 +
95 +#define PRIdMAX "I64d"
96 +#define PRIiMAX "I64i"
97 +
98 +#define PRIdPTR "Id"
99 +#define PRIiPTR "Ii"
100 +
101 +// The fprintf macros for unsigned integers are:
102 +#define PRIo8 "o"
103 +#define PRIu8 "u"
104 +#define PRIx8 "x"
105 +#define PRIX8 "X"
106 +#define PRIoLEAST8 "o"
107 +#define PRIuLEAST8 "u"
108 +#define PRIxLEAST8 "x"
109 +#define PRIXLEAST8 "X"
110 +#define PRIoFAST8 "o"
111 +#define PRIuFAST8 "u"
112 +#define PRIxFAST8 "x"
113 +#define PRIXFAST8 "X"
114 +
115 +#define PRIo16 "ho"
116 +#define PRIu16 "hu"
117 +#define PRIx16 "hx"
118 +#define PRIX16 "hX"
119 +#define PRIoLEAST16 "ho"
120 +#define PRIuLEAST16 "hu"
121 +#define PRIxLEAST16 "hx"
122 +#define PRIXLEAST16 "hX"
123 +#define PRIoFAST16 "ho"
124 +#define PRIuFAST16 "hu"
125 +#define PRIxFAST16 "hx"
126 +#define PRIXFAST16 "hX"
127 +
128 +#define PRIo32 "I32o"
129 +#define PRIu32 "I32u"
130 +#define PRIx32 "I32x"
131 +#define PRIX32 "I32X"
132 +#define PRIoLEAST32 "I32o"
133 +#define PRIuLEAST32 "I32u"
134 +#define PRIxLEAST32 "I32x"
135 +#define PRIXLEAST32 "I32X"
136 +#define PRIoFAST32 "I32o"
137 +#define PRIuFAST32 "I32u"
138 +#define PRIxFAST32 "I32x"
139 +#define PRIXFAST32 "I32X"
140 +
141 +#define PRIo64 "I64o"
142 +#define PRIu64 "I64u"
143 +#define PRIx64 "I64x"
144 +#define PRIX64 "I64X"
145 +#define PRIoLEAST64 "I64o"
146 +#define PRIuLEAST64 "I64u"
147 +#define PRIxLEAST64 "I64x"
148 +#define PRIXLEAST64 "I64X"
149 +#define PRIoFAST64 "I64o"
150 +#define PRIuFAST64 "I64u"
151 +#define PRIxFAST64 "I64x"
152 +#define PRIXFAST64 "I64X"
153 +
154 +#define PRIoMAX "I64o"
155 +#define PRIuMAX "I64u"
156 +#define PRIxMAX "I64x"
157 +#define PRIXMAX "I64X"
158 +
159 +#define PRIoPTR "Io"
160 +#define PRIuPTR "Iu"
161 +#define PRIxPTR "Ix"
162 +#define PRIXPTR "IX"
163 +
164 +// The fscanf macros for signed integers are:
165 +#define SCNd8 "d"
166 +#define SCNi8 "i"
167 +#define SCNdLEAST8 "d"
168 +#define SCNiLEAST8 "i"
169 +#define SCNdFAST8 "d"
170 +#define SCNiFAST8 "i"
171 +
172 +#define SCNd16 "hd"
173 +#define SCNi16 "hi"
174 +#define SCNdLEAST16 "hd"
175 +#define SCNiLEAST16 "hi"
176 +#define SCNdFAST16 "hd"
177 +#define SCNiFAST16 "hi"
178 +
179 +#define SCNd32 "ld"
180 +#define SCNi32 "li"
181 +#define SCNdLEAST32 "ld"
182 +#define SCNiLEAST32 "li"
183 +#define SCNdFAST32 "ld"
184 +#define SCNiFAST32 "li"
185 +
186 +#define SCNd64 "I64d"
187 +#define SCNi64 "I64i"
188 +#define SCNdLEAST64 "I64d"
189 +#define SCNiLEAST64 "I64i"
190 +#define SCNdFAST64 "I64d"
191 +#define SCNiFAST64 "I64i"
192 +
193 +#define SCNdMAX "I64d"
194 +#define SCNiMAX "I64i"
195 +
196 +#ifdef _WIN64 // [
197 +# define SCNdPTR "I64d"
198 +# define SCNiPTR "I64i"
199 +#else // _WIN64 ][
200 +# define SCNdPTR "ld"
201 +# define SCNiPTR "li"
202 +#endif // _WIN64 ]
203 +
204 +// The fscanf macros for unsigned integers are:
205 +#define SCNo8 "o"
206 +#define SCNu8 "u"
207 +#define SCNx8 "x"
208 +#define SCNX8 "X"
209 +#define SCNoLEAST8 "o"
210 +#define SCNuLEAST8 "u"
211 +#define SCNxLEAST8 "x"
212 +#define SCNXLEAST8 "X"
213 +#define SCNoFAST8 "o"
214 +#define SCNuFAST8 "u"
215 +#define SCNxFAST8 "x"
216 +#define SCNXFAST8 "X"
217 +
218 +#define SCNo16 "ho"
219 +#define SCNu16 "hu"
220 +#define SCNx16 "hx"
221 +#define SCNX16 "hX"
222 +#define SCNoLEAST16 "ho"
223 +#define SCNuLEAST16 "hu"
224 +#define SCNxLEAST16 "hx"
225 +#define SCNXLEAST16 "hX"
226 +#define SCNoFAST16 "ho"
227 +#define SCNuFAST16 "hu"
228 +#define SCNxFAST16 "hx"
229 +#define SCNXFAST16 "hX"
230 +
231 +#define SCNo32 "lo"
232 +#define SCNu32 "lu"
233 +#define SCNx32 "lx"
234 +#define SCNX32 "lX"
235 +#define SCNoLEAST32 "lo"
236 +#define SCNuLEAST32 "lu"
237 +#define SCNxLEAST32 "lx"
238 +#define SCNXLEAST32 "lX"
239 +#define SCNoFAST32 "lo"
240 +#define SCNuFAST32 "lu"
241 +#define SCNxFAST32 "lx"
242 +#define SCNXFAST32 "lX"
243 +
244 +#define SCNo64 "I64o"
245 +#define SCNu64 "I64u"
246 +#define SCNx64 "I64x"
247 +#define SCNX64 "I64X"
248 +#define SCNoLEAST64 "I64o"
249 +#define SCNuLEAST64 "I64u"
250 +#define SCNxLEAST64 "I64x"
251 +#define SCNXLEAST64 "I64X"
252 +#define SCNoFAST64 "I64o"
253 +#define SCNuFAST64 "I64u"
254 +#define SCNxFAST64 "I64x"
255 +#define SCNXFAST64 "I64X"
256 +
257 +#define SCNoMAX "I64o"
258 +#define SCNuMAX "I64u"
259 +#define SCNxMAX "I64x"
260 +#define SCNXMAX "I64X"
261 +
262 +#ifdef _WIN64 // [
263 +# define SCNoPTR "I64o"
264 +# define SCNuPTR "I64u"
265 +# define SCNxPTR "I64x"
266 +# define SCNXPTR "I64X"
267 +#else // _WIN64 ][
268 +# define SCNoPTR "lo"
269 +# define SCNuPTR "lu"
270 +# define SCNxPTR "lx"
271 +# define SCNXPTR "lX"
272 +#endif // _WIN64 ]
273 +
274 +#endif // __STDC_FORMAT_MACROS ]
275 +
276 +// 7.8.2 Functions for greatest-width integer types
277 +
278 +// 7.8.2.1 The imaxabs function
279 +#define imaxabs _abs64
280 +
281 +// 7.8.2.2 The imaxdiv function
282 +
283 +// This is modified version of div() function from Microsoft's div.c found
284 +// in %MSVC.NET%\crt\src\div.c
285 +#ifdef STATIC_IMAXDIV // [
286 +static
287 +#else // STATIC_IMAXDIV ][
288 +_inline
289 +#endif // STATIC_IMAXDIV ]
290 +imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
291 +{
292 + imaxdiv_t result;
293 +
294 + result.quot = numer / denom;
295 + result.rem = numer % denom;
296 +
297 + if (numer < 0 && result.rem > 0) {
298 + // did division wrong; must fix up
299 + ++result.quot;
300 + result.rem -= denom;
301 + }
302 +
303 + return result;
304 +}
305 +
306 +// 7.8.2.3 The strtoimax and strtoumax functions
307 +#define strtoimax _strtoi64
308 +#define strtoumax _strtoui64
309 +
310 +// 7.8.2.4 The wcstoimax and wcstoumax functions
311 +#define wcstoimax _wcstoi64
312 +#define wcstoumax _wcstoui64
313 +
314 +#endif // _MSC_VER >= 1800
315 +
316 +#endif // _MSC_INTTYPES_H_ ]
1 +// ISO C9x compliant stdint.h for Microsoft Visual Studio
2 +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
3 +//
4 +// Copyright (c) 2006-2013 Alexander Chemeris
5 +//
6 +// Redistribution and use in source and binary forms, with or without
7 +// modification, are permitted provided that the following conditions are met:
8 +//
9 +// 1. Redistributions of source code must retain the above copyright notice,
10 +// this list of conditions and the following disclaimer.
11 +//
12 +// 2. Redistributions in binary form must reproduce the above copyright
13 +// notice, this list of conditions and the following disclaimer in the
14 +// documentation and/or other materials provided with the distribution.
15 +//
16 +// 3. Neither the name of the product nor the names of its contributors may
17 +// be used to endorse or promote products derived from this software
18 +// without specific prior written permission.
19 +//
20 +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
21 +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
23 +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 +//
31 +///////////////////////////////////////////////////////////////////////////////
32 +
33 +// The above software in this distribution may have been modified by
34 +// THL A29 Limited ("Tencent Modifications").
35 +// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
36 +
37 +#ifndef _MSC_VER // [
38 +#error "Use this header only with Microsoft Visual C++ compilers!"
39 +#endif // _MSC_VER ]
40 +
41 +#ifndef _MSC_STDINT_H_ // [
42 +#define _MSC_STDINT_H_
43 +
44 +#if _MSC_VER > 1000
45 +#pragma once
46 +#endif
47 +
48 +// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
49 +#if _MSC_VER >= 1600 // [
50 +#include <stdint.h>
51 +
52 +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
53 +
54 +#undef INT8_C
55 +#undef INT16_C
56 +#undef INT32_C
57 +#undef INT64_C
58 +#undef UINT8_C
59 +#undef UINT16_C
60 +#undef UINT32_C
61 +#undef UINT64_C
62 +
63 +// 7.18.4.1 Macros for minimum-width integer constants
64 +
65 +#define INT8_C(val) val##i8
66 +#define INT16_C(val) val##i16
67 +#define INT32_C(val) val##i32
68 +#define INT64_C(val) val##i64
69 +
70 +#define UINT8_C(val) val##ui8
71 +#define UINT16_C(val) val##ui16
72 +#define UINT32_C(val) val##ui32
73 +#define UINT64_C(val) val##ui64
74 +
75 +// 7.18.4.2 Macros for greatest-width integer constants
76 +// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
77 +// Check out Issue 9 for the details.
78 +#ifndef INTMAX_C // [
79 +# define INTMAX_C INT64_C
80 +#endif // INTMAX_C ]
81 +#ifndef UINTMAX_C // [
82 +# define UINTMAX_C UINT64_C
83 +#endif // UINTMAX_C ]
84 +
85 +#endif // __STDC_CONSTANT_MACROS ]
86 +
87 +#else // ] _MSC_VER >= 1700 [
88 +
89 +#include <limits.h>
90 +
91 +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
92 +// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
93 +// or compiler would give many errors like this:
94 +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
95 +#if defined(__cplusplus) && !defined(_M_ARM)
96 +extern "C" {
97 +#endif
98 +# include <wchar.h>
99 +#if defined(__cplusplus) && !defined(_M_ARM)
100 +}
101 +#endif
102 +
103 +// Define _W64 macros to mark types changing their size, like intptr_t.
104 +#ifndef _W64
105 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
106 +# define _W64 __w64
107 +# else
108 +# define _W64
109 +# endif
110 +#endif
111 +
112 +
113 +// 7.18.1 Integer types
114 +
115 +// 7.18.1.1 Exact-width integer types
116 +
117 +// Visual Studio 6 and Embedded Visual C++ 4 doesn't
118 +// realize that, e.g. char has the same size as __int8
119 +// so we give up on __intX for them.
120 +#if (_MSC_VER < 1300)
121 + typedef signed char int8_t;
122 + typedef signed short int16_t;
123 + typedef signed int int32_t;
124 + typedef unsigned char uint8_t;
125 + typedef unsigned short uint16_t;
126 + typedef unsigned int uint32_t;
127 +#else
128 + typedef signed __int8 int8_t;
129 + typedef signed __int16 int16_t;
130 + typedef signed __int32 int32_t;
131 + typedef unsigned __int8 uint8_t;
132 + typedef unsigned __int16 uint16_t;
133 + typedef unsigned __int32 uint32_t;
134 +#endif
135 +typedef signed __int64 int64_t;
136 +typedef unsigned __int64 uint64_t;
137 +
138 +
139 +// 7.18.1.2 Minimum-width integer types
140 +typedef int8_t int_least8_t;
141 +typedef int16_t int_least16_t;
142 +typedef int32_t int_least32_t;
143 +typedef int64_t int_least64_t;
144 +typedef uint8_t uint_least8_t;
145 +typedef uint16_t uint_least16_t;
146 +typedef uint32_t uint_least32_t;
147 +typedef uint64_t uint_least64_t;
148 +
149 +// 7.18.1.3 Fastest minimum-width integer types
150 +typedef int8_t int_fast8_t;
151 +typedef int16_t int_fast16_t;
152 +typedef int32_t int_fast32_t;
153 +typedef int64_t int_fast64_t;
154 +typedef uint8_t uint_fast8_t;
155 +typedef uint16_t uint_fast16_t;
156 +typedef uint32_t uint_fast32_t;
157 +typedef uint64_t uint_fast64_t;
158 +
159 +// 7.18.1.4 Integer types capable of holding object pointers
160 +#ifdef _WIN64 // [
161 + typedef signed __int64 intptr_t;
162 + typedef unsigned __int64 uintptr_t;
163 +#else // _WIN64 ][
164 + typedef _W64 signed int intptr_t;
165 + typedef _W64 unsigned int uintptr_t;
166 +#endif // _WIN64 ]
167 +
168 +// 7.18.1.5 Greatest-width integer types
169 +typedef int64_t intmax_t;
170 +typedef uint64_t uintmax_t;
171 +
172 +
173 +// 7.18.2 Limits of specified-width integer types
174 +
175 +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
176 +
177 +// 7.18.2.1 Limits of exact-width integer types
178 +#define INT8_MIN ((int8_t)_I8_MIN)
179 +#define INT8_MAX _I8_MAX
180 +#define INT16_MIN ((int16_t)_I16_MIN)
181 +#define INT16_MAX _I16_MAX
182 +#define INT32_MIN ((int32_t)_I32_MIN)
183 +#define INT32_MAX _I32_MAX
184 +#define INT64_MIN ((int64_t)_I64_MIN)
185 +#define INT64_MAX _I64_MAX
186 +#define UINT8_MAX _UI8_MAX
187 +#define UINT16_MAX _UI16_MAX
188 +#define UINT32_MAX _UI32_MAX
189 +#define UINT64_MAX _UI64_MAX
190 +
191 +// 7.18.2.2 Limits of minimum-width integer types
192 +#define INT_LEAST8_MIN INT8_MIN
193 +#define INT_LEAST8_MAX INT8_MAX
194 +#define INT_LEAST16_MIN INT16_MIN
195 +#define INT_LEAST16_MAX INT16_MAX
196 +#define INT_LEAST32_MIN INT32_MIN
197 +#define INT_LEAST32_MAX INT32_MAX
198 +#define INT_LEAST64_MIN INT64_MIN
199 +#define INT_LEAST64_MAX INT64_MAX
200 +#define UINT_LEAST8_MAX UINT8_MAX
201 +#define UINT_LEAST16_MAX UINT16_MAX
202 +#define UINT_LEAST32_MAX UINT32_MAX
203 +#define UINT_LEAST64_MAX UINT64_MAX
204 +
205 +// 7.18.2.3 Limits of fastest minimum-width integer types
206 +#define INT_FAST8_MIN INT8_MIN
207 +#define INT_FAST8_MAX INT8_MAX
208 +#define INT_FAST16_MIN INT16_MIN
209 +#define INT_FAST16_MAX INT16_MAX
210 +#define INT_FAST32_MIN INT32_MIN
211 +#define INT_FAST32_MAX INT32_MAX
212 +#define INT_FAST64_MIN INT64_MIN
213 +#define INT_FAST64_MAX INT64_MAX
214 +#define UINT_FAST8_MAX UINT8_MAX
215 +#define UINT_FAST16_MAX UINT16_MAX
216 +#define UINT_FAST32_MAX UINT32_MAX
217 +#define UINT_FAST64_MAX UINT64_MAX
218 +
219 +// 7.18.2.4 Limits of integer types capable of holding object pointers
220 +#ifdef _WIN64 // [
221 +# define INTPTR_MIN INT64_MIN
222 +# define INTPTR_MAX INT64_MAX
223 +# define UINTPTR_MAX UINT64_MAX
224 +#else // _WIN64 ][
225 +# define INTPTR_MIN INT32_MIN
226 +# define INTPTR_MAX INT32_MAX
227 +# define UINTPTR_MAX UINT32_MAX
228 +#endif // _WIN64 ]
229 +
230 +// 7.18.2.5 Limits of greatest-width integer types
231 +#define INTMAX_MIN INT64_MIN
232 +#define INTMAX_MAX INT64_MAX
233 +#define UINTMAX_MAX UINT64_MAX
234 +
235 +// 7.18.3 Limits of other integer types
236 +
237 +#ifdef _WIN64 // [
238 +# define PTRDIFF_MIN _I64_MIN
239 +# define PTRDIFF_MAX _I64_MAX
240 +#else // _WIN64 ][
241 +# define PTRDIFF_MIN _I32_MIN
242 +# define PTRDIFF_MAX _I32_MAX
243 +#endif // _WIN64 ]
244 +
245 +#define SIG_ATOMIC_MIN INT_MIN
246 +#define SIG_ATOMIC_MAX INT_MAX
247 +
248 +#ifndef SIZE_MAX // [
249 +# ifdef _WIN64 // [
250 +# define SIZE_MAX _UI64_MAX
251 +# else // _WIN64 ][
252 +# define SIZE_MAX _UI32_MAX
253 +# endif // _WIN64 ]
254 +#endif // SIZE_MAX ]
255 +
256 +// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
257 +#ifndef WCHAR_MIN // [
258 +# define WCHAR_MIN 0
259 +#endif // WCHAR_MIN ]
260 +#ifndef WCHAR_MAX // [
261 +# define WCHAR_MAX _UI16_MAX
262 +#endif // WCHAR_MAX ]
263 +
264 +#define WINT_MIN 0
265 +#define WINT_MAX _UI16_MAX
266 +
267 +#endif // __STDC_LIMIT_MACROS ]
268 +
269 +
270 +// 7.18.4 Limits of other integer types
271 +
272 +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
273 +
274 +// 7.18.4.1 Macros for minimum-width integer constants
275 +
276 +#define INT8_C(val) val##i8
277 +#define INT16_C(val) val##i16
278 +#define INT32_C(val) val##i32
279 +#define INT64_C(val) val##i64
280 +
281 +#define UINT8_C(val) val##ui8
282 +#define UINT16_C(val) val##ui16
283 +#define UINT32_C(val) val##ui32
284 +#define UINT64_C(val) val##ui64
285 +
286 +// 7.18.4.2 Macros for greatest-width integer constants
287 +// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
288 +// Check out Issue 9 for the details.
289 +#ifndef INTMAX_C // [
290 +# define INTMAX_C INT64_C
291 +#endif // INTMAX_C ]
292 +#ifndef UINTMAX_C // [
293 +# define UINTMAX_C UINT64_C
294 +#endif // UINTMAX_C ]
295 +
296 +#endif // __STDC_CONSTANT_MACROS ]
297 +
298 +#endif // _MSC_VER >= 1600 ]
299 +
300 +#endif // _MSC_STDINT_H_ ]
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
16 +#define RAPIDJSON_OSTREAMWRAPPER_H_
17 +
18 +#include "stream.h"
19 +#include <iosfwd>
20 +
21 +#ifdef __clang__
22 +RAPIDJSON_DIAG_PUSH
23 +RAPIDJSON_DIAG_OFF(padded)
24 +#endif
25 +
26 +RAPIDJSON_NAMESPACE_BEGIN
27 +
28 +//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
29 +/*!
30 + The classes can be wrapped including but not limited to:
31 +
32 + - \c std::ostringstream
33 + - \c std::stringstream
34 + - \c std::wpstringstream
35 + - \c std::wstringstream
36 + - \c std::ifstream
37 + - \c std::fstream
38 + - \c std::wofstream
39 + - \c std::wfstream
40 +
41 + \tparam StreamType Class derived from \c std::basic_ostream.
42 +*/
43 +
44 +template <typename StreamType>
45 +class BasicOStreamWrapper {
46 +public:
47 + typedef typename StreamType::char_type Ch;
48 + BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
49 +
50 + void Put(Ch c) {
51 + stream_.put(c);
52 + }
53 +
54 + void Flush() {
55 + stream_.flush();
56 + }
57 +
58 + // Not implemented
59 + char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
60 + char Take() { RAPIDJSON_ASSERT(false); return 0; }
61 + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
62 + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
63 + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
64 +
65 +private:
66 + BasicOStreamWrapper(const BasicOStreamWrapper&);
67 + BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
68 +
69 + StreamType& stream_;
70 +};
71 +
72 +typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
73 +typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
74 +
75 +#ifdef __clang__
76 +RAPIDJSON_DIAG_POP
77 +#endif
78 +
79 +RAPIDJSON_NAMESPACE_END
80 +
81 +#endif // RAPIDJSON_OSTREAMWRAPPER_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_POINTER_H_
16 +#define RAPIDJSON_POINTER_H_
17 +
18 +#include "document.h"
19 +#include "internal/itoa.h"
20 +
21 +#ifdef __clang__
22 +RAPIDJSON_DIAG_PUSH
23 +RAPIDJSON_DIAG_OFF(switch-enum)
24 +#endif
25 +
26 +#ifdef _MSC_VER
27 +RAPIDJSON_DIAG_PUSH
28 +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
29 +#endif
30 +
31 +RAPIDJSON_NAMESPACE_BEGIN
32 +
33 +static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
34 +
35 +//! Error code of parsing.
36 +/*! \ingroup RAPIDJSON_ERRORS
37 + \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
38 +*/
39 +enum PointerParseErrorCode {
40 + kPointerParseErrorNone = 0, //!< The parse is successful
41 +
42 + kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
43 + kPointerParseErrorInvalidEscape, //!< Invalid escape
44 + kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
45 + kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
46 +};
47 +
48 +///////////////////////////////////////////////////////////////////////////////
49 +// GenericPointer
50 +
51 +//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
52 +/*!
53 + This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer"
54 + (https://tools.ietf.org/html/rfc6901).
55 +
56 + A JSON pointer is for identifying a specific value in a JSON document
57 + (GenericDocument). It can simplify coding of DOM tree manipulation, because it
58 + can access multiple-level depth of DOM tree with single API call.
59 +
60 + After it parses a string representation (e.g. "/foo/0" or URI fragment
61 + representation (e.g. "#/foo/0") into its internal representation (tokens),
62 + it can be used to resolve a specific value in multiple documents, or sub-tree
63 + of documents.
64 +
65 + Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
66 + Apart from assignment, a Pointer cannot be modified after construction.
67 +
68 + Although Pointer is very convenient, please aware that constructing Pointer
69 + involves parsing and dynamic memory allocation. A special constructor with user-
70 + supplied tokens eliminates these.
71 +
72 + GenericPointer depends on GenericDocument and GenericValue.
73 +
74 + \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
75 + \tparam Allocator The allocator type for allocating memory for internal representation.
76 +
77 + \note GenericPointer uses same encoding of ValueType.
78 + However, Allocator of GenericPointer is independent of Allocator of Value.
79 +*/
80 +template <typename ValueType, typename Allocator = CrtAllocator>
81 +class GenericPointer {
82 +public:
83 + typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
84 + typedef typename ValueType::Ch Ch; //!< Character type from Value
85 +
86 + //! A token is the basic units of internal representation.
87 + /*!
88 + A JSON pointer string representation "/foo/123" is parsed to two tokens:
89 + "foo" and 123. 123 will be represented in both numeric form and string form.
90 + They are resolved according to the actual value type (object or array).
91 +
92 + For token that are not numbers, or the numeric value is out of bound
93 + (greater than limits of SizeType), they are only treated as string form
94 + (i.e. the token's index will be equal to kPointerInvalidIndex).
95 +
96 + This struct is public so that user can create a Pointer without parsing and
97 + allocation, using a special constructor.
98 + */
99 + struct Token {
100 + const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character.
101 + SizeType length; //!< Length of the name.
102 + SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex.
103 + };
104 +
105 + //!@name Constructors and destructor.
106 + //@{
107 +
108 + //! Default constructor.
109 + GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
110 +
111 + //! Constructor that parses a string or URI fragment representation.
112 + /*!
113 + \param source A null-terminated, string or URI fragment representation of JSON pointer.
114 + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
115 + */
116 + explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
117 + Parse(source, internal::StrLen(source));
118 + }
119 +
120 +#if RAPIDJSON_HAS_STDSTRING
121 + //! Constructor that parses a string or URI fragment representation.
122 + /*!
123 + \param source A string or URI fragment representation of JSON pointer.
124 + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
125 + \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
126 + */
127 + explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
128 + Parse(source.c_str(), source.size());
129 + }
130 +#endif
131 +
132 + //! Constructor that parses a string or URI fragment representation, with length of the source string.
133 + /*!
134 + \param source A string or URI fragment representation of JSON pointer.
135 + \param length Length of source.
136 + \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
137 + \note Slightly faster than the overload without length.
138 + */
139 + GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
140 + Parse(source, length);
141 + }
142 +
143 + //! Constructor with user-supplied tokens.
144 + /*!
145 + This constructor let user supplies const array of tokens.
146 + This prevents the parsing process and eliminates allocation.
147 + This is preferred for memory constrained environments.
148 +
149 + \param tokens An constant array of tokens representing the JSON pointer.
150 + \param tokenCount Number of tokens.
151 +
152 + \b Example
153 + \code
154 + #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
155 + #define INDEX(i) { #i, sizeof(#i) - 1, i }
156 +
157 + static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
158 + static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
159 + // Equivalent to static const Pointer p("/foo/123");
160 +
161 + #undef NAME
162 + #undef INDEX
163 + \endcode
164 + */
165 + GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
166 +
167 + //! Copy constructor.
168 + GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
169 + *this = rhs;
170 + }
171 +
172 + //! Destructor.
173 + ~GenericPointer() {
174 + if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
175 + Allocator::Free(tokens_);
176 + RAPIDJSON_DELETE(ownAllocator_);
177 + }
178 +
179 + //! Assignment operator.
180 + GenericPointer& operator=(const GenericPointer& rhs) {
181 + if (this != &rhs) {
182 + // Do not delete ownAllcator
183 + if (nameBuffer_)
184 + Allocator::Free(tokens_);
185 +
186 + tokenCount_ = rhs.tokenCount_;
187 + parseErrorOffset_ = rhs.parseErrorOffset_;
188 + parseErrorCode_ = rhs.parseErrorCode_;
189 +
190 + if (rhs.nameBuffer_)
191 + CopyFromRaw(rhs); // Normally parsed tokens.
192 + else {
193 + tokens_ = rhs.tokens_; // User supplied const tokens.
194 + nameBuffer_ = 0;
195 + }
196 + }
197 + return *this;
198 + }
199 +
200 + //@}
201 +
202 + //!@name Append token
203 + //@{
204 +
205 + //! Append a token and return a new Pointer
206 + /*!
207 + \param token Token to be appended.
208 + \param allocator Allocator for the newly return Pointer.
209 + \return A new Pointer with appended token.
210 + */
211 + GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
212 + GenericPointer r;
213 + r.allocator_ = allocator;
214 + Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
215 + std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
216 + r.tokens_[tokenCount_].name = p;
217 + r.tokens_[tokenCount_].length = token.length;
218 + r.tokens_[tokenCount_].index = token.index;
219 + return r;
220 + }
221 +
222 + //! Append a name token with length, and return a new Pointer
223 + /*!
224 + \param name Name to be appended.
225 + \param length Length of name.
226 + \param allocator Allocator for the newly return Pointer.
227 + \return A new Pointer with appended token.
228 + */
229 + GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
230 + Token token = { name, length, kPointerInvalidIndex };
231 + return Append(token, allocator);
232 + }
233 +
234 + //! Append a name token without length, and return a new Pointer
235 + /*!
236 + \param name Name (const Ch*) to be appended.
237 + \param allocator Allocator for the newly return Pointer.
238 + \return A new Pointer with appended token.
239 + */
240 + template <typename T>
241 + RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
242 + Append(T* name, Allocator* allocator = 0) const {
243 + return Append(name, internal::StrLen(name), allocator);
244 + }
245 +
246 +#if RAPIDJSON_HAS_STDSTRING
247 + //! Append a name token, and return a new Pointer
248 + /*!
249 + \param name Name to be appended.
250 + \param allocator Allocator for the newly return Pointer.
251 + \return A new Pointer with appended token.
252 + */
253 + GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
254 + return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
255 + }
256 +#endif
257 +
258 + //! Append a index token, and return a new Pointer
259 + /*!
260 + \param index Index to be appended.
261 + \param allocator Allocator for the newly return Pointer.
262 + \return A new Pointer with appended token.
263 + */
264 + GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
265 + char buffer[21];
266 + char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
267 + SizeType length = static_cast<SizeType>(end - buffer);
268 + buffer[length] = '\0';
269 +
270 + if (sizeof(Ch) == 1) {
271 + Token token = { reinterpret_cast<Ch*>(buffer), length, index };
272 + return Append(token, allocator);
273 + }
274 + else {
275 + Ch name[21];
276 + for (size_t i = 0; i <= length; i++)
277 + name[i] = static_cast<Ch>(buffer[i]);
278 + Token token = { name, length, index };
279 + return Append(token, allocator);
280 + }
281 + }
282 +
283 + //! Append a token by value, and return a new Pointer
284 + /*!
285 + \param token token to be appended.
286 + \param allocator Allocator for the newly return Pointer.
287 + \return A new Pointer with appended token.
288 + */
289 + GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
290 + if (token.IsString())
291 + return Append(token.GetString(), token.GetStringLength(), allocator);
292 + else {
293 + RAPIDJSON_ASSERT(token.IsUint64());
294 + RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
295 + return Append(static_cast<SizeType>(token.GetUint64()), allocator);
296 + }
297 + }
298 +
299 + //!@name Handling Parse Error
300 + //@{
301 +
302 + //! Check whether this is a valid pointer.
303 + bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
304 +
305 + //! Get the parsing error offset in code unit.
306 + size_t GetParseErrorOffset() const { return parseErrorOffset_; }
307 +
308 + //! Get the parsing error code.
309 + PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
310 +
311 + //@}
312 +
313 + //! Get the allocator of this pointer.
314 + Allocator& GetAllocator() { return *allocator_; }
315 +
316 + //!@name Tokens
317 + //@{
318 +
319 + //! Get the token array (const version only).
320 + const Token* GetTokens() const { return tokens_; }
321 +
322 + //! Get the number of tokens.
323 + size_t GetTokenCount() const { return tokenCount_; }
324 +
325 + //@}
326 +
327 + //!@name Equality/inequality operators
328 + //@{
329 +
330 + //! Equality operator.
331 + /*!
332 + \note When any pointers are invalid, always returns false.
333 + */
334 + bool operator==(const GenericPointer& rhs) const {
335 + if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
336 + return false;
337 +
338 + for (size_t i = 0; i < tokenCount_; i++) {
339 + if (tokens_[i].index != rhs.tokens_[i].index ||
340 + tokens_[i].length != rhs.tokens_[i].length ||
341 + (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
342 + {
343 + return false;
344 + }
345 + }
346 +
347 + return true;
348 + }
349 +
350 + //! Inequality operator.
351 + /*!
352 + \note When any pointers are invalid, always returns true.
353 + */
354 + bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
355 +
356 + //@}
357 +
358 + //!@name Stringify
359 + //@{
360 +
361 + //! Stringify the pointer into string representation.
362 + /*!
363 + \tparam OutputStream Type of output stream.
364 + \param os The output stream.
365 + */
366 + template<typename OutputStream>
367 + bool Stringify(OutputStream& os) const {
368 + return Stringify<false, OutputStream>(os);
369 + }
370 +
371 + //! Stringify the pointer into URI fragment representation.
372 + /*!
373 + \tparam OutputStream Type of output stream.
374 + \param os The output stream.
375 + */
376 + template<typename OutputStream>
377 + bool StringifyUriFragment(OutputStream& os) const {
378 + return Stringify<true, OutputStream>(os);
379 + }
380 +
381 + //@}
382 +
383 + //!@name Create value
384 + //@{
385 +
386 + //! Create a value in a subtree.
387 + /*!
388 + If the value is not exist, it creates all parent values and a JSON Null value.
389 + So it always succeed and return the newly created or existing value.
390 +
391 + Remind that it may change types of parents according to tokens, so it
392 + potentially removes previously stored values. For example, if a document
393 + was an array, and "/foo" is used to create a value, then the document
394 + will be changed to an object, and all existing array elements are lost.
395 +
396 + \param root Root value of a DOM subtree to be resolved. It can be any value other than document root.
397 + \param allocator Allocator for creating the values if the specified value or its parents are not exist.
398 + \param alreadyExist If non-null, it stores whether the resolved value is already exist.
399 + \return The resolved newly created (a JSON Null value), or already exists value.
400 + */
401 + ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
402 + RAPIDJSON_ASSERT(IsValid());
403 + ValueType* v = &root;
404 + bool exist = true;
405 + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
406 + if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
407 + v->PushBack(ValueType().Move(), allocator);
408 + v = &((*v)[v->Size() - 1]);
409 + exist = false;
410 + }
411 + else {
412 + if (t->index == kPointerInvalidIndex) { // must be object name
413 + if (!v->IsObject())
414 + v->SetObject(); // Change to Object
415 + }
416 + else { // object name or array index
417 + if (!v->IsArray() && !v->IsObject())
418 + v->SetArray(); // Change to Array
419 + }
420 +
421 + if (v->IsArray()) {
422 + if (t->index >= v->Size()) {
423 + v->Reserve(t->index + 1, allocator);
424 + while (t->index >= v->Size())
425 + v->PushBack(ValueType().Move(), allocator);
426 + exist = false;
427 + }
428 + v = &((*v)[t->index]);
429 + }
430 + else {
431 + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
432 + if (m == v->MemberEnd()) {
433 + v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
434 + v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
435 + exist = false;
436 + }
437 + else
438 + v = &m->value;
439 + }
440 + }
441 + }
442 +
443 + if (alreadyExist)
444 + *alreadyExist = exist;
445 +
446 + return *v;
447 + }
448 +
449 + //! Creates a value in a document.
450 + /*!
451 + \param document A document to be resolved.
452 + \param alreadyExist If non-null, it stores whether the resolved value is already exist.
453 + \return The resolved newly created, or already exists value.
454 + */
455 + template <typename stackAllocator>
456 + ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {
457 + return Create(document, document.GetAllocator(), alreadyExist);
458 + }
459 +
460 + //@}
461 +
462 + //!@name Query value
463 + //@{
464 +
465 + //! Query a value in a subtree.
466 + /*!
467 + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
468 + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
469 + \return Pointer to the value if it can be resolved. Otherwise null.
470 +
471 + \note
472 + There are only 3 situations when a value cannot be resolved:
473 + 1. A value in the path is not an array nor object.
474 + 2. An object value does not contain the token.
475 + 3. A token is out of range of an array value.
476 +
477 + Use unresolvedTokenIndex to retrieve the token index.
478 + */
479 + ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
480 + RAPIDJSON_ASSERT(IsValid());
481 + ValueType* v = &root;
482 + for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
483 + switch (v->GetType()) {
484 + case kObjectType:
485 + {
486 + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
487 + if (m == v->MemberEnd())
488 + break;
489 + v = &m->value;
490 + }
491 + continue;
492 + case kArrayType:
493 + if (t->index == kPointerInvalidIndex || t->index >= v->Size())
494 + break;
495 + v = &((*v)[t->index]);
496 + continue;
497 + default:
498 + break;
499 + }
500 +
501 + // Error: unresolved token
502 + if (unresolvedTokenIndex)
503 + *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
504 + return 0;
505 + }
506 + return v;
507 + }
508 +
509 + //! Query a const value in a const subtree.
510 + /*!
511 + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
512 + \return Pointer to the value if it can be resolved. Otherwise null.
513 + */
514 + const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
515 + return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
516 + }
517 +
518 + //@}
519 +
520 + //!@name Query a value with default
521 + //@{
522 +
523 + //! Query a value in a subtree with default value.
524 + /*!
525 + Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.
526 + So that this function always succeed.
527 +
528 + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
529 + \param defaultValue Default value to be cloned if the value was not exists.
530 + \param allocator Allocator for creating the values if the specified value or its parents are not exist.
531 + \see Create()
532 + */
533 + ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
534 + bool alreadyExist;
535 + Value& v = Create(root, allocator, &alreadyExist);
536 + return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
537 + }
538 +
539 + //! Query a value in a subtree with default null-terminated string.
540 + ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
541 + bool alreadyExist;
542 + Value& v = Create(root, allocator, &alreadyExist);
543 + return alreadyExist ? v : v.SetString(defaultValue, allocator);
544 + }
545 +
546 +#if RAPIDJSON_HAS_STDSTRING
547 + //! Query a value in a subtree with default std::basic_string.
548 + ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
549 + bool alreadyExist;
550 + Value& v = Create(root, allocator, &alreadyExist);
551 + return alreadyExist ? v : v.SetString(defaultValue, allocator);
552 + }
553 +#endif
554 +
555 + //! Query a value in a subtree with default primitive value.
556 + /*!
557 + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
558 + */
559 + template <typename T>
560 + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
561 + GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
562 + return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
563 + }
564 +
565 + //! Query a value in a document with default value.
566 + template <typename stackAllocator>
567 + ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {
568 + return GetWithDefault(document, defaultValue, document.GetAllocator());
569 + }
570 +
571 + //! Query a value in a document with default null-terminated string.
572 + template <typename stackAllocator>
573 + ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
574 + return GetWithDefault(document, defaultValue, document.GetAllocator());
575 + }
576 +
577 +#if RAPIDJSON_HAS_STDSTRING
578 + //! Query a value in a document with default std::basic_string.
579 + template <typename stackAllocator>
580 + ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {
581 + return GetWithDefault(document, defaultValue, document.GetAllocator());
582 + }
583 +#endif
584 +
585 + //! Query a value in a document with default primitive value.
586 + /*!
587 + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
588 + */
589 + template <typename T, typename stackAllocator>
590 + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
591 + GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
592 + return GetWithDefault(document, defaultValue, document.GetAllocator());
593 + }
594 +
595 + //@}
596 +
597 + //!@name Set a value
598 + //@{
599 +
600 + //! Set a value in a subtree, with move semantics.
601 + /*!
602 + It creates all parents if they are not exist or types are different to the tokens.
603 + So this function always succeeds but potentially remove existing values.
604 +
605 + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
606 + \param value Value to be set.
607 + \param allocator Allocator for creating the values if the specified value or its parents are not exist.
608 + \see Create()
609 + */
610 + ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
611 + return Create(root, allocator) = value;
612 + }
613 +
614 + //! Set a value in a subtree, with copy semantics.
615 + ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {
616 + return Create(root, allocator).CopyFrom(value, allocator);
617 + }
618 +
619 + //! Set a null-terminated string in a subtree.
620 + ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {
621 + return Create(root, allocator) = ValueType(value, allocator).Move();
622 + }
623 +
624 +#if RAPIDJSON_HAS_STDSTRING
625 + //! Set a std::basic_string in a subtree.
626 + ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {
627 + return Create(root, allocator) = ValueType(value, allocator).Move();
628 + }
629 +#endif
630 +
631 + //! Set a primitive value in a subtree.
632 + /*!
633 + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
634 + */
635 + template <typename T>
636 + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
637 + Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
638 + return Create(root, allocator) = ValueType(value).Move();
639 + }
640 +
641 + //! Set a value in a document, with move semantics.
642 + template <typename stackAllocator>
643 + ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
644 + return Create(document) = value;
645 + }
646 +
647 + //! Set a value in a document, with copy semantics.
648 + template <typename stackAllocator>
649 + ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {
650 + return Create(document).CopyFrom(value, document.GetAllocator());
651 + }
652 +
653 + //! Set a null-terminated string in a document.
654 + template <typename stackAllocator>
655 + ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {
656 + return Create(document) = ValueType(value, document.GetAllocator()).Move();
657 + }
658 +
659 +#if RAPIDJSON_HAS_STDSTRING
660 + //! Sets a std::basic_string in a document.
661 + template <typename stackAllocator>
662 + ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {
663 + return Create(document) = ValueType(value, document.GetAllocator()).Move();
664 + }
665 +#endif
666 +
667 + //! Set a primitive value in a document.
668 + /*!
669 + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
670 + */
671 + template <typename T, typename stackAllocator>
672 + RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
673 + Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
674 + return Create(document) = value;
675 + }
676 +
677 + //@}
678 +
679 + //!@name Swap a value
680 + //@{
681 +
682 + //! Swap a value with a value in a subtree.
683 + /*!
684 + It creates all parents if they are not exist or types are different to the tokens.
685 + So this function always succeeds but potentially remove existing values.
686 +
687 + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
688 + \param value Value to be swapped.
689 + \param allocator Allocator for creating the values if the specified value or its parents are not exist.
690 + \see Create()
691 + */
692 + ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
693 + return Create(root, allocator).Swap(value);
694 + }
695 +
696 + //! Swap a value with a value in a document.
697 + template <typename stackAllocator>
698 + ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
699 + return Create(document).Swap(value);
700 + }
701 +
702 + //@}
703 +
704 + //! Erase a value in a subtree.
705 + /*!
706 + \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
707 + \return Whether the resolved value is found and erased.
708 +
709 + \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
710 + */
711 + bool Erase(ValueType& root) const {
712 + RAPIDJSON_ASSERT(IsValid());
713 + if (tokenCount_ == 0) // Cannot erase the root
714 + return false;
715 +
716 + ValueType* v = &root;
717 + const Token* last = tokens_ + (tokenCount_ - 1);
718 + for (const Token *t = tokens_; t != last; ++t) {
719 + switch (v->GetType()) {
720 + case kObjectType:
721 + {
722 + typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
723 + if (m == v->MemberEnd())
724 + return false;
725 + v = &m->value;
726 + }
727 + break;
728 + case kArrayType:
729 + if (t->index == kPointerInvalidIndex || t->index >= v->Size())
730 + return false;
731 + v = &((*v)[t->index]);
732 + break;
733 + default:
734 + return false;
735 + }
736 + }
737 +
738 + switch (v->GetType()) {
739 + case kObjectType:
740 + return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
741 + case kArrayType:
742 + if (last->index == kPointerInvalidIndex || last->index >= v->Size())
743 + return false;
744 + v->Erase(v->Begin() + last->index);
745 + return true;
746 + default:
747 + return false;
748 + }
749 + }
750 +
751 +private:
752 + //! Clone the content from rhs to this.
753 + /*!
754 + \param rhs Source pointer.
755 + \param extraToken Extra tokens to be allocated.
756 + \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.
757 + \return Start of non-occupied name buffer, for storing extra names.
758 + */
759 + Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
760 + if (!allocator_) // allocator is independently owned.
761 + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
762 +
763 + size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
764 + for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
765 + nameBufferSize += t->length;
766 +
767 + tokenCount_ = rhs.tokenCount_ + extraToken;
768 + tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
769 + nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
770 + if (rhs.tokenCount_ > 0) {
771 + std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
772 + }
773 + if (nameBufferSize > 0) {
774 + std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
775 + }
776 +
777 + // Adjust pointers to name buffer
778 + std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
779 + for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
780 + t->name += diff;
781 +
782 + return nameBuffer_ + nameBufferSize;
783 + }
784 +
785 + //! Check whether a character should be percent-encoded.
786 + /*!
787 + According to RFC 3986 2.3 Unreserved Characters.
788 + \param c The character (code unit) to be tested.
789 + */
790 + bool NeedPercentEncode(Ch c) const {
791 + return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');
792 + }
793 +
794 + //! Parse a JSON String or its URI fragment representation into tokens.
795 +#ifndef __clang__ // -Wdocumentation
796 + /*!
797 + \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.
798 + \param length Length of the source string.
799 + \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
800 + */
801 +#endif
802 + void Parse(const Ch* source, size_t length) {
803 + RAPIDJSON_ASSERT(source != NULL);
804 + RAPIDJSON_ASSERT(nameBuffer_ == 0);
805 + RAPIDJSON_ASSERT(tokens_ == 0);
806 +
807 + // Create own allocator if user did not supply.
808 + if (!allocator_)
809 + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
810 +
811 + // Count number of '/' as tokenCount
812 + tokenCount_ = 0;
813 + for (const Ch* s = source; s != source + length; s++)
814 + if (*s == '/')
815 + tokenCount_++;
816 +
817 + Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
818 + Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
819 + size_t i = 0;
820 +
821 + // Detect if it is a URI fragment
822 + bool uriFragment = false;
823 + if (source[i] == '#') {
824 + uriFragment = true;
825 + i++;
826 + }
827 +
828 + if (i != length && source[i] != '/') {
829 + parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
830 + goto error;
831 + }
832 +
833 + while (i < length) {
834 + RAPIDJSON_ASSERT(source[i] == '/');
835 + i++; // consumes '/'
836 +
837 + token->name = name;
838 + bool isNumber = true;
839 +
840 + while (i < length && source[i] != '/') {
841 + Ch c = source[i];
842 + if (uriFragment) {
843 + // Decoding percent-encoding for URI fragment
844 + if (c == '%') {
845 + PercentDecodeStream is(&source[i], source + length);
846 + GenericInsituStringStream<EncodingType> os(name);
847 + Ch* begin = os.PutBegin();
848 + if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {
849 + parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;
850 + goto error;
851 + }
852 + size_t len = os.PutEnd(begin);
853 + i += is.Tell() - 1;
854 + if (len == 1)
855 + c = *name;
856 + else {
857 + name += len;
858 + isNumber = false;
859 + i++;
860 + continue;
861 + }
862 + }
863 + else if (NeedPercentEncode(c)) {
864 + parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;
865 + goto error;
866 + }
867 + }
868 +
869 + i++;
870 +
871 + // Escaping "~0" -> '~', "~1" -> '/'
872 + if (c == '~') {
873 + if (i < length) {
874 + c = source[i];
875 + if (c == '0') c = '~';
876 + else if (c == '1') c = '/';
877 + else {
878 + parseErrorCode_ = kPointerParseErrorInvalidEscape;
879 + goto error;
880 + }
881 + i++;
882 + }
883 + else {
884 + parseErrorCode_ = kPointerParseErrorInvalidEscape;
885 + goto error;
886 + }
887 + }
888 +
889 + // First check for index: all of characters are digit
890 + if (c < '0' || c > '9')
891 + isNumber = false;
892 +
893 + *name++ = c;
894 + }
895 + token->length = static_cast<SizeType>(name - token->name);
896 + if (token->length == 0)
897 + isNumber = false;
898 + *name++ = '\0'; // Null terminator
899 +
900 + // Second check for index: more than one digit cannot have leading zero
901 + if (isNumber && token->length > 1 && token->name[0] == '0')
902 + isNumber = false;
903 +
904 + // String to SizeType conversion
905 + SizeType n = 0;
906 + if (isNumber) {
907 + for (size_t j = 0; j < token->length; j++) {
908 + SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
909 + if (m < n) { // overflow detection
910 + isNumber = false;
911 + break;
912 + }
913 + n = m;
914 + }
915 + }
916 +
917 + token->index = isNumber ? n : kPointerInvalidIndex;
918 + token++;
919 + }
920 +
921 + RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
922 + parseErrorCode_ = kPointerParseErrorNone;
923 + return;
924 +
925 + error:
926 + Allocator::Free(tokens_);
927 + nameBuffer_ = 0;
928 + tokens_ = 0;
929 + tokenCount_ = 0;
930 + parseErrorOffset_ = i;
931 + return;
932 + }
933 +
934 + //! Stringify to string or URI fragment representation.
935 + /*!
936 + \tparam uriFragment True for stringifying to URI fragment representation. False for string representation.
937 + \tparam OutputStream type of output stream.
938 + \param os The output stream.
939 + */
940 + template<bool uriFragment, typename OutputStream>
941 + bool Stringify(OutputStream& os) const {
942 + RAPIDJSON_ASSERT(IsValid());
943 +
944 + if (uriFragment)
945 + os.Put('#');
946 +
947 + for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
948 + os.Put('/');
949 + for (size_t j = 0; j < t->length; j++) {
950 + Ch c = t->name[j];
951 + if (c == '~') {
952 + os.Put('~');
953 + os.Put('0');
954 + }
955 + else if (c == '/') {
956 + os.Put('~');
957 + os.Put('1');
958 + }
959 + else if (uriFragment && NeedPercentEncode(c)) {
960 + // Transcode to UTF8 sequence
961 + GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);
962 + PercentEncodeStream<OutputStream> target(os);
963 + if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))
964 + return false;
965 + j += source.Tell() - 1;
966 + }
967 + else
968 + os.Put(c);
969 + }
970 + }
971 + return true;
972 + }
973 +
974 + //! A helper stream for decoding a percent-encoded sequence into code unit.
975 + /*!
976 + This stream decodes %XY triplet into code unit (0-255).
977 + If it encounters invalid characters, it sets output code unit as 0 and
978 + mark invalid, and to be checked by IsValid().
979 + */
980 + class PercentDecodeStream {
981 + public:
982 + typedef typename ValueType::Ch Ch;
983 +
984 + //! Constructor
985 + /*!
986 + \param source Start of the stream
987 + \param end Past-the-end of the stream.
988 + */
989 + PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
990 +
991 + Ch Take() {
992 + if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
993 + valid_ = false;
994 + return 0;
995 + }
996 + src_++;
997 + Ch c = 0;
998 + for (int j = 0; j < 2; j++) {
999 + c = static_cast<Ch>(c << 4);
1000 + Ch h = *src_;
1001 + if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
1002 + else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
1003 + else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
1004 + else {
1005 + valid_ = false;
1006 + return 0;
1007 + }
1008 + src_++;
1009 + }
1010 + return c;
1011 + }
1012 +
1013 + size_t Tell() const { return static_cast<size_t>(src_ - head_); }
1014 + bool IsValid() const { return valid_; }
1015 +
1016 + private:
1017 + const Ch* src_; //!< Current read position.
1018 + const Ch* head_; //!< Original head of the string.
1019 + const Ch* end_; //!< Past-the-end position.
1020 + bool valid_; //!< Whether the parsing is valid.
1021 + };
1022 +
1023 + //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
1024 + template <typename OutputStream>
1025 + class PercentEncodeStream {
1026 + public:
1027 + PercentEncodeStream(OutputStream& os) : os_(os) {}
1028 + void Put(char c) { // UTF-8 must be byte
1029 + unsigned char u = static_cast<unsigned char>(c);
1030 + static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
1031 + os_.Put('%');
1032 + os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4]));
1033 + os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15]));
1034 + }
1035 + private:
1036 + OutputStream& os_;
1037 + };
1038 +
1039 + Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
1040 + Allocator* ownAllocator_; //!< Allocator owned by this Pointer.
1041 + Ch* nameBuffer_; //!< A buffer containing all names in tokens.
1042 + Token* tokens_; //!< A list of tokens.
1043 + size_t tokenCount_; //!< Number of tokens in tokens_.
1044 + size_t parseErrorOffset_; //!< Offset in code unit when parsing fail.
1045 + PointerParseErrorCode parseErrorCode_; //!< Parsing error code.
1046 +};
1047 +
1048 +//! GenericPointer for Value (UTF-8, default allocator).
1049 +typedef GenericPointer<Value> Pointer;
1050 +
1051 +//!@name Helper functions for GenericPointer
1052 +//@{
1053 +
1054 +//////////////////////////////////////////////////////////////////////////////
1055 +
1056 +template <typename T>
1057 +typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
1058 + return pointer.Create(root, a);
1059 +}
1060 +
1061 +template <typename T, typename CharType, size_t N>
1062 +typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {
1063 + return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
1064 +}
1065 +
1066 +// No allocator parameter
1067 +
1068 +template <typename DocumentType>
1069 +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
1070 + return pointer.Create(document);
1071 +}
1072 +
1073 +template <typename DocumentType, typename CharType, size_t N>
1074 +typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
1075 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
1076 +}
1077 +
1078 +//////////////////////////////////////////////////////////////////////////////
1079 +
1080 +template <typename T>
1081 +typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
1082 + return pointer.Get(root, unresolvedTokenIndex);
1083 +}
1084 +
1085 +template <typename T>
1086 +const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
1087 + return pointer.Get(root, unresolvedTokenIndex);
1088 +}
1089 +
1090 +template <typename T, typename CharType, size_t N>
1091 +typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
1092 + return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
1093 +}
1094 +
1095 +template <typename T, typename CharType, size_t N>
1096 +const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
1097 + return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
1098 +}
1099 +
1100 +//////////////////////////////////////////////////////////////////////////////
1101 +
1102 +template <typename T>
1103 +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
1104 + return pointer.GetWithDefault(root, defaultValue, a);
1105 +}
1106 +
1107 +template <typename T>
1108 +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
1109 + return pointer.GetWithDefault(root, defaultValue, a);
1110 +}
1111 +
1112 +#if RAPIDJSON_HAS_STDSTRING
1113 +template <typename T>
1114 +typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
1115 + return pointer.GetWithDefault(root, defaultValue, a);
1116 +}
1117 +#endif
1118 +
1119 +template <typename T, typename T2>
1120 +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1121 +GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
1122 + return pointer.GetWithDefault(root, defaultValue, a);
1123 +}
1124 +
1125 +template <typename T, typename CharType, size_t N>
1126 +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
1127 + return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1128 +}
1129 +
1130 +template <typename T, typename CharType, size_t N>
1131 +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
1132 + return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1133 +}
1134 +
1135 +#if RAPIDJSON_HAS_STDSTRING
1136 +template <typename T, typename CharType, size_t N>
1137 +typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
1138 + return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1139 +}
1140 +#endif
1141 +
1142 +template <typename T, typename CharType, size_t N, typename T2>
1143 +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1144 +GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
1145 + return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
1146 +}
1147 +
1148 +// No allocator parameter
1149 +
1150 +template <typename DocumentType>
1151 +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
1152 + return pointer.GetWithDefault(document, defaultValue);
1153 +}
1154 +
1155 +template <typename DocumentType>
1156 +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {
1157 + return pointer.GetWithDefault(document, defaultValue);
1158 +}
1159 +
1160 +#if RAPIDJSON_HAS_STDSTRING
1161 +template <typename DocumentType>
1162 +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {
1163 + return pointer.GetWithDefault(document, defaultValue);
1164 +}
1165 +#endif
1166 +
1167 +template <typename DocumentType, typename T2>
1168 +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1169 +GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
1170 + return pointer.GetWithDefault(document, defaultValue);
1171 +}
1172 +
1173 +template <typename DocumentType, typename CharType, size_t N>
1174 +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {
1175 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1176 +}
1177 +
1178 +template <typename DocumentType, typename CharType, size_t N>
1179 +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {
1180 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1181 +}
1182 +
1183 +#if RAPIDJSON_HAS_STDSTRING
1184 +template <typename DocumentType, typename CharType, size_t N>
1185 +typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
1186 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1187 +}
1188 +#endif
1189 +
1190 +template <typename DocumentType, typename CharType, size_t N, typename T2>
1191 +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1192 +GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
1193 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
1194 +}
1195 +
1196 +//////////////////////////////////////////////////////////////////////////////
1197 +
1198 +template <typename T>
1199 +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
1200 + return pointer.Set(root, value, a);
1201 +}
1202 +
1203 +template <typename T>
1204 +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {
1205 + return pointer.Set(root, value, a);
1206 +}
1207 +
1208 +template <typename T>
1209 +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {
1210 + return pointer.Set(root, value, a);
1211 +}
1212 +
1213 +#if RAPIDJSON_HAS_STDSTRING
1214 +template <typename T>
1215 +typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
1216 + return pointer.Set(root, value, a);
1217 +}
1218 +#endif
1219 +
1220 +template <typename T, typename T2>
1221 +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1222 +SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
1223 + return pointer.Set(root, value, a);
1224 +}
1225 +
1226 +template <typename T, typename CharType, size_t N>
1227 +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
1228 + return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1229 +}
1230 +
1231 +template <typename T, typename CharType, size_t N>
1232 +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {
1233 + return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1234 +}
1235 +
1236 +template <typename T, typename CharType, size_t N>
1237 +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {
1238 + return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1239 +}
1240 +
1241 +#if RAPIDJSON_HAS_STDSTRING
1242 +template <typename T, typename CharType, size_t N>
1243 +typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
1244 + return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1245 +}
1246 +#endif
1247 +
1248 +template <typename T, typename CharType, size_t N, typename T2>
1249 +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
1250 +SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {
1251 + return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
1252 +}
1253 +
1254 +// No allocator parameter
1255 +
1256 +template <typename DocumentType>
1257 +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1258 + return pointer.Set(document, value);
1259 +}
1260 +
1261 +template <typename DocumentType>
1262 +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
1263 + return pointer.Set(document, value);
1264 +}
1265 +
1266 +template <typename DocumentType>
1267 +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {
1268 + return pointer.Set(document, value);
1269 +}
1270 +
1271 +#if RAPIDJSON_HAS_STDSTRING
1272 +template <typename DocumentType>
1273 +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {
1274 + return pointer.Set(document, value);
1275 +}
1276 +#endif
1277 +
1278 +template <typename DocumentType, typename T2>
1279 +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1280 +SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
1281 + return pointer.Set(document, value);
1282 +}
1283 +
1284 +template <typename DocumentType, typename CharType, size_t N>
1285 +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
1286 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1287 +}
1288 +
1289 +template <typename DocumentType, typename CharType, size_t N>
1290 +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {
1291 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1292 +}
1293 +
1294 +template <typename DocumentType, typename CharType, size_t N>
1295 +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {
1296 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1297 +}
1298 +
1299 +#if RAPIDJSON_HAS_STDSTRING
1300 +template <typename DocumentType, typename CharType, size_t N>
1301 +typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
1302 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1303 +}
1304 +#endif
1305 +
1306 +template <typename DocumentType, typename CharType, size_t N, typename T2>
1307 +RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
1308 +SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
1309 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
1310 +}
1311 +
1312 +//////////////////////////////////////////////////////////////////////////////
1313 +
1314 +template <typename T>
1315 +typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
1316 + return pointer.Swap(root, value, a);
1317 +}
1318 +
1319 +template <typename T, typename CharType, size_t N>
1320 +typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
1321 + return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);
1322 +}
1323 +
1324 +template <typename DocumentType>
1325 +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
1326 + return pointer.Swap(document, value);
1327 +}
1328 +
1329 +template <typename DocumentType, typename CharType, size_t N>
1330 +typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
1331 + return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
1332 +}
1333 +
1334 +//////////////////////////////////////////////////////////////////////////////
1335 +
1336 +template <typename T>
1337 +bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
1338 + return pointer.Erase(root);
1339 +}
1340 +
1341 +template <typename T, typename CharType, size_t N>
1342 +bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
1343 + return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
1344 +}
1345 +
1346 +//@}
1347 +
1348 +RAPIDJSON_NAMESPACE_END
1349 +
1350 +#ifdef __clang__
1351 +RAPIDJSON_DIAG_POP
1352 +#endif
1353 +
1354 +#ifdef _MSC_VER
1355 +RAPIDJSON_DIAG_POP
1356 +#endif
1357 +
1358 +#endif // RAPIDJSON_POINTER_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_PRETTYWRITER_H_
16 +#define RAPIDJSON_PRETTYWRITER_H_
17 +
18 +#include "writer.h"
19 +
20 +#ifdef __GNUC__
21 +RAPIDJSON_DIAG_PUSH
22 +RAPIDJSON_DIAG_OFF(effc++)
23 +#endif
24 +
25 +#if defined(__clang__)
26 +RAPIDJSON_DIAG_PUSH
27 +RAPIDJSON_DIAG_OFF(c++98-compat)
28 +#endif
29 +
30 +RAPIDJSON_NAMESPACE_BEGIN
31 +
32 +//! Combination of PrettyWriter format flags.
33 +/*! \see PrettyWriter::SetFormatOptions
34 + */
35 +enum PrettyFormatOptions {
36 + kFormatDefault = 0, //!< Default pretty formatting.
37 + kFormatSingleLineArray = 1 //!< Format arrays on a single line.
38 +};
39 +
40 +//! Writer with indentation and spacing.
41 +/*!
42 + \tparam OutputStream Type of ouptut os.
43 + \tparam SourceEncoding Encoding of source string.
44 + \tparam TargetEncoding Encoding of output stream.
45 + \tparam StackAllocator Type of allocator for allocating memory of stack.
46 +*/
47 +template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
48 +class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
49 +public:
50 + typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
51 + typedef typename Base::Ch Ch;
52 +
53 + //! Constructor
54 + /*! \param os Output stream.
55 + \param allocator User supplied allocator. If it is null, it will create a private one.
56 + \param levelDepth Initial capacity of stack.
57 + */
58 + explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
59 + Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
60 +
61 +
62 + explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
63 + Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
64 +
65 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
66 + PrettyWriter(PrettyWriter&& rhs) :
67 + Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
68 +#endif
69 +
70 + //! Set custom indentation.
71 + /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
72 + \param indentCharCount Number of indent characters for each indentation level.
73 + \note The default indentation is 4 spaces.
74 + */
75 + PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
76 + RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
77 + indentChar_ = indentChar;
78 + indentCharCount_ = indentCharCount;
79 + return *this;
80 + }
81 +
82 + //! Set pretty writer formatting options.
83 + /*! \param options Formatting options.
84 + */
85 + PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
86 + formatOptions_ = options;
87 + return *this;
88 + }
89 +
90 + /*! @name Implementation of Handler
91 + \see Handler
92 + */
93 + //@{
94 +
95 + bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
96 + bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
97 + bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
98 + bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
99 + bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
100 + bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
101 + bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
102 +
103 + bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
104 + RAPIDJSON_ASSERT(str != 0);
105 + (void)copy;
106 + PrettyPrefix(kNumberType);
107 + return Base::WriteString(str, length);
108 + }
109 +
110 + bool String(const Ch* str, SizeType length, bool copy = false) {
111 + RAPIDJSON_ASSERT(str != 0);
112 + (void)copy;
113 + PrettyPrefix(kStringType);
114 + return Base::WriteString(str, length);
115 + }
116 +
117 +#if RAPIDJSON_HAS_STDSTRING
118 + bool String(const std::basic_string<Ch>& str) {
119 + return String(str.data(), SizeType(str.size()));
120 + }
121 +#endif
122 +
123 + bool StartObject() {
124 + PrettyPrefix(kObjectType);
125 + new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
126 + return Base::WriteStartObject();
127 + }
128 +
129 + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
130 +
131 +#if RAPIDJSON_HAS_STDSTRING
132 + bool Key(const std::basic_string<Ch>& str) {
133 + return Key(str.data(), SizeType(str.size()));
134 + }
135 +#endif
136 +
137 + bool EndObject(SizeType memberCount = 0) {
138 + (void)memberCount;
139 + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
140 + RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
141 + RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
142 +
143 + bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
144 +
145 + if (!empty) {
146 + Base::os_->Put('\n');
147 + WriteIndent();
148 + }
149 + bool ret = Base::WriteEndObject();
150 + (void)ret;
151 + RAPIDJSON_ASSERT(ret == true);
152 + if (Base::level_stack_.Empty()) // end of json text
153 + Base::Flush();
154 + return true;
155 + }
156 +
157 + bool StartArray() {
158 + PrettyPrefix(kArrayType);
159 + new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
160 + return Base::WriteStartArray();
161 + }
162 +
163 + bool EndArray(SizeType memberCount = 0) {
164 + (void)memberCount;
165 + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
166 + RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
167 + bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
168 +
169 + if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
170 + Base::os_->Put('\n');
171 + WriteIndent();
172 + }
173 + bool ret = Base::WriteEndArray();
174 + (void)ret;
175 + RAPIDJSON_ASSERT(ret == true);
176 + if (Base::level_stack_.Empty()) // end of json text
177 + Base::Flush();
178 + return true;
179 + }
180 +
181 + //@}
182 +
183 + /*! @name Convenience extensions */
184 + //@{
185 +
186 + //! Simpler but slower overload.
187 + bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
188 + bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
189 +
190 + //@}
191 +
192 + //! Write a raw JSON value.
193 + /*!
194 + For user to write a stringified JSON as a value.
195 +
196 + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
197 + \param length Length of the json.
198 + \param type Type of the root of json.
199 + \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
200 + */
201 + bool RawValue(const Ch* json, size_t length, Type type) {
202 + RAPIDJSON_ASSERT(json != 0);
203 + PrettyPrefix(type);
204 + return Base::WriteRawValue(json, length);
205 + }
206 +
207 +protected:
208 + void PrettyPrefix(Type type) {
209 + (void)type;
210 + if (Base::level_stack_.GetSize() != 0) { // this value is not at root
211 + typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
212 +
213 + if (level->inArray) {
214 + if (level->valueCount > 0) {
215 + Base::os_->Put(','); // add comma if it is not the first element in array
216 + if (formatOptions_ & kFormatSingleLineArray)
217 + Base::os_->Put(' ');
218 + }
219 +
220 + if (!(formatOptions_ & kFormatSingleLineArray)) {
221 + Base::os_->Put('\n');
222 + WriteIndent();
223 + }
224 + }
225 + else { // in object
226 + if (level->valueCount > 0) {
227 + if (level->valueCount % 2 == 0) {
228 + Base::os_->Put(',');
229 + Base::os_->Put('\n');
230 + }
231 + else {
232 + Base::os_->Put(':');
233 + Base::os_->Put(' ');
234 + }
235 + }
236 + else
237 + Base::os_->Put('\n');
238 +
239 + if (level->valueCount % 2 == 0)
240 + WriteIndent();
241 + }
242 + if (!level->inArray && level->valueCount % 2 == 0)
243 + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
244 + level->valueCount++;
245 + }
246 + else {
247 + RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
248 + Base::hasRoot_ = true;
249 + }
250 + }
251 +
252 + void WriteIndent() {
253 + size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
254 + PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);
255 + }
256 +
257 + Ch indentChar_;
258 + unsigned indentCharCount_;
259 + PrettyFormatOptions formatOptions_;
260 +
261 +private:
262 + // Prohibit copy constructor & assignment operator.
263 + PrettyWriter(const PrettyWriter&);
264 + PrettyWriter& operator=(const PrettyWriter&);
265 +};
266 +
267 +RAPIDJSON_NAMESPACE_END
268 +
269 +#if defined(__clang__)
270 +RAPIDJSON_DIAG_POP
271 +#endif
272 +
273 +#ifdef __GNUC__
274 +RAPIDJSON_DIAG_POP
275 +#endif
276 +
277 +#endif // RAPIDJSON_RAPIDJSON_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_RAPIDJSON_H_
16 +#define RAPIDJSON_RAPIDJSON_H_
17 +
18 +/*!\file rapidjson.h
19 + \brief common definitions and configuration
20 +
21 + \see RAPIDJSON_CONFIG
22 + */
23 +
24 +/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
25 + \brief Configuration macros for library features
26 +
27 + Some RapidJSON features are configurable to adapt the library to a wide
28 + variety of platforms, environments and usage scenarios. Most of the
29 + features can be configured in terms of overriden or predefined
30 + preprocessor macros at compile-time.
31 +
32 + Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
33 +
34 + \note These macros should be given on the compiler command-line
35 + (where applicable) to avoid inconsistent values when compiling
36 + different translation units of a single application.
37 + */
38 +
39 +#include <cstdlib> // malloc(), realloc(), free(), size_t
40 +#include <cstring> // memset(), memcpy(), memmove(), memcmp()
41 +
42 +///////////////////////////////////////////////////////////////////////////////
43 +// RAPIDJSON_VERSION_STRING
44 +//
45 +// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
46 +//
47 +
48 +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
49 +// token stringification
50 +#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
51 +#define RAPIDJSON_DO_STRINGIFY(x) #x
52 +
53 +// token concatenation
54 +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
55 +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
56 +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
57 +//!@endcond
58 +
59 +/*! \def RAPIDJSON_MAJOR_VERSION
60 + \ingroup RAPIDJSON_CONFIG
61 + \brief Major version of RapidJSON in integer.
62 +*/
63 +/*! \def RAPIDJSON_MINOR_VERSION
64 + \ingroup RAPIDJSON_CONFIG
65 + \brief Minor version of RapidJSON in integer.
66 +*/
67 +/*! \def RAPIDJSON_PATCH_VERSION
68 + \ingroup RAPIDJSON_CONFIG
69 + \brief Patch version of RapidJSON in integer.
70 +*/
71 +/*! \def RAPIDJSON_VERSION_STRING
72 + \ingroup RAPIDJSON_CONFIG
73 + \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
74 +*/
75 +#define RAPIDJSON_MAJOR_VERSION 1
76 +#define RAPIDJSON_MINOR_VERSION 1
77 +#define RAPIDJSON_PATCH_VERSION 0
78 +#define RAPIDJSON_VERSION_STRING \
79 + RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
80 +
81 +///////////////////////////////////////////////////////////////////////////////
82 +// RAPIDJSON_NAMESPACE_(BEGIN|END)
83 +/*! \def RAPIDJSON_NAMESPACE
84 + \ingroup RAPIDJSON_CONFIG
85 + \brief provide custom rapidjson namespace
86 +
87 + In order to avoid symbol clashes and/or "One Definition Rule" errors
88 + between multiple inclusions of (different versions of) RapidJSON in
89 + a single binary, users can customize the name of the main RapidJSON
90 + namespace.
91 +
92 + In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
93 + to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
94 + levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
95 + RAPIDJSON_NAMESPACE_END need to be defined as well:
96 +
97 + \code
98 + // in some .cpp file
99 + #define RAPIDJSON_NAMESPACE my::rapidjson
100 + #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
101 + #define RAPIDJSON_NAMESPACE_END } }
102 + #include "rapidjson/..."
103 + \endcode
104 +
105 + \see rapidjson
106 + */
107 +/*! \def RAPIDJSON_NAMESPACE_BEGIN
108 + \ingroup RAPIDJSON_CONFIG
109 + \brief provide custom rapidjson namespace (opening expression)
110 + \see RAPIDJSON_NAMESPACE
111 +*/
112 +/*! \def RAPIDJSON_NAMESPACE_END
113 + \ingroup RAPIDJSON_CONFIG
114 + \brief provide custom rapidjson namespace (closing expression)
115 + \see RAPIDJSON_NAMESPACE
116 +*/
117 +#ifndef RAPIDJSON_NAMESPACE
118 +#define RAPIDJSON_NAMESPACE rapidjson
119 +#endif
120 +#ifndef RAPIDJSON_NAMESPACE_BEGIN
121 +#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
122 +#endif
123 +#ifndef RAPIDJSON_NAMESPACE_END
124 +#define RAPIDJSON_NAMESPACE_END }
125 +#endif
126 +
127 +///////////////////////////////////////////////////////////////////////////////
128 +// RAPIDJSON_HAS_STDSTRING
129 +
130 +#ifndef RAPIDJSON_HAS_STDSTRING
131 +#ifdef RAPIDJSON_DOXYGEN_RUNNING
132 +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
133 +#else
134 +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
135 +#endif
136 +/*! \def RAPIDJSON_HAS_STDSTRING
137 + \ingroup RAPIDJSON_CONFIG
138 + \brief Enable RapidJSON support for \c std::string
139 +
140 + By defining this preprocessor symbol to \c 1, several convenience functions for using
141 + \ref rapidjson::GenericValue with \c std::string are enabled, especially
142 + for construction and comparison.
143 +
144 + \hideinitializer
145 +*/
146 +#endif // !defined(RAPIDJSON_HAS_STDSTRING)
147 +
148 +#if RAPIDJSON_HAS_STDSTRING
149 +#include <string>
150 +#endif // RAPIDJSON_HAS_STDSTRING
151 +
152 +///////////////////////////////////////////////////////////////////////////////
153 +// RAPIDJSON_NO_INT64DEFINE
154 +
155 +/*! \def RAPIDJSON_NO_INT64DEFINE
156 + \ingroup RAPIDJSON_CONFIG
157 + \brief Use external 64-bit integer types.
158 +
159 + RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
160 + to be available at global scope.
161 +
162 + If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
163 + prevent RapidJSON from defining its own types.
164 +*/
165 +#ifndef RAPIDJSON_NO_INT64DEFINE
166 +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
167 +#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
168 +#include "msinttypes/stdint.h"
169 +#include "msinttypes/inttypes.h"
170 +#else
171 +// Other compilers should have this.
172 +#include <stdint.h>
173 +#include <inttypes.h>
174 +#endif
175 +//!@endcond
176 +#ifdef RAPIDJSON_DOXYGEN_RUNNING
177 +#define RAPIDJSON_NO_INT64DEFINE
178 +#endif
179 +#endif // RAPIDJSON_NO_INT64TYPEDEF
180 +
181 +///////////////////////////////////////////////////////////////////////////////
182 +// RAPIDJSON_FORCEINLINE
183 +
184 +#ifndef RAPIDJSON_FORCEINLINE
185 +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
186 +#if defined(_MSC_VER) && defined(NDEBUG)
187 +#define RAPIDJSON_FORCEINLINE __forceinline
188 +#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
189 +#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
190 +#else
191 +#define RAPIDJSON_FORCEINLINE
192 +#endif
193 +//!@endcond
194 +#endif // RAPIDJSON_FORCEINLINE
195 +
196 +///////////////////////////////////////////////////////////////////////////////
197 +// RAPIDJSON_ENDIAN
198 +#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
199 +#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
200 +
201 +//! Endianness of the machine.
202 +/*!
203 + \def RAPIDJSON_ENDIAN
204 + \ingroup RAPIDJSON_CONFIG
205 +
206 + GCC 4.6 provided macro for detecting endianness of the target machine. But other
207 + compilers may not have this. User can define RAPIDJSON_ENDIAN to either
208 + \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
209 +
210 + Default detection implemented with reference to
211 + \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
212 + \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
213 +*/
214 +#ifndef RAPIDJSON_ENDIAN
215 +// Detect with GCC 4.6's macro
216 +# ifdef __BYTE_ORDER__
217 +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
218 +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
219 +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
220 +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
221 +# else
222 +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
223 +# endif // __BYTE_ORDER__
224 +// Detect with GLIBC's endian.h
225 +# elif defined(__GLIBC__)
226 +# include <endian.h>
227 +# if (__BYTE_ORDER == __LITTLE_ENDIAN)
228 +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
229 +# elif (__BYTE_ORDER == __BIG_ENDIAN)
230 +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
231 +# else
232 +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
233 +# endif // __GLIBC__
234 +// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
235 +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
236 +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
237 +# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
238 +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
239 +// Detect with architecture macros
240 +# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
241 +# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
242 +# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
243 +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
244 +# elif defined(_MSC_VER) && defined(_M_ARM)
245 +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
246 +# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
247 +# define RAPIDJSON_ENDIAN
248 +# else
249 +# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
250 +# endif
251 +#endif // RAPIDJSON_ENDIAN
252 +
253 +///////////////////////////////////////////////////////////////////////////////
254 +// RAPIDJSON_64BIT
255 +
256 +//! Whether using 64-bit architecture
257 +#ifndef RAPIDJSON_64BIT
258 +#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)
259 +#define RAPIDJSON_64BIT 1
260 +#else
261 +#define RAPIDJSON_64BIT 0
262 +#endif
263 +#endif // RAPIDJSON_64BIT
264 +
265 +///////////////////////////////////////////////////////////////////////////////
266 +// RAPIDJSON_ALIGN
267 +
268 +//! Data alignment of the machine.
269 +/*! \ingroup RAPIDJSON_CONFIG
270 + \param x pointer to align
271 +
272 + Some machines require strict data alignment. Currently the default uses 4 bytes
273 + alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
274 + User can customize by defining the RAPIDJSON_ALIGN function macro.
275 +*/
276 +#ifndef RAPIDJSON_ALIGN
277 +#if RAPIDJSON_64BIT == 1
278 +#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
279 +#else
280 +#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
281 +#endif
282 +#endif
283 +
284 +///////////////////////////////////////////////////////////////////////////////
285 +// RAPIDJSON_UINT64_C2
286 +
287 +//! Construct a 64-bit literal by a pair of 32-bit integer.
288 +/*!
289 + 64-bit literal with or without ULL suffix is prone to compiler warnings.
290 + UINT64_C() is C macro which cause compilation problems.
291 + Use this macro to define 64-bit constants by a pair of 32-bit integer.
292 +*/
293 +#ifndef RAPIDJSON_UINT64_C2
294 +#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
295 +#endif
296 +
297 +///////////////////////////////////////////////////////////////////////////////
298 +// RAPIDJSON_48BITPOINTER_OPTIMIZATION
299 +
300 +//! Use only lower 48-bit address for some pointers.
301 +/*!
302 + \ingroup RAPIDJSON_CONFIG
303 +
304 + This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
305 + The higher 16-bit can be used for storing other data.
306 + \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
307 +*/
308 +#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
309 +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
310 +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
311 +#else
312 +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
313 +#endif
314 +#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
315 +
316 +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
317 +#if RAPIDJSON_64BIT != 1
318 +#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
319 +#endif
320 +#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
321 +#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
322 +#else
323 +#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
324 +#define RAPIDJSON_GETPOINTER(type, p) (p)
325 +#endif
326 +
327 +///////////////////////////////////////////////////////////////////////////////
328 +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD
329 +
330 +/*! \def RAPIDJSON_SIMD
331 + \ingroup RAPIDJSON_CONFIG
332 + \brief Enable SSE2/SSE4.2/Neon optimization.
333 +
334 + RapidJSON supports optimized implementations for some parsing operations
335 + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel
336 + or ARM compatible processors.
337 +
338 + To enable these optimizations, three different symbols can be defined;
339 + \code
340 + // Enable SSE2 optimization.
341 + #define RAPIDJSON_SSE2
342 +
343 + // Enable SSE4.2 optimization.
344 + #define RAPIDJSON_SSE42
345 + \endcode
346 +
347 + // Enable ARM Neon optimization.
348 + #define RAPIDJSON_NEON
349 + \endcode
350 +
351 + \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined.
352 +
353 + If any of these symbols is defined, RapidJSON defines the macro
354 + \c RAPIDJSON_SIMD to indicate the availability of the optimized code.
355 +*/
356 +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
357 + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING)
358 +#define RAPIDJSON_SIMD
359 +#endif
360 +
361 +///////////////////////////////////////////////////////////////////////////////
362 +// RAPIDJSON_NO_SIZETYPEDEFINE
363 +
364 +#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
365 +/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
366 + \ingroup RAPIDJSON_CONFIG
367 + \brief User-provided \c SizeType definition.
368 +
369 + In order to avoid using 32-bit size types for indexing strings and arrays,
370 + define this preprocessor symbol and provide the type rapidjson::SizeType
371 + before including RapidJSON:
372 + \code
373 + #define RAPIDJSON_NO_SIZETYPEDEFINE
374 + namespace rapidjson { typedef ::std::size_t SizeType; }
375 + #include "rapidjson/..."
376 + \endcode
377 +
378 + \see rapidjson::SizeType
379 +*/
380 +#ifdef RAPIDJSON_DOXYGEN_RUNNING
381 +#define RAPIDJSON_NO_SIZETYPEDEFINE
382 +#endif
383 +RAPIDJSON_NAMESPACE_BEGIN
384 +//! Size type (for string lengths, array sizes, etc.)
385 +/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
386 + instead of using \c size_t. Users may override the SizeType by defining
387 + \ref RAPIDJSON_NO_SIZETYPEDEFINE.
388 +*/
389 +typedef unsigned SizeType;
390 +RAPIDJSON_NAMESPACE_END
391 +#endif
392 +
393 +// always import std::size_t to rapidjson namespace
394 +RAPIDJSON_NAMESPACE_BEGIN
395 +using std::size_t;
396 +RAPIDJSON_NAMESPACE_END
397 +
398 +///////////////////////////////////////////////////////////////////////////////
399 +// RAPIDJSON_ASSERT
400 +
401 +//! Assertion.
402 +/*! \ingroup RAPIDJSON_CONFIG
403 + By default, rapidjson uses C \c assert() for internal assertions.
404 + User can override it by defining RAPIDJSON_ASSERT(x) macro.
405 +
406 + \note Parsing errors are handled and can be customized by the
407 + \ref RAPIDJSON_ERRORS APIs.
408 +*/
409 +#ifndef RAPIDJSON_ASSERT
410 +#include <cassert>
411 +#define RAPIDJSON_ASSERT(x) assert(x)
412 +#endif // RAPIDJSON_ASSERT
413 +
414 +///////////////////////////////////////////////////////////////////////////////
415 +// RAPIDJSON_STATIC_ASSERT
416 +
417 +// Prefer C++11 static_assert, if available
418 +#ifndef RAPIDJSON_STATIC_ASSERT
419 +#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
420 +#define RAPIDJSON_STATIC_ASSERT(x) \
421 + static_assert(x, RAPIDJSON_STRINGIFY(x))
422 +#endif // C++11
423 +#endif // RAPIDJSON_STATIC_ASSERT
424 +
425 +// Adopt C++03 implementation from boost
426 +#ifndef RAPIDJSON_STATIC_ASSERT
427 +#ifndef __clang__
428 +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
429 +#endif
430 +RAPIDJSON_NAMESPACE_BEGIN
431 +template <bool x> struct STATIC_ASSERTION_FAILURE;
432 +template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
433 +template <size_t x> struct StaticAssertTest {};
434 +RAPIDJSON_NAMESPACE_END
435 +
436 +#if defined(__GNUC__)
437 +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
438 +#else
439 +#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
440 +#endif
441 +#ifndef __clang__
442 +//!@endcond
443 +#endif
444 +
445 +/*! \def RAPIDJSON_STATIC_ASSERT
446 + \brief (Internal) macro to check for conditions at compile-time
447 + \param x compile-time condition
448 + \hideinitializer
449 + */
450 +#define RAPIDJSON_STATIC_ASSERT(x) \
451 + typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
452 + sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
453 + RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
454 +#endif // RAPIDJSON_STATIC_ASSERT
455 +
456 +///////////////////////////////////////////////////////////////////////////////
457 +// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
458 +
459 +//! Compiler branching hint for expression with high probability to be true.
460 +/*!
461 + \ingroup RAPIDJSON_CONFIG
462 + \param x Boolean expression likely to be true.
463 +*/
464 +#ifndef RAPIDJSON_LIKELY
465 +#if defined(__GNUC__) || defined(__clang__)
466 +#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
467 +#else
468 +#define RAPIDJSON_LIKELY(x) (x)
469 +#endif
470 +#endif
471 +
472 +//! Compiler branching hint for expression with low probability to be true.
473 +/*!
474 + \ingroup RAPIDJSON_CONFIG
475 + \param x Boolean expression unlikely to be true.
476 +*/
477 +#ifndef RAPIDJSON_UNLIKELY
478 +#if defined(__GNUC__) || defined(__clang__)
479 +#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
480 +#else
481 +#define RAPIDJSON_UNLIKELY(x) (x)
482 +#endif
483 +#endif
484 +
485 +///////////////////////////////////////////////////////////////////////////////
486 +// Helpers
487 +
488 +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
489 +
490 +#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
491 +#define RAPIDJSON_MULTILINEMACRO_END \
492 +} while((void)0, 0)
493 +
494 +// adopted from Boost
495 +#define RAPIDJSON_VERSION_CODE(x,y,z) \
496 + (((x)*100000) + ((y)*100) + (z))
497 +
498 +///////////////////////////////////////////////////////////////////////////////
499 +// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
500 +
501 +#if defined(__GNUC__)
502 +#define RAPIDJSON_GNUC \
503 + RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
504 +#endif
505 +
506 +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
507 +
508 +#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
509 +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
510 +#define RAPIDJSON_DIAG_OFF(x) \
511 + RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
512 +
513 +// push/pop support in Clang and GCC>=4.6
514 +#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
515 +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
516 +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
517 +#else // GCC >= 4.2, < 4.6
518 +#define RAPIDJSON_DIAG_PUSH /* ignored */
519 +#define RAPIDJSON_DIAG_POP /* ignored */
520 +#endif
521 +
522 +#elif defined(_MSC_VER)
523 +
524 +// pragma (MSVC specific)
525 +#define RAPIDJSON_PRAGMA(x) __pragma(x)
526 +#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
527 +
528 +#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
529 +#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
530 +#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
531 +
532 +#else
533 +
534 +#define RAPIDJSON_DIAG_OFF(x) /* ignored */
535 +#define RAPIDJSON_DIAG_PUSH /* ignored */
536 +#define RAPIDJSON_DIAG_POP /* ignored */
537 +
538 +#endif // RAPIDJSON_DIAG_*
539 +
540 +///////////////////////////////////////////////////////////////////////////////
541 +// C++11 features
542 +
543 +#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
544 +#if defined(__clang__)
545 +#if __has_feature(cxx_rvalue_references) && \
546 + (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
547 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
548 +#else
549 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
550 +#endif
551 +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
552 + (defined(_MSC_VER) && _MSC_VER >= 1600)
553 +
554 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
555 +#else
556 +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
557 +#endif
558 +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
559 +
560 +#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
561 +#if defined(__clang__)
562 +#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
563 +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
564 +// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
565 +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
566 +#else
567 +#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
568 +#endif
569 +#endif
570 +#if RAPIDJSON_HAS_CXX11_NOEXCEPT
571 +#define RAPIDJSON_NOEXCEPT noexcept
572 +#else
573 +#define RAPIDJSON_NOEXCEPT /* noexcept */
574 +#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
575 +
576 +// no automatic detection, yet
577 +#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
578 +#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
579 +#endif
580 +
581 +#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
582 +#if defined(__clang__)
583 +#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
584 +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
585 + (defined(_MSC_VER) && _MSC_VER >= 1700)
586 +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
587 +#else
588 +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
589 +#endif
590 +#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
591 +
592 +//!@endcond
593 +
594 +///////////////////////////////////////////////////////////////////////////////
595 +// new/delete
596 +
597 +#ifndef RAPIDJSON_NEW
598 +///! customization point for global \c new
599 +#define RAPIDJSON_NEW(TypeName) new TypeName
600 +#endif
601 +#ifndef RAPIDJSON_DELETE
602 +///! customization point for global \c delete
603 +#define RAPIDJSON_DELETE(x) delete x
604 +#endif
605 +
606 +///////////////////////////////////////////////////////////////////////////////
607 +// Type
608 +
609 +/*! \namespace rapidjson
610 + \brief main RapidJSON namespace
611 + \see RAPIDJSON_NAMESPACE
612 +*/
613 +RAPIDJSON_NAMESPACE_BEGIN
614 +
615 +//! Type of JSON value
616 +enum Type {
617 + kNullType = 0, //!< null
618 + kFalseType = 1, //!< false
619 + kTrueType = 2, //!< true
620 + kObjectType = 3, //!< object
621 + kArrayType = 4, //!< array
622 + kStringType = 5, //!< string
623 + kNumberType = 6 //!< number
624 +};
625 +
626 +RAPIDJSON_NAMESPACE_END
627 +
628 +#endif // RAPIDJSON_RAPIDJSON_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_READER_H_
16 +#define RAPIDJSON_READER_H_
17 +
18 +/*! \file reader.h */
19 +
20 +#include "allocators.h"
21 +#include "stream.h"
22 +#include "encodedstream.h"
23 +#include "internal/meta.h"
24 +#include "internal/stack.h"
25 +#include "internal/strtod.h"
26 +#include <limits>
27 +
28 +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
29 +#include <intrin.h>
30 +#pragma intrinsic(_BitScanForward)
31 +#endif
32 +#ifdef RAPIDJSON_SSE42
33 +#include <nmmintrin.h>
34 +#elif defined(RAPIDJSON_SSE2)
35 +#include <emmintrin.h>
36 +#elif defined(RAPIDJSON_NEON)
37 +#include <arm_neon.h>
38 +#endif
39 +
40 +#ifdef _MSC_VER
41 +RAPIDJSON_DIAG_PUSH
42 +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
43 +RAPIDJSON_DIAG_OFF(4702) // unreachable code
44 +#endif
45 +
46 +#ifdef __clang__
47 +RAPIDJSON_DIAG_PUSH
48 +RAPIDJSON_DIAG_OFF(old-style-cast)
49 +RAPIDJSON_DIAG_OFF(padded)
50 +RAPIDJSON_DIAG_OFF(switch-enum)
51 +#endif
52 +
53 +#ifdef __GNUC__
54 +RAPIDJSON_DIAG_PUSH
55 +RAPIDJSON_DIAG_OFF(effc++)
56 +#endif
57 +
58 +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
59 +#define RAPIDJSON_NOTHING /* deliberately empty */
60 +#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
61 +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
62 + RAPIDJSON_MULTILINEMACRO_BEGIN \
63 + if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
64 + RAPIDJSON_MULTILINEMACRO_END
65 +#endif
66 +#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
67 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
68 +//!@endcond
69 +
70 +/*! \def RAPIDJSON_PARSE_ERROR_NORETURN
71 + \ingroup RAPIDJSON_ERRORS
72 + \brief Macro to indicate a parse error.
73 + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
74 + \param offset position of the error in JSON input (\c size_t)
75 +
76 + This macros can be used as a customization point for the internal
77 + error handling mechanism of RapidJSON.
78 +
79 + A common usage model is to throw an exception instead of requiring the
80 + caller to explicitly check the \ref rapidjson::GenericReader::Parse's
81 + return value:
82 +
83 + \code
84 + #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \
85 + throw ParseException(parseErrorCode, #parseErrorCode, offset)
86 +
87 + #include <stdexcept> // std::runtime_error
88 + #include "rapidjson/error/error.h" // rapidjson::ParseResult
89 +
90 + struct ParseException : std::runtime_error, rapidjson::ParseResult {
91 + ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)
92 + : std::runtime_error(msg), ParseResult(code, offset) {}
93 + };
94 +
95 + #include "rapidjson/reader.h"
96 + \endcode
97 +
98 + \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse
99 + */
100 +#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
101 +#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
102 + RAPIDJSON_MULTILINEMACRO_BEGIN \
103 + RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
104 + SetParseError(parseErrorCode, offset); \
105 + RAPIDJSON_MULTILINEMACRO_END
106 +#endif
107 +
108 +/*! \def RAPIDJSON_PARSE_ERROR
109 + \ingroup RAPIDJSON_ERRORS
110 + \brief (Internal) macro to indicate and handle a parse error.
111 + \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
112 + \param offset position of the error in JSON input (\c size_t)
113 +
114 + Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.
115 +
116 + \see RAPIDJSON_PARSE_ERROR_NORETURN
117 + \hideinitializer
118 + */
119 +#ifndef RAPIDJSON_PARSE_ERROR
120 +#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
121 + RAPIDJSON_MULTILINEMACRO_BEGIN \
122 + RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
123 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
124 + RAPIDJSON_MULTILINEMACRO_END
125 +#endif
126 +
127 +#include "error/error.h" // ParseErrorCode, ParseResult
128 +
129 +RAPIDJSON_NAMESPACE_BEGIN
130 +
131 +///////////////////////////////////////////////////////////////////////////////
132 +// ParseFlag
133 +
134 +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
135 + \ingroup RAPIDJSON_CONFIG
136 + \brief User-defined kParseDefaultFlags definition.
137 +
138 + User can define this as any \c ParseFlag combinations.
139 +*/
140 +#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
141 +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
142 +#endif
143 +
144 +//! Combination of parseFlags
145 +/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
146 + */
147 +enum ParseFlag {
148 + kParseNoFlags = 0, //!< No flags are set.
149 + kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
150 + kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
151 + kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
152 + kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
153 + kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
154 + kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
155 + kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
156 + kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
157 + kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
158 + kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
159 +};
160 +
161 +///////////////////////////////////////////////////////////////////////////////
162 +// Handler
163 +
164 +/*! \class rapidjson::Handler
165 + \brief Concept for receiving events from GenericReader upon parsing.
166 + The functions return true if no error occurs. If they return false,
167 + the event publisher should terminate the process.
168 +\code
169 +concept Handler {
170 + typename Ch;
171 +
172 + bool Null();
173 + bool Bool(bool b);
174 + bool Int(int i);
175 + bool Uint(unsigned i);
176 + bool Int64(int64_t i);
177 + bool Uint64(uint64_t i);
178 + bool Double(double d);
179 + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
180 + bool RawNumber(const Ch* str, SizeType length, bool copy);
181 + bool String(const Ch* str, SizeType length, bool copy);
182 + bool StartObject();
183 + bool Key(const Ch* str, SizeType length, bool copy);
184 + bool EndObject(SizeType memberCount);
185 + bool StartArray();
186 + bool EndArray(SizeType elementCount);
187 +};
188 +\endcode
189 +*/
190 +///////////////////////////////////////////////////////////////////////////////
191 +// BaseReaderHandler
192 +
193 +//! Default implementation of Handler.
194 +/*! This can be used as base class of any reader handler.
195 + \note implements Handler concept
196 +*/
197 +template<typename Encoding = UTF8<>, typename Derived = void>
198 +struct BaseReaderHandler {
199 + typedef typename Encoding::Ch Ch;
200 +
201 + typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;
202 +
203 + bool Default() { return true; }
204 + bool Null() { return static_cast<Override&>(*this).Default(); }
205 + bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
206 + bool Int(int) { return static_cast<Override&>(*this).Default(); }
207 + bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
208 + bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
209 + bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
210 + bool Double(double) { return static_cast<Override&>(*this).Default(); }
211 + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
212 + bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
213 + bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
214 + bool StartObject() { return static_cast<Override&>(*this).Default(); }
215 + bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
216 + bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
217 + bool StartArray() { return static_cast<Override&>(*this).Default(); }
218 + bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
219 +};
220 +
221 +///////////////////////////////////////////////////////////////////////////////
222 +// StreamLocalCopy
223 +
224 +namespace internal {
225 +
226 +template<typename Stream, int = StreamTraits<Stream>::copyOptimization>
227 +class StreamLocalCopy;
228 +
229 +//! Do copy optimization.
230 +template<typename Stream>
231 +class StreamLocalCopy<Stream, 1> {
232 +public:
233 + StreamLocalCopy(Stream& original) : s(original), original_(original) {}
234 + ~StreamLocalCopy() { original_ = s; }
235 +
236 + Stream s;
237 +
238 +private:
239 + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
240 +
241 + Stream& original_;
242 +};
243 +
244 +//! Keep reference.
245 +template<typename Stream>
246 +class StreamLocalCopy<Stream, 0> {
247 +public:
248 + StreamLocalCopy(Stream& original) : s(original) {}
249 +
250 + Stream& s;
251 +
252 +private:
253 + StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
254 +};
255 +
256 +} // namespace internal
257 +
258 +///////////////////////////////////////////////////////////////////////////////
259 +// SkipWhitespace
260 +
261 +//! Skip the JSON white spaces in a stream.
262 +/*! \param is A input stream for skipping white spaces.
263 + \note This function has SSE2/SSE4.2 specialization.
264 +*/
265 +template<typename InputStream>
266 +void SkipWhitespace(InputStream& is) {
267 + internal::StreamLocalCopy<InputStream> copy(is);
268 + InputStream& s(copy.s);
269 +
270 + typename InputStream::Ch c;
271 + while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t')
272 + s.Take();
273 +}
274 +
275 +inline const char* SkipWhitespace(const char* p, const char* end) {
276 + while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
277 + ++p;
278 + return p;
279 +}
280 +
281 +#ifdef RAPIDJSON_SSE42
282 +//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
283 +inline const char *SkipWhitespace_SIMD(const char* p) {
284 + // Fast return for single non-whitespace
285 + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
286 + ++p;
287 + else
288 + return p;
289 +
290 + // 16-byte align to the next boundary
291 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
292 + while (p != nextAligned)
293 + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
294 + ++p;
295 + else
296 + return p;
297 +
298 + // The rest of string using SIMD
299 + static const char whitespace[16] = " \n\r\t";
300 + const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
301 +
302 + for (;; p += 16) {
303 + const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
304 + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
305 + if (r != 16) // some of characters is non-whitespace
306 + return p + r;
307 + }
308 +}
309 +
310 +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
311 + // Fast return for single non-whitespace
312 + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
313 + ++p;
314 + else
315 + return p;
316 +
317 + // The middle of string using SIMD
318 + static const char whitespace[16] = " \n\r\t";
319 + const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
320 +
321 + for (; p <= end - 16; p += 16) {
322 + const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
323 + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
324 + if (r != 16) // some of characters is non-whitespace
325 + return p + r;
326 + }
327 +
328 + return SkipWhitespace(p, end);
329 +}
330 +
331 +#elif defined(RAPIDJSON_SSE2)
332 +
333 +//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
334 +inline const char *SkipWhitespace_SIMD(const char* p) {
335 + // Fast return for single non-whitespace
336 + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
337 + ++p;
338 + else
339 + return p;
340 +
341 + // 16-byte align to the next boundary
342 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
343 + while (p != nextAligned)
344 + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
345 + ++p;
346 + else
347 + return p;
348 +
349 + // The rest of string
350 + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
351 + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
352 + #undef C16
353 +
354 + const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
355 + const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
356 + const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
357 + const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
358 +
359 + for (;; p += 16) {
360 + const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
361 + __m128i x = _mm_cmpeq_epi8(s, w0);
362 + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
363 + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
364 + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
365 + unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
366 + if (r != 0) { // some of characters may be non-whitespace
367 +#ifdef _MSC_VER // Find the index of first non-whitespace
368 + unsigned long offset;
369 + _BitScanForward(&offset, r);
370 + return p + offset;
371 +#else
372 + return p + __builtin_ffs(r) - 1;
373 +#endif
374 + }
375 + }
376 +}
377 +
378 +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
379 + // Fast return for single non-whitespace
380 + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
381 + ++p;
382 + else
383 + return p;
384 +
385 + // The rest of string
386 + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
387 + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
388 + #undef C16
389 +
390 + const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
391 + const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
392 + const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
393 + const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
394 +
395 + for (; p <= end - 16; p += 16) {
396 + const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
397 + __m128i x = _mm_cmpeq_epi8(s, w0);
398 + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
399 + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
400 + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
401 + unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
402 + if (r != 0) { // some of characters may be non-whitespace
403 +#ifdef _MSC_VER // Find the index of first non-whitespace
404 + unsigned long offset;
405 + _BitScanForward(&offset, r);
406 + return p + offset;
407 +#else
408 + return p + __builtin_ffs(r) - 1;
409 +#endif
410 + }
411 + }
412 +
413 + return SkipWhitespace(p, end);
414 +}
415 +
416 +#elif defined(RAPIDJSON_NEON)
417 +
418 +//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once.
419 +inline const char *SkipWhitespace_SIMD(const char* p) {
420 + // Fast return for single non-whitespace
421 + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
422 + ++p;
423 + else
424 + return p;
425 +
426 + // 16-byte align to the next boundary
427 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
428 + while (p != nextAligned)
429 + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
430 + ++p;
431 + else
432 + return p;
433 +
434 + const uint8x16_t w0 = vmovq_n_u8(' ');
435 + const uint8x16_t w1 = vmovq_n_u8('\n');
436 + const uint8x16_t w2 = vmovq_n_u8('\r');
437 + const uint8x16_t w3 = vmovq_n_u8('\t');
438 +
439 + for (;; p += 16) {
440 + const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
441 + uint8x16_t x = vceqq_u8(s, w0);
442 + x = vorrq_u8(x, vceqq_u8(s, w1));
443 + x = vorrq_u8(x, vceqq_u8(s, w2));
444 + x = vorrq_u8(x, vceqq_u8(s, w3));
445 +
446 + x = vmvnq_u8(x); // Negate
447 + x = vrev64q_u8(x); // Rev in 64
448 + uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
449 + uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
450 +
451 + if (low == 0) {
452 + if (high != 0) {
453 + int lz =__builtin_clzll(high);;
454 + return p + 8 + (lz >> 3);
455 + }
456 + } else {
457 + int lz = __builtin_clzll(low);;
458 + return p + (lz >> 3);
459 + }
460 + }
461 +}
462 +
463 +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
464 + // Fast return for single non-whitespace
465 + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
466 + ++p;
467 + else
468 + return p;
469 +
470 + const uint8x16_t w0 = vmovq_n_u8(' ');
471 + const uint8x16_t w1 = vmovq_n_u8('\n');
472 + const uint8x16_t w2 = vmovq_n_u8('\r');
473 + const uint8x16_t w3 = vmovq_n_u8('\t');
474 +
475 + for (; p <= end - 16; p += 16) {
476 + const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
477 + uint8x16_t x = vceqq_u8(s, w0);
478 + x = vorrq_u8(x, vceqq_u8(s, w1));
479 + x = vorrq_u8(x, vceqq_u8(s, w2));
480 + x = vorrq_u8(x, vceqq_u8(s, w3));
481 +
482 + x = vmvnq_u8(x); // Negate
483 + x = vrev64q_u8(x); // Rev in 64
484 + uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
485 + uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
486 +
487 + if (low == 0) {
488 + if (high != 0) {
489 + int lz = __builtin_clzll(high);
490 + return p + 8 + (lz >> 3);
491 + }
492 + } else {
493 + int lz = __builtin_clzll(low);
494 + return p + (lz >> 3);
495 + }
496 + }
497 +
498 + return SkipWhitespace(p, end);
499 +}
500 +
501 +#endif // RAPIDJSON_NEON
502 +
503 +#ifdef RAPIDJSON_SIMD
504 +//! Template function specialization for InsituStringStream
505 +template<> inline void SkipWhitespace(InsituStringStream& is) {
506 + is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
507 +}
508 +
509 +//! Template function specialization for StringStream
510 +template<> inline void SkipWhitespace(StringStream& is) {
511 + is.src_ = SkipWhitespace_SIMD(is.src_);
512 +}
513 +
514 +template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {
515 + is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
516 +}
517 +#endif // RAPIDJSON_SIMD
518 +
519 +///////////////////////////////////////////////////////////////////////////////
520 +// GenericReader
521 +
522 +//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
523 +/*! GenericReader parses JSON text from a stream, and send events synchronously to an
524 + object implementing Handler concept.
525 +
526 + It needs to allocate a stack for storing a single decoded string during
527 + non-destructive parsing.
528 +
529 + For in-situ parsing, the decoded string is directly written to the source
530 + text string, no temporary buffer is required.
531 +
532 + A GenericReader object can be reused for parsing multiple JSON text.
533 +
534 + \tparam SourceEncoding Encoding of the input stream.
535 + \tparam TargetEncoding Encoding of the parse output.
536 + \tparam StackAllocator Allocator type for stack.
537 +*/
538 +template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>
539 +class GenericReader {
540 +public:
541 + typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
542 +
543 + //! Constructor.
544 + /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
545 + \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
546 + */
547 + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
548 +
549 + //! Parse JSON text.
550 + /*! \tparam parseFlags Combination of \ref ParseFlag.
551 + \tparam InputStream Type of input stream, implementing Stream concept.
552 + \tparam Handler Type of handler, implementing Handler concept.
553 + \param is Input stream to be parsed.
554 + \param handler The handler to receive events.
555 + \return Whether the parsing is successful.
556 + */
557 + template <unsigned parseFlags, typename InputStream, typename Handler>
558 + ParseResult Parse(InputStream& is, Handler& handler) {
559 + if (parseFlags & kParseIterativeFlag)
560 + return IterativeParse<parseFlags>(is, handler);
561 +
562 + parseResult_.Clear();
563 +
564 + ClearStackOnExit scope(*this);
565 +
566 + SkipWhitespaceAndComments<parseFlags>(is);
567 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
568 +
569 + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
570 + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
571 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
572 + }
573 + else {
574 + ParseValue<parseFlags>(is, handler);
575 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
576 +
577 + if (!(parseFlags & kParseStopWhenDoneFlag)) {
578 + SkipWhitespaceAndComments<parseFlags>(is);
579 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
580 +
581 + if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
582 + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
583 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
584 + }
585 + }
586 + }
587 +
588 + return parseResult_;
589 + }
590 +
591 + //! Parse JSON text (with \ref kParseDefaultFlags)
592 + /*! \tparam InputStream Type of input stream, implementing Stream concept
593 + \tparam Handler Type of handler, implementing Handler concept.
594 + \param is Input stream to be parsed.
595 + \param handler The handler to receive events.
596 + \return Whether the parsing is successful.
597 + */
598 + template <typename InputStream, typename Handler>
599 + ParseResult Parse(InputStream& is, Handler& handler) {
600 + return Parse<kParseDefaultFlags>(is, handler);
601 + }
602 +
603 + //! Initialize JSON text token-by-token parsing
604 + /*!
605 + */
606 + void IterativeParseInit() {
607 + parseResult_.Clear();
608 + state_ = IterativeParsingStartState;
609 + }
610 +
611 + //! Parse one token from JSON text
612 + /*! \tparam InputStream Type of input stream, implementing Stream concept
613 + \tparam Handler Type of handler, implementing Handler concept.
614 + \param is Input stream to be parsed.
615 + \param handler The handler to receive events.
616 + \return Whether the parsing is successful.
617 + */
618 + template <unsigned parseFlags, typename InputStream, typename Handler>
619 + bool IterativeParseNext(InputStream& is, Handler& handler) {
620 + while (RAPIDJSON_LIKELY(is.Peek() != '\0')) {
621 + SkipWhitespaceAndComments<parseFlags>(is);
622 +
623 + Token t = Tokenize(is.Peek());
624 + IterativeParsingState n = Predict(state_, t);
625 + IterativeParsingState d = Transit<parseFlags>(state_, t, n, is, handler);
626 +
627 + // If we've finished or hit an error...
628 + if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) {
629 + // Report errors.
630 + if (d == IterativeParsingErrorState) {
631 + HandleError(state_, is);
632 + return false;
633 + }
634 +
635 + // Transition to the finish state.
636 + RAPIDJSON_ASSERT(d == IterativeParsingFinishState);
637 + state_ = d;
638 +
639 + // If StopWhenDone is not set...
640 + if (!(parseFlags & kParseStopWhenDoneFlag)) {
641 + // ... and extra non-whitespace data is found...
642 + SkipWhitespaceAndComments<parseFlags>(is);
643 + if (is.Peek() != '\0') {
644 + // ... this is considered an error.
645 + HandleError(state_, is);
646 + return false;
647 + }
648 + }
649 +
650 + // Success! We are done!
651 + return true;
652 + }
653 +
654 + // Transition to the new state.
655 + state_ = d;
656 +
657 + // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now.
658 + if (!IsIterativeParsingDelimiterState(n))
659 + return true;
660 + }
661 +
662 + // We reached the end of file.
663 + stack_.Clear();
664 +
665 + if (state_ != IterativeParsingFinishState) {
666 + HandleError(state_, is);
667 + return false;
668 + }
669 +
670 + return true;
671 + }
672 +
673 + //! Check if token-by-token parsing JSON text is complete
674 + /*! \return Whether the JSON has been fully decoded.
675 + */
676 + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() {
677 + return IsIterativeParsingCompleteState(state_);
678 + }
679 +
680 + //! Whether a parse error has occured in the last parsing.
681 + bool HasParseError() const { return parseResult_.IsError(); }
682 +
683 + //! Get the \ref ParseErrorCode of last parsing.
684 + ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
685 +
686 + //! Get the position of last parsing error in input, 0 otherwise.
687 + size_t GetErrorOffset() const { return parseResult_.Offset(); }
688 +
689 +protected:
690 + void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }
691 +
692 +private:
693 + // Prohibit copy constructor & assignment operator.
694 + GenericReader(const GenericReader&);
695 + GenericReader& operator=(const GenericReader&);
696 +
697 + void ClearStack() { stack_.Clear(); }
698 +
699 + // clear stack on any exit from ParseStream, e.g. due to exception
700 + struct ClearStackOnExit {
701 + explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
702 + ~ClearStackOnExit() { r_.ClearStack(); }
703 + private:
704 + GenericReader& r_;
705 + ClearStackOnExit(const ClearStackOnExit&);
706 + ClearStackOnExit& operator=(const ClearStackOnExit&);
707 + };
708 +
709 + template<unsigned parseFlags, typename InputStream>
710 + void SkipWhitespaceAndComments(InputStream& is) {
711 + SkipWhitespace(is);
712 +
713 + if (parseFlags & kParseCommentsFlag) {
714 + while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
715 + if (Consume(is, '*')) {
716 + while (true) {
717 + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
718 + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
719 + else if (Consume(is, '*')) {
720 + if (Consume(is, '/'))
721 + break;
722 + }
723 + else
724 + is.Take();
725 + }
726 + }
727 + else if (RAPIDJSON_LIKELY(Consume(is, '/')))
728 + while (is.Peek() != '\0' && is.Take() != '\n') {}
729 + else
730 + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
731 +
732 + SkipWhitespace(is);
733 + }
734 + }
735 + }
736 +
737 + // Parse object: { string : value, ... }
738 + template<unsigned parseFlags, typename InputStream, typename Handler>
739 + void ParseObject(InputStream& is, Handler& handler) {
740 + RAPIDJSON_ASSERT(is.Peek() == '{');
741 + is.Take(); // Skip '{'
742 +
743 + if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
744 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
745 +
746 + SkipWhitespaceAndComments<parseFlags>(is);
747 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
748 +
749 + if (Consume(is, '}')) {
750 + if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
751 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
752 + return;
753 + }
754 +
755 + for (SizeType memberCount = 0;;) {
756 + if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
757 + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
758 +
759 + ParseString<parseFlags>(is, handler, true);
760 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
761 +
762 + SkipWhitespaceAndComments<parseFlags>(is);
763 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
764 +
765 + if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
766 + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
767 +
768 + SkipWhitespaceAndComments<parseFlags>(is);
769 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
770 +
771 + ParseValue<parseFlags>(is, handler);
772 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
773 +
774 + SkipWhitespaceAndComments<parseFlags>(is);
775 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
776 +
777 + ++memberCount;
778 +
779 + switch (is.Peek()) {
780 + case ',':
781 + is.Take();
782 + SkipWhitespaceAndComments<parseFlags>(is);
783 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
784 + break;
785 + case '}':
786 + is.Take();
787 + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
788 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
789 + return;
790 + default:
791 + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy
792 + }
793 +
794 + if (parseFlags & kParseTrailingCommasFlag) {
795 + if (is.Peek() == '}') {
796 + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
797 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
798 + is.Take();
799 + return;
800 + }
801 + }
802 + }
803 + }
804 +
805 + // Parse array: [ value, ... ]
806 + template<unsigned parseFlags, typename InputStream, typename Handler>
807 + void ParseArray(InputStream& is, Handler& handler) {
808 + RAPIDJSON_ASSERT(is.Peek() == '[');
809 + is.Take(); // Skip '['
810 +
811 + if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
812 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
813 +
814 + SkipWhitespaceAndComments<parseFlags>(is);
815 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
816 +
817 + if (Consume(is, ']')) {
818 + if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
819 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
820 + return;
821 + }
822 +
823 + for (SizeType elementCount = 0;;) {
824 + ParseValue<parseFlags>(is, handler);
825 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
826 +
827 + ++elementCount;
828 + SkipWhitespaceAndComments<parseFlags>(is);
829 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
830 +
831 + if (Consume(is, ',')) {
832 + SkipWhitespaceAndComments<parseFlags>(is);
833 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
834 + }
835 + else if (Consume(is, ']')) {
836 + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
837 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
838 + return;
839 + }
840 + else
841 + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
842 +
843 + if (parseFlags & kParseTrailingCommasFlag) {
844 + if (is.Peek() == ']') {
845 + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
846 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
847 + is.Take();
848 + return;
849 + }
850 + }
851 + }
852 + }
853 +
854 + template<unsigned parseFlags, typename InputStream, typename Handler>
855 + void ParseNull(InputStream& is, Handler& handler) {
856 + RAPIDJSON_ASSERT(is.Peek() == 'n');
857 + is.Take();
858 +
859 + if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {
860 + if (RAPIDJSON_UNLIKELY(!handler.Null()))
861 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
862 + }
863 + else
864 + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
865 + }
866 +
867 + template<unsigned parseFlags, typename InputStream, typename Handler>
868 + void ParseTrue(InputStream& is, Handler& handler) {
869 + RAPIDJSON_ASSERT(is.Peek() == 't');
870 + is.Take();
871 +
872 + if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {
873 + if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
874 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
875 + }
876 + else
877 + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
878 + }
879 +
880 + template<unsigned parseFlags, typename InputStream, typename Handler>
881 + void ParseFalse(InputStream& is, Handler& handler) {
882 + RAPIDJSON_ASSERT(is.Peek() == 'f');
883 + is.Take();
884 +
885 + if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {
886 + if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
887 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
888 + }
889 + else
890 + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
891 + }
892 +
893 + template<typename InputStream>
894 + RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {
895 + if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
896 + is.Take();
897 + return true;
898 + }
899 + else
900 + return false;
901 + }
902 +
903 + // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
904 + template<typename InputStream>
905 + unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
906 + unsigned codepoint = 0;
907 + for (int i = 0; i < 4; i++) {
908 + Ch c = is.Peek();
909 + codepoint <<= 4;
910 + codepoint += static_cast<unsigned>(c);
911 + if (c >= '0' && c <= '9')
912 + codepoint -= '0';
913 + else if (c >= 'A' && c <= 'F')
914 + codepoint -= 'A' - 10;
915 + else if (c >= 'a' && c <= 'f')
916 + codepoint -= 'a' - 10;
917 + else {
918 + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);
919 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
920 + }
921 + is.Take();
922 + }
923 + return codepoint;
924 + }
925 +
926 + template <typename CharType>
927 + class StackStream {
928 + public:
929 + typedef CharType Ch;
930 +
931 + StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}
932 + RAPIDJSON_FORCEINLINE void Put(Ch c) {
933 + *stack_.template Push<Ch>() = c;
934 + ++length_;
935 + }
936 +
937 + RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
938 + length_ += count;
939 + return stack_.template Push<Ch>(count);
940 + }
941 +
942 + size_t Length() const { return length_; }
943 +
944 + Ch* Pop() {
945 + return stack_.template Pop<Ch>(length_);
946 + }
947 +
948 + private:
949 + StackStream(const StackStream&);
950 + StackStream& operator=(const StackStream&);
951 +
952 + internal::Stack<StackAllocator>& stack_;
953 + SizeType length_;
954 + };
955 +
956 + // Parse string and generate String event. Different code paths for kParseInsituFlag.
957 + template<unsigned parseFlags, typename InputStream, typename Handler>
958 + void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
959 + internal::StreamLocalCopy<InputStream> copy(is);
960 + InputStream& s(copy.s);
961 +
962 + RAPIDJSON_ASSERT(s.Peek() == '\"');
963 + s.Take(); // Skip '\"'
964 +
965 + bool success = false;
966 + if (parseFlags & kParseInsituFlag) {
967 + typename InputStream::Ch *head = s.PutBegin();
968 + ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
969 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
970 + size_t length = s.PutEnd(head) - 1;
971 + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
972 + const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
973 + success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
974 + }
975 + else {
976 + StackStream<typename TargetEncoding::Ch> stackStream(stack_);
977 + ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
978 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
979 + SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
980 + const typename TargetEncoding::Ch* const str = stackStream.Pop();
981 + success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
982 + }
983 + if (RAPIDJSON_UNLIKELY(!success))
984 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
985 + }
986 +
987 + // Parse string to an output is
988 + // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
989 + template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
990 + RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
991 +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
992 +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
993 + static const char escape[256] = {
994 + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
995 + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
996 + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
997 + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
998 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
999 + };
1000 +#undef Z16
1001 +//!@endcond
1002 +
1003 + for (;;) {
1004 + // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
1005 + if (!(parseFlags & kParseValidateEncodingFlag))
1006 + ScanCopyUnescapedString(is, os);
1007 +
1008 + Ch c = is.Peek();
1009 + if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
1010 + size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
1011 + is.Take();
1012 + Ch e = is.Peek();
1013 + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
1014 + is.Take();
1015 + os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
1016 + }
1017 + else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
1018 + is.Take();
1019 + unsigned codepoint = ParseHex4(is, escapeOffset);
1020 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
1021 + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
1022 + // Handle UTF-16 surrogate pair
1023 + if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
1024 + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
1025 + unsigned codepoint2 = ParseHex4(is, escapeOffset);
1026 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
1027 + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
1028 + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
1029 + codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
1030 + }
1031 + TEncoding::Encode(os, codepoint);
1032 + }
1033 + else
1034 + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
1035 + }
1036 + else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
1037 + is.Take();
1038 + os.Put('\0'); // null-terminate the string
1039 + return;
1040 + }
1041 + else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
1042 + if (c == '\0')
1043 + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
1044 + else
1045 + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
1046 + }
1047 + else {
1048 + size_t offset = is.Tell();
1049 + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
1050 + !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
1051 + !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
1052 + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
1053 + }
1054 + }
1055 + }
1056 +
1057 + template<typename InputStream, typename OutputStream>
1058 + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {
1059 + // Do nothing for generic version
1060 + }
1061 +
1062 +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
1063 + // StringStream -> StackStream<char>
1064 + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
1065 + const char* p = is.src_;
1066 +
1067 + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1068 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1069 + while (p != nextAligned)
1070 + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1071 + is.src_ = p;
1072 + return;
1073 + }
1074 + else
1075 + os.Put(*p++);
1076 +
1077 + // The rest of string using SIMD
1078 + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
1079 + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
1080 + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
1081 + const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
1082 + const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
1083 + const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
1084 +
1085 + for (;; p += 16) {
1086 + const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
1087 + const __m128i t1 = _mm_cmpeq_epi8(s, dq);
1088 + const __m128i t2 = _mm_cmpeq_epi8(s, bs);
1089 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
1090 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
1091 + unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
1092 + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
1093 + SizeType length;
1094 + #ifdef _MSC_VER // Find the index of first escaped
1095 + unsigned long offset;
1096 + _BitScanForward(&offset, r);
1097 + length = offset;
1098 + #else
1099 + length = static_cast<SizeType>(__builtin_ffs(r) - 1);
1100 + #endif
1101 + if (length != 0) {
1102 + char* q = reinterpret_cast<char*>(os.Push(length));
1103 + for (size_t i = 0; i < length; i++)
1104 + q[i] = p[i];
1105 +
1106 + p += length;
1107 + }
1108 + break;
1109 + }
1110 + _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
1111 + }
1112 +
1113 + is.src_ = p;
1114 + }
1115 +
1116 + // InsituStringStream -> InsituStringStream
1117 + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
1118 + RAPIDJSON_ASSERT(&is == &os);
1119 + (void)os;
1120 +
1121 + if (is.src_ == is.dst_) {
1122 + SkipUnescapedString(is);
1123 + return;
1124 + }
1125 +
1126 + char* p = is.src_;
1127 + char *q = is.dst_;
1128 +
1129 + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1130 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1131 + while (p != nextAligned)
1132 + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1133 + is.src_ = p;
1134 + is.dst_ = q;
1135 + return;
1136 + }
1137 + else
1138 + *q++ = *p++;
1139 +
1140 + // The rest of string using SIMD
1141 + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
1142 + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
1143 + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
1144 + const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
1145 + const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
1146 + const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
1147 +
1148 + for (;; p += 16, q += 16) {
1149 + const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
1150 + const __m128i t1 = _mm_cmpeq_epi8(s, dq);
1151 + const __m128i t2 = _mm_cmpeq_epi8(s, bs);
1152 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
1153 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
1154 + unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
1155 + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
1156 + size_t length;
1157 +#ifdef _MSC_VER // Find the index of first escaped
1158 + unsigned long offset;
1159 + _BitScanForward(&offset, r);
1160 + length = offset;
1161 +#else
1162 + length = static_cast<size_t>(__builtin_ffs(r) - 1);
1163 +#endif
1164 + for (const char* pend = p + length; p != pend; )
1165 + *q++ = *p++;
1166 + break;
1167 + }
1168 + _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);
1169 + }
1170 +
1171 + is.src_ = p;
1172 + is.dst_ = q;
1173 + }
1174 +
1175 + // When read/write pointers are the same for insitu stream, just skip unescaped characters
1176 + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
1177 + RAPIDJSON_ASSERT(is.src_ == is.dst_);
1178 + char* p = is.src_;
1179 +
1180 + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1181 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1182 + for (; p != nextAligned; p++)
1183 + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1184 + is.src_ = is.dst_ = p;
1185 + return;
1186 + }
1187 +
1188 + // The rest of string using SIMD
1189 + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
1190 + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
1191 + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
1192 + const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
1193 + const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
1194 + const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
1195 +
1196 + for (;; p += 16) {
1197 + const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
1198 + const __m128i t1 = _mm_cmpeq_epi8(s, dq);
1199 + const __m128i t2 = _mm_cmpeq_epi8(s, bs);
1200 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
1201 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
1202 + unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
1203 + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
1204 + size_t length;
1205 +#ifdef _MSC_VER // Find the index of first escaped
1206 + unsigned long offset;
1207 + _BitScanForward(&offset, r);
1208 + length = offset;
1209 +#else
1210 + length = static_cast<size_t>(__builtin_ffs(r) - 1);
1211 +#endif
1212 + p += length;
1213 + break;
1214 + }
1215 + }
1216 +
1217 + is.src_ = is.dst_ = p;
1218 + }
1219 +#elif defined(RAPIDJSON_NEON)
1220 + // StringStream -> StackStream<char>
1221 + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
1222 + const char* p = is.src_;
1223 +
1224 + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1225 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1226 + while (p != nextAligned)
1227 + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1228 + is.src_ = p;
1229 + return;
1230 + }
1231 + else
1232 + os.Put(*p++);
1233 +
1234 + // The rest of string using SIMD
1235 + const uint8x16_t s0 = vmovq_n_u8('"');
1236 + const uint8x16_t s1 = vmovq_n_u8('\\');
1237 + const uint8x16_t s2 = vmovq_n_u8('\b');
1238 + const uint8x16_t s3 = vmovq_n_u8(32);
1239 +
1240 + for (;; p += 16) {
1241 + const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
1242 + uint8x16_t x = vceqq_u8(s, s0);
1243 + x = vorrq_u8(x, vceqq_u8(s, s1));
1244 + x = vorrq_u8(x, vceqq_u8(s, s2));
1245 + x = vorrq_u8(x, vcltq_u8(s, s3));
1246 +
1247 + x = vrev64q_u8(x); // Rev in 64
1248 + uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
1249 + uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
1250 +
1251 + SizeType length = 0;
1252 + bool escaped = false;
1253 + if (low == 0) {
1254 + if (high != 0) {
1255 + unsigned lz = (unsigned)__builtin_clzll(high);;
1256 + length = 8 + (lz >> 3);
1257 + escaped = true;
1258 + }
1259 + } else {
1260 + unsigned lz = (unsigned)__builtin_clzll(low);;
1261 + length = lz >> 3;
1262 + escaped = true;
1263 + }
1264 + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
1265 + if (length != 0) {
1266 + char* q = reinterpret_cast<char*>(os.Push(length));
1267 + for (size_t i = 0; i < length; i++)
1268 + q[i] = p[i];
1269 +
1270 + p += length;
1271 + }
1272 + break;
1273 + }
1274 + vst1q_u8(reinterpret_cast<uint8_t *>(os.Push(16)), s);
1275 + }
1276 +
1277 + is.src_ = p;
1278 + }
1279 +
1280 + // InsituStringStream -> InsituStringStream
1281 + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
1282 + RAPIDJSON_ASSERT(&is == &os);
1283 + (void)os;
1284 +
1285 + if (is.src_ == is.dst_) {
1286 + SkipUnescapedString(is);
1287 + return;
1288 + }
1289 +
1290 + char* p = is.src_;
1291 + char *q = is.dst_;
1292 +
1293 + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1294 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1295 + while (p != nextAligned)
1296 + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1297 + is.src_ = p;
1298 + is.dst_ = q;
1299 + return;
1300 + }
1301 + else
1302 + *q++ = *p++;
1303 +
1304 + // The rest of string using SIMD
1305 + const uint8x16_t s0 = vmovq_n_u8('"');
1306 + const uint8x16_t s1 = vmovq_n_u8('\\');
1307 + const uint8x16_t s2 = vmovq_n_u8('\b');
1308 + const uint8x16_t s3 = vmovq_n_u8(32);
1309 +
1310 + for (;; p += 16, q += 16) {
1311 + const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p));
1312 + uint8x16_t x = vceqq_u8(s, s0);
1313 + x = vorrq_u8(x, vceqq_u8(s, s1));
1314 + x = vorrq_u8(x, vceqq_u8(s, s2));
1315 + x = vorrq_u8(x, vcltq_u8(s, s3));
1316 +
1317 + x = vrev64q_u8(x); // Rev in 64
1318 + uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
1319 + uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
1320 +
1321 + SizeType length = 0;
1322 + bool escaped = false;
1323 + if (low == 0) {
1324 + if (high != 0) {
1325 + unsigned lz = (unsigned)__builtin_clzll(high);
1326 + length = 8 + (lz >> 3);
1327 + escaped = true;
1328 + }
1329 + } else {
1330 + unsigned lz = (unsigned)__builtin_clzll(low);
1331 + length = lz >> 3;
1332 + escaped = true;
1333 + }
1334 + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
1335 + for (const char* pend = p + length; p != pend; ) {
1336 + *q++ = *p++;
1337 + }
1338 + break;
1339 + }
1340 + vst1q_u8(reinterpret_cast<uint8_t *>(q), s);
1341 + }
1342 +
1343 + is.src_ = p;
1344 + is.dst_ = q;
1345 + }
1346 +
1347 + // When read/write pointers are the same for insitu stream, just skip unescaped characters
1348 + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
1349 + RAPIDJSON_ASSERT(is.src_ == is.dst_);
1350 + char* p = is.src_;
1351 +
1352 + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1353 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1354 + for (; p != nextAligned; p++)
1355 + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1356 + is.src_ = is.dst_ = p;
1357 + return;
1358 + }
1359 +
1360 + // The rest of string using SIMD
1361 + const uint8x16_t s0 = vmovq_n_u8('"');
1362 + const uint8x16_t s1 = vmovq_n_u8('\\');
1363 + const uint8x16_t s2 = vmovq_n_u8('\b');
1364 + const uint8x16_t s3 = vmovq_n_u8(32);
1365 +
1366 + for (;; p += 16) {
1367 + const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p));
1368 + uint8x16_t x = vceqq_u8(s, s0);
1369 + x = vorrq_u8(x, vceqq_u8(s, s1));
1370 + x = vorrq_u8(x, vceqq_u8(s, s2));
1371 + x = vorrq_u8(x, vcltq_u8(s, s3));
1372 +
1373 + x = vrev64q_u8(x); // Rev in 64
1374 + uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
1375 + uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
1376 +
1377 + if (low == 0) {
1378 + if (high != 0) {
1379 + int lz = __builtin_clzll(high);
1380 + p += 8 + (lz >> 3);
1381 + break;
1382 + }
1383 + } else {
1384 + int lz = __builtin_clzll(low);
1385 + p += lz >> 3;
1386 + break;
1387 + }
1388 + }
1389 +
1390 + is.src_ = is.dst_ = p;
1391 + }
1392 +#endif // RAPIDJSON_NEON
1393 +
1394 + template<typename InputStream, bool backup, bool pushOnTake>
1395 + class NumberStream;
1396 +
1397 + template<typename InputStream>
1398 + class NumberStream<InputStream, false, false> {
1399 + public:
1400 + typedef typename InputStream::Ch Ch;
1401 +
1402 + NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
1403 +
1404 + RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
1405 + RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
1406 + RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
1407 + RAPIDJSON_FORCEINLINE void Push(char) {}
1408 +
1409 + size_t Tell() { return is.Tell(); }
1410 + size_t Length() { return 0; }
1411 + const char* Pop() { return 0; }
1412 +
1413 + protected:
1414 + NumberStream& operator=(const NumberStream&);
1415 +
1416 + InputStream& is;
1417 + };
1418 +
1419 + template<typename InputStream>
1420 + class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
1421 + typedef NumberStream<InputStream, false, false> Base;
1422 + public:
1423 + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
1424 +
1425 + RAPIDJSON_FORCEINLINE Ch TakePush() {
1426 + stackStream.Put(static_cast<char>(Base::is.Peek()));
1427 + return Base::is.Take();
1428 + }
1429 +
1430 + RAPIDJSON_FORCEINLINE void Push(char c) {
1431 + stackStream.Put(c);
1432 + }
1433 +
1434 + size_t Length() { return stackStream.Length(); }
1435 +
1436 + const char* Pop() {
1437 + stackStream.Put('\0');
1438 + return stackStream.Pop();
1439 + }
1440 +
1441 + private:
1442 + StackStream<char> stackStream;
1443 + };
1444 +
1445 + template<typename InputStream>
1446 + class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
1447 + typedef NumberStream<InputStream, true, false> Base;
1448 + public:
1449 + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
1450 +
1451 + RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
1452 + };
1453 +
1454 + template<unsigned parseFlags, typename InputStream, typename Handler>
1455 + void ParseNumber(InputStream& is, Handler& handler) {
1456 + internal::StreamLocalCopy<InputStream> copy(is);
1457 + NumberStream<InputStream,
1458 + ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
1459 + ((parseFlags & kParseInsituFlag) == 0) :
1460 + ((parseFlags & kParseFullPrecisionFlag) != 0),
1461 + (parseFlags & kParseNumbersAsStringsFlag) != 0 &&
1462 + (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);
1463 +
1464 + size_t startOffset = s.Tell();
1465 + double d = 0.0;
1466 + bool useNanOrInf = false;
1467 +
1468 + // Parse minus
1469 + bool minus = Consume(s, '-');
1470 +
1471 + // Parse int: zero / ( digit1-9 *DIGIT )
1472 + unsigned i = 0;
1473 + uint64_t i64 = 0;
1474 + bool use64bit = false;
1475 + int significandDigit = 0;
1476 + if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
1477 + i = 0;
1478 + s.TakePush();
1479 + }
1480 + else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
1481 + i = static_cast<unsigned>(s.TakePush() - '0');
1482 +
1483 + if (minus)
1484 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1485 + if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648
1486 + if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {
1487 + i64 = i;
1488 + use64bit = true;
1489 + break;
1490 + }
1491 + }
1492 + i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
1493 + significandDigit++;
1494 + }
1495 + else
1496 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1497 + if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295
1498 + if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {
1499 + i64 = i;
1500 + use64bit = true;
1501 + break;
1502 + }
1503 + }
1504 + i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
1505 + significandDigit++;
1506 + }
1507 + }
1508 + // Parse NaN or Infinity here
1509 + else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
1510 + if (Consume(s, 'N')) {
1511 + if (Consume(s, 'a') && Consume(s, 'N')) {
1512 + d = std::numeric_limits<double>::quiet_NaN();
1513 + useNanOrInf = true;
1514 + }
1515 + }
1516 + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) {
1517 + if (Consume(s, 'n') && Consume(s, 'f')) {
1518 + d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
1519 + useNanOrInf = true;
1520 +
1521 + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
1522 + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) {
1523 + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
1524 + }
1525 + }
1526 + }
1527 +
1528 + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) {
1529 + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
1530 + }
1531 + }
1532 + else
1533 + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
1534 +
1535 + // Parse 64bit int
1536 + bool useDouble = false;
1537 + if (use64bit) {
1538 + if (minus)
1539 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1540 + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
1541 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
1542 + d = static_cast<double>(i64);
1543 + useDouble = true;
1544 + break;
1545 + }
1546 + i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
1547 + significandDigit++;
1548 + }
1549 + else
1550 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1551 + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615
1552 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {
1553 + d = static_cast<double>(i64);
1554 + useDouble = true;
1555 + break;
1556 + }
1557 + i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
1558 + significandDigit++;
1559 + }
1560 + }
1561 +
1562 + // Force double for big integer
1563 + if (useDouble) {
1564 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1565 + if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
1566 + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
1567 + d = d * 10 + (s.TakePush() - '0');
1568 + }
1569 + }
1570 +
1571 + // Parse frac = decimal-point 1*DIGIT
1572 + int expFrac = 0;
1573 + size_t decimalPosition;
1574 + if (Consume(s, '.')) {
1575 + decimalPosition = s.Length();
1576 +
1577 + if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
1578 + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
1579 +
1580 + if (!useDouble) {
1581 +#if RAPIDJSON_64BIT
1582 + // Use i64 to store significand in 64-bit architecture
1583 + if (!use64bit)
1584 + i64 = i;
1585 +
1586 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1587 + if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
1588 + break;
1589 + else {
1590 + i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
1591 + --expFrac;
1592 + if (i64 != 0)
1593 + significandDigit++;
1594 + }
1595 + }
1596 +
1597 + d = static_cast<double>(i64);
1598 +#else
1599 + // Use double to store significand in 32-bit architecture
1600 + d = static_cast<double>(use64bit ? i64 : i);
1601 +#endif
1602 + useDouble = true;
1603 + }
1604 +
1605 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1606 + if (significandDigit < 17) {
1607 + d = d * 10.0 + (s.TakePush() - '0');
1608 + --expFrac;
1609 + if (RAPIDJSON_LIKELY(d > 0.0))
1610 + significandDigit++;
1611 + }
1612 + else
1613 + s.TakePush();
1614 + }
1615 + }
1616 + else
1617 + decimalPosition = s.Length(); // decimal position at the end of integer.
1618 +
1619 + // Parse exp = e [ minus / plus ] 1*DIGIT
1620 + int exp = 0;
1621 + if (Consume(s, 'e') || Consume(s, 'E')) {
1622 + if (!useDouble) {
1623 + d = static_cast<double>(use64bit ? i64 : i);
1624 + useDouble = true;
1625 + }
1626 +
1627 + bool expMinus = false;
1628 + if (Consume(s, '+'))
1629 + ;
1630 + else if (Consume(s, '-'))
1631 + expMinus = true;
1632 +
1633 + if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1634 + exp = static_cast<int>(s.Take() - '0');
1635 + if (expMinus) {
1636 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1637 + exp = exp * 10 + static_cast<int>(s.Take() - '0');
1638 + if (exp >= 214748364) { // Issue #313: prevent overflow exponent
1639 + while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
1640 + s.Take();
1641 + }
1642 + }
1643 + }
1644 + else { // positive exp
1645 + int maxExp = 308 - expFrac;
1646 + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1647 + exp = exp * 10 + static_cast<int>(s.Take() - '0');
1648 + if (RAPIDJSON_UNLIKELY(exp > maxExp))
1649 + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
1650 + }
1651 + }
1652 + }
1653 + else
1654 + RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
1655 +
1656 + if (expMinus)
1657 + exp = -exp;
1658 + }
1659 +
1660 + // Finish parsing, call event according to the type of number.
1661 + bool cont = true;
1662 +
1663 + if (parseFlags & kParseNumbersAsStringsFlag) {
1664 + if (parseFlags & kParseInsituFlag) {
1665 + s.Pop(); // Pop stack no matter if it will be used or not.
1666 + typename InputStream::Ch* head = is.PutBegin();
1667 + const size_t length = s.Tell() - startOffset;
1668 + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
1669 + // unable to insert the \0 character here, it will erase the comma after this number
1670 + const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
1671 + cont = handler.RawNumber(str, SizeType(length), false);
1672 + }
1673 + else {
1674 + SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
1675 + StringStream srcStream(s.Pop());
1676 + StackStream<typename TargetEncoding::Ch> dstStream(stack_);
1677 + while (numCharsToCopy--) {
1678 + Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
1679 + }
1680 + dstStream.Put('\0');
1681 + const typename TargetEncoding::Ch* str = dstStream.Pop();
1682 + const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;
1683 + cont = handler.RawNumber(str, SizeType(length), true);
1684 + }
1685 + }
1686 + else {
1687 + size_t length = s.Length();
1688 + const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
1689 +
1690 + if (useDouble) {
1691 + int p = exp + expFrac;
1692 + if (parseFlags & kParseFullPrecisionFlag)
1693 + d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
1694 + else
1695 + d = internal::StrtodNormalPrecision(d, p);
1696 +
1697 + cont = handler.Double(minus ? -d : d);
1698 + }
1699 + else if (useNanOrInf) {
1700 + cont = handler.Double(d);
1701 + }
1702 + else {
1703 + if (use64bit) {
1704 + if (minus)
1705 + cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
1706 + else
1707 + cont = handler.Uint64(i64);
1708 + }
1709 + else {
1710 + if (minus)
1711 + cont = handler.Int(static_cast<int32_t>(~i + 1));
1712 + else
1713 + cont = handler.Uint(i);
1714 + }
1715 + }
1716 + }
1717 + if (RAPIDJSON_UNLIKELY(!cont))
1718 + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
1719 + }
1720 +
1721 + // Parse any JSON value
1722 + template<unsigned parseFlags, typename InputStream, typename Handler>
1723 + void ParseValue(InputStream& is, Handler& handler) {
1724 + switch (is.Peek()) {
1725 + case 'n': ParseNull <parseFlags>(is, handler); break;
1726 + case 't': ParseTrue <parseFlags>(is, handler); break;
1727 + case 'f': ParseFalse <parseFlags>(is, handler); break;
1728 + case '"': ParseString<parseFlags>(is, handler); break;
1729 + case '{': ParseObject<parseFlags>(is, handler); break;
1730 + case '[': ParseArray <parseFlags>(is, handler); break;
1731 + default :
1732 + ParseNumber<parseFlags>(is, handler);
1733 + break;
1734 +
1735 + }
1736 + }
1737 +
1738 + // Iterative Parsing
1739 +
1740 + // States
1741 + enum IterativeParsingState {
1742 + IterativeParsingFinishState = 0, // sink states at top
1743 + IterativeParsingErrorState, // sink states at top
1744 + IterativeParsingStartState,
1745 +
1746 + // Object states
1747 + IterativeParsingObjectInitialState,
1748 + IterativeParsingMemberKeyState,
1749 + IterativeParsingMemberValueState,
1750 + IterativeParsingObjectFinishState,
1751 +
1752 + // Array states
1753 + IterativeParsingArrayInitialState,
1754 + IterativeParsingElementState,
1755 + IterativeParsingArrayFinishState,
1756 +
1757 + // Single value state
1758 + IterativeParsingValueState,
1759 +
1760 + // Delimiter states (at bottom)
1761 + IterativeParsingElementDelimiterState,
1762 + IterativeParsingMemberDelimiterState,
1763 + IterativeParsingKeyValueDelimiterState,
1764 +
1765 + cIterativeParsingStateCount
1766 + };
1767 +
1768 + // Tokens
1769 + enum Token {
1770 + LeftBracketToken = 0,
1771 + RightBracketToken,
1772 +
1773 + LeftCurlyBracketToken,
1774 + RightCurlyBracketToken,
1775 +
1776 + CommaToken,
1777 + ColonToken,
1778 +
1779 + StringToken,
1780 + FalseToken,
1781 + TrueToken,
1782 + NullToken,
1783 + NumberToken,
1784 +
1785 + kTokenCount
1786 + };
1787 +
1788 + RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
1789 +
1790 +//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
1791 +#define N NumberToken
1792 +#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N
1793 + // Maps from ASCII to Token
1794 + static const unsigned char tokenMap[256] = {
1795 + N16, // 00~0F
1796 + N16, // 10~1F
1797 + N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F
1798 + N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F
1799 + N16, // 40~4F
1800 + N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F
1801 + N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F
1802 + N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F
1803 + N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF
1804 + };
1805 +#undef N
1806 +#undef N16
1807 +//!@endcond
1808 +
1809 + if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
1810 + return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
1811 + else
1812 + return NumberToken;
1813 + }
1814 +
1815 + RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
1816 + // current state x one lookahead token -> new state
1817 + static const char G[cIterativeParsingStateCount][kTokenCount] = {
1818 + // Finish(sink state)
1819 + {
1820 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1821 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1822 + IterativeParsingErrorState
1823 + },
1824 + // Error(sink state)
1825 + {
1826 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1827 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1828 + IterativeParsingErrorState
1829 + },
1830 + // Start
1831 + {
1832 + IterativeParsingArrayInitialState, // Left bracket
1833 + IterativeParsingErrorState, // Right bracket
1834 + IterativeParsingObjectInitialState, // Left curly bracket
1835 + IterativeParsingErrorState, // Right curly bracket
1836 + IterativeParsingErrorState, // Comma
1837 + IterativeParsingErrorState, // Colon
1838 + IterativeParsingValueState, // String
1839 + IterativeParsingValueState, // False
1840 + IterativeParsingValueState, // True
1841 + IterativeParsingValueState, // Null
1842 + IterativeParsingValueState // Number
1843 + },
1844 + // ObjectInitial
1845 + {
1846 + IterativeParsingErrorState, // Left bracket
1847 + IterativeParsingErrorState, // Right bracket
1848 + IterativeParsingErrorState, // Left curly bracket
1849 + IterativeParsingObjectFinishState, // Right curly bracket
1850 + IterativeParsingErrorState, // Comma
1851 + IterativeParsingErrorState, // Colon
1852 + IterativeParsingMemberKeyState, // String
1853 + IterativeParsingErrorState, // False
1854 + IterativeParsingErrorState, // True
1855 + IterativeParsingErrorState, // Null
1856 + IterativeParsingErrorState // Number
1857 + },
1858 + // MemberKey
1859 + {
1860 + IterativeParsingErrorState, // Left bracket
1861 + IterativeParsingErrorState, // Right bracket
1862 + IterativeParsingErrorState, // Left curly bracket
1863 + IterativeParsingErrorState, // Right curly bracket
1864 + IterativeParsingErrorState, // Comma
1865 + IterativeParsingKeyValueDelimiterState, // Colon
1866 + IterativeParsingErrorState, // String
1867 + IterativeParsingErrorState, // False
1868 + IterativeParsingErrorState, // True
1869 + IterativeParsingErrorState, // Null
1870 + IterativeParsingErrorState // Number
1871 + },
1872 + // MemberValue
1873 + {
1874 + IterativeParsingErrorState, // Left bracket
1875 + IterativeParsingErrorState, // Right bracket
1876 + IterativeParsingErrorState, // Left curly bracket
1877 + IterativeParsingObjectFinishState, // Right curly bracket
1878 + IterativeParsingMemberDelimiterState, // Comma
1879 + IterativeParsingErrorState, // Colon
1880 + IterativeParsingErrorState, // String
1881 + IterativeParsingErrorState, // False
1882 + IterativeParsingErrorState, // True
1883 + IterativeParsingErrorState, // Null
1884 + IterativeParsingErrorState // Number
1885 + },
1886 + // ObjectFinish(sink state)
1887 + {
1888 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1889 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1890 + IterativeParsingErrorState
1891 + },
1892 + // ArrayInitial
1893 + {
1894 + IterativeParsingArrayInitialState, // Left bracket(push Element state)
1895 + IterativeParsingArrayFinishState, // Right bracket
1896 + IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
1897 + IterativeParsingErrorState, // Right curly bracket
1898 + IterativeParsingErrorState, // Comma
1899 + IterativeParsingErrorState, // Colon
1900 + IterativeParsingElementState, // String
1901 + IterativeParsingElementState, // False
1902 + IterativeParsingElementState, // True
1903 + IterativeParsingElementState, // Null
1904 + IterativeParsingElementState // Number
1905 + },
1906 + // Element
1907 + {
1908 + IterativeParsingErrorState, // Left bracket
1909 + IterativeParsingArrayFinishState, // Right bracket
1910 + IterativeParsingErrorState, // Left curly bracket
1911 + IterativeParsingErrorState, // Right curly bracket
1912 + IterativeParsingElementDelimiterState, // Comma
1913 + IterativeParsingErrorState, // Colon
1914 + IterativeParsingErrorState, // String
1915 + IterativeParsingErrorState, // False
1916 + IterativeParsingErrorState, // True
1917 + IterativeParsingErrorState, // Null
1918 + IterativeParsingErrorState // Number
1919 + },
1920 + // ArrayFinish(sink state)
1921 + {
1922 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1923 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1924 + IterativeParsingErrorState
1925 + },
1926 + // Single Value (sink state)
1927 + {
1928 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1929 + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1930 + IterativeParsingErrorState
1931 + },
1932 + // ElementDelimiter
1933 + {
1934 + IterativeParsingArrayInitialState, // Left bracket(push Element state)
1935 + IterativeParsingArrayFinishState, // Right bracket
1936 + IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
1937 + IterativeParsingErrorState, // Right curly bracket
1938 + IterativeParsingErrorState, // Comma
1939 + IterativeParsingErrorState, // Colon
1940 + IterativeParsingElementState, // String
1941 + IterativeParsingElementState, // False
1942 + IterativeParsingElementState, // True
1943 + IterativeParsingElementState, // Null
1944 + IterativeParsingElementState // Number
1945 + },
1946 + // MemberDelimiter
1947 + {
1948 + IterativeParsingErrorState, // Left bracket
1949 + IterativeParsingErrorState, // Right bracket
1950 + IterativeParsingErrorState, // Left curly bracket
1951 + IterativeParsingObjectFinishState, // Right curly bracket
1952 + IterativeParsingErrorState, // Comma
1953 + IterativeParsingErrorState, // Colon
1954 + IterativeParsingMemberKeyState, // String
1955 + IterativeParsingErrorState, // False
1956 + IterativeParsingErrorState, // True
1957 + IterativeParsingErrorState, // Null
1958 + IterativeParsingErrorState // Number
1959 + },
1960 + // KeyValueDelimiter
1961 + {
1962 + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
1963 + IterativeParsingErrorState, // Right bracket
1964 + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
1965 + IterativeParsingErrorState, // Right curly bracket
1966 + IterativeParsingErrorState, // Comma
1967 + IterativeParsingErrorState, // Colon
1968 + IterativeParsingMemberValueState, // String
1969 + IterativeParsingMemberValueState, // False
1970 + IterativeParsingMemberValueState, // True
1971 + IterativeParsingMemberValueState, // Null
1972 + IterativeParsingMemberValueState // Number
1973 + },
1974 + }; // End of G
1975 +
1976 + return static_cast<IterativeParsingState>(G[state][token]);
1977 + }
1978 +
1979 + // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
1980 + // May return a new state on state pop.
1981 + template <unsigned parseFlags, typename InputStream, typename Handler>
1982 + RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
1983 + (void)token;
1984 +
1985 + switch (dst) {
1986 + case IterativeParsingErrorState:
1987 + return dst;
1988 +
1989 + case IterativeParsingObjectInitialState:
1990 + case IterativeParsingArrayInitialState:
1991 + {
1992 + // Push the state(Element or MemeberValue) if we are nested in another array or value of member.
1993 + // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.
1994 + IterativeParsingState n = src;
1995 + if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)
1996 + n = IterativeParsingElementState;
1997 + else if (src == IterativeParsingKeyValueDelimiterState)
1998 + n = IterativeParsingMemberValueState;
1999 + // Push current state.
2000 + *stack_.template Push<SizeType>(1) = n;
2001 + // Initialize and push the member/element count.
2002 + *stack_.template Push<SizeType>(1) = 0;
2003 + // Call handler
2004 + bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();
2005 + // On handler short circuits the parsing.
2006 + if (!hr) {
2007 + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
2008 + return IterativeParsingErrorState;
2009 + }
2010 + else {
2011 + is.Take();
2012 + return dst;
2013 + }
2014 + }
2015 +
2016 + case IterativeParsingMemberKeyState:
2017 + ParseString<parseFlags>(is, handler, true);
2018 + if (HasParseError())
2019 + return IterativeParsingErrorState;
2020 + else
2021 + return dst;
2022 +
2023 + case IterativeParsingKeyValueDelimiterState:
2024 + RAPIDJSON_ASSERT(token == ColonToken);
2025 + is.Take();
2026 + return dst;
2027 +
2028 + case IterativeParsingMemberValueState:
2029 + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
2030 + ParseValue<parseFlags>(is, handler);
2031 + if (HasParseError()) {
2032 + return IterativeParsingErrorState;
2033 + }
2034 + return dst;
2035 +
2036 + case IterativeParsingElementState:
2037 + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
2038 + ParseValue<parseFlags>(is, handler);
2039 + if (HasParseError()) {
2040 + return IterativeParsingErrorState;
2041 + }
2042 + return dst;
2043 +
2044 + case IterativeParsingMemberDelimiterState:
2045 + case IterativeParsingElementDelimiterState:
2046 + is.Take();
2047 + // Update member/element count.
2048 + *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
2049 + return dst;
2050 +
2051 + case IterativeParsingObjectFinishState:
2052 + {
2053 + // Transit from delimiter is only allowed when trailing commas are enabled
2054 + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) {
2055 + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell());
2056 + return IterativeParsingErrorState;
2057 + }
2058 + // Get member count.
2059 + SizeType c = *stack_.template Pop<SizeType>(1);
2060 + // If the object is not empty, count the last member.
2061 + if (src == IterativeParsingMemberValueState)
2062 + ++c;
2063 + // Restore the state.
2064 + IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
2065 + // Transit to Finish state if this is the topmost scope.
2066 + if (n == IterativeParsingStartState)
2067 + n = IterativeParsingFinishState;
2068 + // Call handler
2069 + bool hr = handler.EndObject(c);
2070 + // On handler short circuits the parsing.
2071 + if (!hr) {
2072 + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
2073 + return IterativeParsingErrorState;
2074 + }
2075 + else {
2076 + is.Take();
2077 + return n;
2078 + }
2079 + }
2080 +
2081 + case IterativeParsingArrayFinishState:
2082 + {
2083 + // Transit from delimiter is only allowed when trailing commas are enabled
2084 + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) {
2085 + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell());
2086 + return IterativeParsingErrorState;
2087 + }
2088 + // Get element count.
2089 + SizeType c = *stack_.template Pop<SizeType>(1);
2090 + // If the array is not empty, count the last element.
2091 + if (src == IterativeParsingElementState)
2092 + ++c;
2093 + // Restore the state.
2094 + IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
2095 + // Transit to Finish state if this is the topmost scope.
2096 + if (n == IterativeParsingStartState)
2097 + n = IterativeParsingFinishState;
2098 + // Call handler
2099 + bool hr = handler.EndArray(c);
2100 + // On handler short circuits the parsing.
2101 + if (!hr) {
2102 + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
2103 + return IterativeParsingErrorState;
2104 + }
2105 + else {
2106 + is.Take();
2107 + return n;
2108 + }
2109 + }
2110 +
2111 + default:
2112 + // This branch is for IterativeParsingValueState actually.
2113 + // Use `default:` rather than
2114 + // `case IterativeParsingValueState:` is for code coverage.
2115 +
2116 + // The IterativeParsingStartState is not enumerated in this switch-case.
2117 + // It is impossible for that case. And it can be caught by following assertion.
2118 +
2119 + // The IterativeParsingFinishState is not enumerated in this switch-case either.
2120 + // It is a "derivative" state which cannot triggered from Predict() directly.
2121 + // Therefore it cannot happen here. And it can be caught by following assertion.
2122 + RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
2123 +
2124 + // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
2125 + ParseValue<parseFlags>(is, handler);
2126 + if (HasParseError()) {
2127 + return IterativeParsingErrorState;
2128 + }
2129 + return IterativeParsingFinishState;
2130 + }
2131 + }
2132 +
2133 + template <typename InputStream>
2134 + void HandleError(IterativeParsingState src, InputStream& is) {
2135 + if (HasParseError()) {
2136 + // Error flag has been set.
2137 + return;
2138 + }
2139 +
2140 + switch (src) {
2141 + case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
2142 + case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
2143 + case IterativeParsingObjectInitialState:
2144 + case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
2145 + case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
2146 + case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
2147 + case IterativeParsingKeyValueDelimiterState:
2148 + case IterativeParsingArrayInitialState:
2149 + case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;
2150 + default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
2151 + }
2152 + }
2153 +
2154 + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) {
2155 + return s >= IterativeParsingElementDelimiterState;
2156 + }
2157 +
2158 + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) {
2159 + return s <= IterativeParsingErrorState;
2160 + }
2161 +
2162 + template <unsigned parseFlags, typename InputStream, typename Handler>
2163 + ParseResult IterativeParse(InputStream& is, Handler& handler) {
2164 + parseResult_.Clear();
2165 + ClearStackOnExit scope(*this);
2166 + IterativeParsingState state = IterativeParsingStartState;
2167 +
2168 + SkipWhitespaceAndComments<parseFlags>(is);
2169 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
2170 + while (is.Peek() != '\0') {
2171 + Token t = Tokenize(is.Peek());
2172 + IterativeParsingState n = Predict(state, t);
2173 + IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
2174 +
2175 + if (d == IterativeParsingErrorState) {
2176 + HandleError(state, is);
2177 + break;
2178 + }
2179 +
2180 + state = d;
2181 +
2182 + // Do not further consume streams if a root JSON has been parsed.
2183 + if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
2184 + break;
2185 +
2186 + SkipWhitespaceAndComments<parseFlags>(is);
2187 + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
2188 + }
2189 +
2190 + // Handle the end of file.
2191 + if (state != IterativeParsingFinishState)
2192 + HandleError(state, is);
2193 +
2194 + return parseResult_;
2195 + }
2196 +
2197 + static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
2198 + internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
2199 + ParseResult parseResult_;
2200 + IterativeParsingState state_;
2201 +}; // class GenericReader
2202 +
2203 +//! Reader with UTF8 encoding and default allocator.
2204 +typedef GenericReader<UTF8<>, UTF8<> > Reader;
2205 +
2206 +RAPIDJSON_NAMESPACE_END
2207 +
2208 +#ifdef __clang__
2209 +RAPIDJSON_DIAG_POP
2210 +#endif
2211 +
2212 +
2213 +#ifdef __GNUC__
2214 +RAPIDJSON_DIAG_POP
2215 +#endif
2216 +
2217 +#ifdef _MSC_VER
2218 +RAPIDJSON_DIAG_POP
2219 +#endif
2220 +
2221 +#endif // RAPIDJSON_READER_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available->
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License-> You may obtain a copy of the License at
7 +//
8 +// http://opensource->org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
13 +// specific language governing permissions and limitations under the License->
14 +
15 +#ifndef RAPIDJSON_SCHEMA_H_
16 +#define RAPIDJSON_SCHEMA_H_
17 +
18 +#include "document.h"
19 +#include "pointer.h"
20 +#include <cmath> // abs, floor
21 +
22 +#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
23 +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
24 +#else
25 +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
26 +#endif
27 +
28 +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
29 +#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
30 +#else
31 +#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
32 +#endif
33 +
34 +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
35 +#include "internal/regex.h"
36 +#elif RAPIDJSON_SCHEMA_USE_STDREGEX
37 +#include <regex>
38 +#endif
39 +
40 +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
41 +#define RAPIDJSON_SCHEMA_HAS_REGEX 1
42 +#else
43 +#define RAPIDJSON_SCHEMA_HAS_REGEX 0
44 +#endif
45 +
46 +#ifndef RAPIDJSON_SCHEMA_VERBOSE
47 +#define RAPIDJSON_SCHEMA_VERBOSE 0
48 +#endif
49 +
50 +#if RAPIDJSON_SCHEMA_VERBOSE
51 +#include "stringbuffer.h"
52 +#endif
53 +
54 +RAPIDJSON_DIAG_PUSH
55 +
56 +#if defined(__GNUC__)
57 +RAPIDJSON_DIAG_OFF(effc++)
58 +#endif
59 +
60 +#ifdef __clang__
61 +RAPIDJSON_DIAG_OFF(weak-vtables)
62 +RAPIDJSON_DIAG_OFF(exit-time-destructors)
63 +RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
64 +RAPIDJSON_DIAG_OFF(variadic-macros)
65 +#endif
66 +
67 +#ifdef _MSC_VER
68 +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
69 +#endif
70 +
71 +RAPIDJSON_NAMESPACE_BEGIN
72 +
73 +///////////////////////////////////////////////////////////////////////////////
74 +// Verbose Utilities
75 +
76 +#if RAPIDJSON_SCHEMA_VERBOSE
77 +
78 +namespace internal {
79 +
80 +inline void PrintInvalidKeyword(const char* keyword) {
81 + printf("Fail keyword: %s\n", keyword);
82 +}
83 +
84 +inline void PrintInvalidKeyword(const wchar_t* keyword) {
85 + wprintf(L"Fail keyword: %ls\n", keyword);
86 +}
87 +
88 +inline void PrintInvalidDocument(const char* document) {
89 + printf("Fail document: %s\n\n", document);
90 +}
91 +
92 +inline void PrintInvalidDocument(const wchar_t* document) {
93 + wprintf(L"Fail document: %ls\n\n", document);
94 +}
95 +
96 +inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
97 + printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
98 +}
99 +
100 +inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
101 + wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
102 +}
103 +
104 +} // namespace internal
105 +
106 +#endif // RAPIDJSON_SCHEMA_VERBOSE
107 +
108 +///////////////////////////////////////////////////////////////////////////////
109 +// RAPIDJSON_INVALID_KEYWORD_RETURN
110 +
111 +#if RAPIDJSON_SCHEMA_VERBOSE
112 +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
113 +#else
114 +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
115 +#endif
116 +
117 +#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
118 +RAPIDJSON_MULTILINEMACRO_BEGIN\
119 + context.invalidKeyword = keyword.GetString();\
120 + RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
121 + return false;\
122 +RAPIDJSON_MULTILINEMACRO_END
123 +
124 +///////////////////////////////////////////////////////////////////////////////
125 +// Forward declarations
126 +
127 +template <typename ValueType, typename Allocator>
128 +class GenericSchemaDocument;
129 +
130 +namespace internal {
131 +
132 +template <typename SchemaDocumentType>
133 +class Schema;
134 +
135 +///////////////////////////////////////////////////////////////////////////////
136 +// ISchemaValidator
137 +
138 +class ISchemaValidator {
139 +public:
140 + virtual ~ISchemaValidator() {}
141 + virtual bool IsValid() const = 0;
142 +};
143 +
144 +///////////////////////////////////////////////////////////////////////////////
145 +// ISchemaStateFactory
146 +
147 +template <typename SchemaType>
148 +class ISchemaStateFactory {
149 +public:
150 + virtual ~ISchemaStateFactory() {}
151 + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
152 + virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
153 + virtual void* CreateHasher() = 0;
154 + virtual uint64_t GetHashCode(void* hasher) = 0;
155 + virtual void DestroryHasher(void* hasher) = 0;
156 + virtual void* MallocState(size_t size) = 0;
157 + virtual void FreeState(void* p) = 0;
158 +};
159 +
160 +///////////////////////////////////////////////////////////////////////////////
161 +// Hasher
162 +
163 +// For comparison of compound value
164 +template<typename Encoding, typename Allocator>
165 +class Hasher {
166 +public:
167 + typedef typename Encoding::Ch Ch;
168 +
169 + Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
170 +
171 + bool Null() { return WriteType(kNullType); }
172 + bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
173 + bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
174 + bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
175 + bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
176 + bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
177 + bool Double(double d) {
178 + Number n;
179 + if (d < 0) n.u.i = static_cast<int64_t>(d);
180 + else n.u.u = static_cast<uint64_t>(d);
181 + n.d = d;
182 + return WriteNumber(n);
183 + }
184 +
185 + bool RawNumber(const Ch* str, SizeType len, bool) {
186 + WriteBuffer(kNumberType, str, len * sizeof(Ch));
187 + return true;
188 + }
189 +
190 + bool String(const Ch* str, SizeType len, bool) {
191 + WriteBuffer(kStringType, str, len * sizeof(Ch));
192 + return true;
193 + }
194 +
195 + bool StartObject() { return true; }
196 + bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
197 + bool EndObject(SizeType memberCount) {
198 + uint64_t h = Hash(0, kObjectType);
199 + uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
200 + for (SizeType i = 0; i < memberCount; i++)
201 + h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive
202 + *stack_.template Push<uint64_t>() = h;
203 + return true;
204 + }
205 +
206 + bool StartArray() { return true; }
207 + bool EndArray(SizeType elementCount) {
208 + uint64_t h = Hash(0, kArrayType);
209 + uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
210 + for (SizeType i = 0; i < elementCount; i++)
211 + h = Hash(h, e[i]); // Use hash to achieve element order sensitive
212 + *stack_.template Push<uint64_t>() = h;
213 + return true;
214 + }
215 +
216 + bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
217 +
218 + uint64_t GetHashCode() const {
219 + RAPIDJSON_ASSERT(IsValid());
220 + return *stack_.template Top<uint64_t>();
221 + }
222 +
223 +private:
224 + static const size_t kDefaultSize = 256;
225 + struct Number {
226 + union U {
227 + uint64_t u;
228 + int64_t i;
229 + }u;
230 + double d;
231 + };
232 +
233 + bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
234 +
235 + bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
236 +
237 + bool WriteBuffer(Type type, const void* data, size_t len) {
238 + // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
239 + uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
240 + const unsigned char* d = static_cast<const unsigned char*>(data);
241 + for (size_t i = 0; i < len; i++)
242 + h = Hash(h, d[i]);
243 + *stack_.template Push<uint64_t>() = h;
244 + return true;
245 + }
246 +
247 + static uint64_t Hash(uint64_t h, uint64_t d) {
248 + static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
249 + h ^= d;
250 + h *= kPrime;
251 + return h;
252 + }
253 +
254 + Stack<Allocator> stack_;
255 +};
256 +
257 +///////////////////////////////////////////////////////////////////////////////
258 +// SchemaValidationContext
259 +
260 +template <typename SchemaDocumentType>
261 +struct SchemaValidationContext {
262 + typedef Schema<SchemaDocumentType> SchemaType;
263 + typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
264 + typedef typename SchemaType::ValueType ValueType;
265 + typedef typename ValueType::Ch Ch;
266 +
267 + enum PatternValidatorType {
268 + kPatternValidatorOnly,
269 + kPatternValidatorWithProperty,
270 + kPatternValidatorWithAdditionalProperty
271 + };
272 +
273 + SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
274 + factory(f),
275 + schema(s),
276 + valueSchema(),
277 + invalidKeyword(),
278 + hasher(),
279 + arrayElementHashCodes(),
280 + validators(),
281 + validatorCount(),
282 + patternPropertiesValidators(),
283 + patternPropertiesValidatorCount(),
284 + patternPropertiesSchemas(),
285 + patternPropertiesSchemaCount(),
286 + valuePatternValidatorType(kPatternValidatorOnly),
287 + propertyExist(),
288 + inArray(false),
289 + valueUniqueness(false),
290 + arrayUniqueness(false)
291 + {
292 + }
293 +
294 + ~SchemaValidationContext() {
295 + if (hasher)
296 + factory.DestroryHasher(hasher);
297 + if (validators) {
298 + for (SizeType i = 0; i < validatorCount; i++)
299 + factory.DestroySchemaValidator(validators[i]);
300 + factory.FreeState(validators);
301 + }
302 + if (patternPropertiesValidators) {
303 + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
304 + factory.DestroySchemaValidator(patternPropertiesValidators[i]);
305 + factory.FreeState(patternPropertiesValidators);
306 + }
307 + if (patternPropertiesSchemas)
308 + factory.FreeState(patternPropertiesSchemas);
309 + if (propertyExist)
310 + factory.FreeState(propertyExist);
311 + }
312 +
313 + SchemaValidatorFactoryType& factory;
314 + const SchemaType* schema;
315 + const SchemaType* valueSchema;
316 + const Ch* invalidKeyword;
317 + void* hasher; // Only validator access
318 + void* arrayElementHashCodes; // Only validator access this
319 + ISchemaValidator** validators;
320 + SizeType validatorCount;
321 + ISchemaValidator** patternPropertiesValidators;
322 + SizeType patternPropertiesValidatorCount;
323 + const SchemaType** patternPropertiesSchemas;
324 + SizeType patternPropertiesSchemaCount;
325 + PatternValidatorType valuePatternValidatorType;
326 + PatternValidatorType objectPatternValidatorType;
327 + SizeType arrayElementIndex;
328 + bool* propertyExist;
329 + bool inArray;
330 + bool valueUniqueness;
331 + bool arrayUniqueness;
332 +};
333 +
334 +///////////////////////////////////////////////////////////////////////////////
335 +// Schema
336 +
337 +template <typename SchemaDocumentType>
338 +class Schema {
339 +public:
340 + typedef typename SchemaDocumentType::ValueType ValueType;
341 + typedef typename SchemaDocumentType::AllocatorType AllocatorType;
342 + typedef typename SchemaDocumentType::PointerType PointerType;
343 + typedef typename ValueType::EncodingType EncodingType;
344 + typedef typename EncodingType::Ch Ch;
345 + typedef SchemaValidationContext<SchemaDocumentType> Context;
346 + typedef Schema<SchemaDocumentType> SchemaType;
347 + typedef GenericValue<EncodingType, AllocatorType> SValue;
348 + friend class GenericSchemaDocument<ValueType, AllocatorType>;
349 +
350 + Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
351 + allocator_(allocator),
352 + typeless_(schemaDocument->GetTypeless()),
353 + enum_(),
354 + enumCount_(),
355 + not_(),
356 + type_((1 << kTotalSchemaType) - 1), // typeless
357 + validatorCount_(),
358 + properties_(),
359 + additionalPropertiesSchema_(),
360 + patternProperties_(),
361 + patternPropertyCount_(),
362 + propertyCount_(),
363 + minProperties_(),
364 + maxProperties_(SizeType(~0)),
365 + additionalProperties_(true),
366 + hasDependencies_(),
367 + hasRequired_(),
368 + hasSchemaDependencies_(),
369 + additionalItemsSchema_(),
370 + itemsList_(),
371 + itemsTuple_(),
372 + itemsTupleCount_(),
373 + minItems_(),
374 + maxItems_(SizeType(~0)),
375 + additionalItems_(true),
376 + uniqueItems_(false),
377 + pattern_(),
378 + minLength_(0),
379 + maxLength_(~SizeType(0)),
380 + exclusiveMinimum_(false),
381 + exclusiveMaximum_(false)
382 + {
383 + typedef typename SchemaDocumentType::ValueType ValueType;
384 + typedef typename ValueType::ConstValueIterator ConstValueIterator;
385 + typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
386 +
387 + if (!value.IsObject())
388 + return;
389 +
390 + if (const ValueType* v = GetMember(value, GetTypeString())) {
391 + type_ = 0;
392 + if (v->IsString())
393 + AddType(*v);
394 + else if (v->IsArray())
395 + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
396 + AddType(*itr);
397 + }
398 +
399 + if (const ValueType* v = GetMember(value, GetEnumString()))
400 + if (v->IsArray() && v->Size() > 0) {
401 + enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
402 + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
403 + typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
404 + char buffer[256 + 24];
405 + MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
406 + EnumHasherType h(&hasherAllocator, 256);
407 + itr->Accept(h);
408 + enum_[enumCount_++] = h.GetHashCode();
409 + }
410 + }
411 +
412 + if (schemaDocument) {
413 + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
414 + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
415 + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
416 + }
417 +
418 + if (const ValueType* v = GetMember(value, GetNotString())) {
419 + schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
420 + notValidatorIndex_ = validatorCount_;
421 + validatorCount_++;
422 + }
423 +
424 + // Object
425 +
426 + const ValueType* properties = GetMember(value, GetPropertiesString());
427 + const ValueType* required = GetMember(value, GetRequiredString());
428 + const ValueType* dependencies = GetMember(value, GetDependenciesString());
429 + {
430 + // Gather properties from properties/required/dependencies
431 + SValue allProperties(kArrayType);
432 +
433 + if (properties && properties->IsObject())
434 + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
435 + AddUniqueElement(allProperties, itr->name);
436 +
437 + if (required && required->IsArray())
438 + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
439 + if (itr->IsString())
440 + AddUniqueElement(allProperties, *itr);
441 +
442 + if (dependencies && dependencies->IsObject())
443 + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
444 + AddUniqueElement(allProperties, itr->name);
445 + if (itr->value.IsArray())
446 + for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
447 + if (i->IsString())
448 + AddUniqueElement(allProperties, *i);
449 + }
450 +
451 + if (allProperties.Size() > 0) {
452 + propertyCount_ = allProperties.Size();
453 + properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
454 + for (SizeType i = 0; i < propertyCount_; i++) {
455 + new (&properties_[i]) Property();
456 + properties_[i].name = allProperties[i];
457 + properties_[i].schema = typeless_;
458 + }
459 + }
460 + }
461 +
462 + if (properties && properties->IsObject()) {
463 + PointerType q = p.Append(GetPropertiesString(), allocator_);
464 + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
465 + SizeType index;
466 + if (FindPropertyIndex(itr->name, &index))
467 + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
468 + }
469 + }
470 +
471 + if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
472 + PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
473 + patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
474 + patternPropertyCount_ = 0;
475 +
476 + for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
477 + new (&patternProperties_[patternPropertyCount_]) PatternProperty();
478 + patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
479 + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
480 + patternPropertyCount_++;
481 + }
482 + }
483 +
484 + if (required && required->IsArray())
485 + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
486 + if (itr->IsString()) {
487 + SizeType index;
488 + if (FindPropertyIndex(*itr, &index)) {
489 + properties_[index].required = true;
490 + hasRequired_ = true;
491 + }
492 + }
493 +
494 + if (dependencies && dependencies->IsObject()) {
495 + PointerType q = p.Append(GetDependenciesString(), allocator_);
496 + hasDependencies_ = true;
497 + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
498 + SizeType sourceIndex;
499 + if (FindPropertyIndex(itr->name, &sourceIndex)) {
500 + if (itr->value.IsArray()) {
501 + properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
502 + std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
503 + for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
504 + SizeType targetIndex;
505 + if (FindPropertyIndex(*targetItr, &targetIndex))
506 + properties_[sourceIndex].dependencies[targetIndex] = true;
507 + }
508 + }
509 + else if (itr->value.IsObject()) {
510 + hasSchemaDependencies_ = true;
511 + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
512 + properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
513 + validatorCount_++;
514 + }
515 + }
516 + }
517 + }
518 +
519 + if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
520 + if (v->IsBool())
521 + additionalProperties_ = v->GetBool();
522 + else if (v->IsObject())
523 + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
524 + }
525 +
526 + AssignIfExist(minProperties_, value, GetMinPropertiesString());
527 + AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
528 +
529 + // Array
530 + if (const ValueType* v = GetMember(value, GetItemsString())) {
531 + PointerType q = p.Append(GetItemsString(), allocator_);
532 + if (v->IsObject()) // List validation
533 + schemaDocument->CreateSchema(&itemsList_, q, *v, document);
534 + else if (v->IsArray()) { // Tuple validation
535 + itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
536 + SizeType index = 0;
537 + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
538 + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
539 + }
540 + }
541 +
542 + AssignIfExist(minItems_, value, GetMinItemsString());
543 + AssignIfExist(maxItems_, value, GetMaxItemsString());
544 +
545 + if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
546 + if (v->IsBool())
547 + additionalItems_ = v->GetBool();
548 + else if (v->IsObject())
549 + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
550 + }
551 +
552 + AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
553 +
554 + // String
555 + AssignIfExist(minLength_, value, GetMinLengthString());
556 + AssignIfExist(maxLength_, value, GetMaxLengthString());
557 +
558 + if (const ValueType* v = GetMember(value, GetPatternString()))
559 + pattern_ = CreatePattern(*v);
560 +
561 + // Number
562 + if (const ValueType* v = GetMember(value, GetMinimumString()))
563 + if (v->IsNumber())
564 + minimum_.CopyFrom(*v, *allocator_);
565 +
566 + if (const ValueType* v = GetMember(value, GetMaximumString()))
567 + if (v->IsNumber())
568 + maximum_.CopyFrom(*v, *allocator_);
569 +
570 + AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
571 + AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
572 +
573 + if (const ValueType* v = GetMember(value, GetMultipleOfString()))
574 + if (v->IsNumber() && v->GetDouble() > 0.0)
575 + multipleOf_.CopyFrom(*v, *allocator_);
576 + }
577 +
578 + ~Schema() {
579 + AllocatorType::Free(enum_);
580 + if (properties_) {
581 + for (SizeType i = 0; i < propertyCount_; i++)
582 + properties_[i].~Property();
583 + AllocatorType::Free(properties_);
584 + }
585 + if (patternProperties_) {
586 + for (SizeType i = 0; i < patternPropertyCount_; i++)
587 + patternProperties_[i].~PatternProperty();
588 + AllocatorType::Free(patternProperties_);
589 + }
590 + AllocatorType::Free(itemsTuple_);
591 +#if RAPIDJSON_SCHEMA_HAS_REGEX
592 + if (pattern_) {
593 + pattern_->~RegexType();
594 + AllocatorType::Free(pattern_);
595 + }
596 +#endif
597 + }
598 +
599 + bool BeginValue(Context& context) const {
600 + if (context.inArray) {
601 + if (uniqueItems_)
602 + context.valueUniqueness = true;
603 +
604 + if (itemsList_)
605 + context.valueSchema = itemsList_;
606 + else if (itemsTuple_) {
607 + if (context.arrayElementIndex < itemsTupleCount_)
608 + context.valueSchema = itemsTuple_[context.arrayElementIndex];
609 + else if (additionalItemsSchema_)
610 + context.valueSchema = additionalItemsSchema_;
611 + else if (additionalItems_)
612 + context.valueSchema = typeless_;
613 + else
614 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
615 + }
616 + else
617 + context.valueSchema = typeless_;
618 +
619 + context.arrayElementIndex++;
620 + }
621 + return true;
622 + }
623 +
624 + RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
625 + if (context.patternPropertiesValidatorCount > 0) {
626 + bool otherValid = false;
627 + SizeType count = context.patternPropertiesValidatorCount;
628 + if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
629 + otherValid = context.patternPropertiesValidators[--count]->IsValid();
630 +
631 + bool patternValid = true;
632 + for (SizeType i = 0; i < count; i++)
633 + if (!context.patternPropertiesValidators[i]->IsValid()) {
634 + patternValid = false;
635 + break;
636 + }
637 +
638 + if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
639 + if (!patternValid)
640 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
641 + }
642 + else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
643 + if (!patternValid || !otherValid)
644 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
645 + }
646 + else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
647 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
648 + }
649 +
650 + if (enum_) {
651 + const uint64_t h = context.factory.GetHashCode(context.hasher);
652 + for (SizeType i = 0; i < enumCount_; i++)
653 + if (enum_[i] == h)
654 + goto foundEnum;
655 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
656 + foundEnum:;
657 + }
658 +
659 + if (allOf_.schemas)
660 + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
661 + if (!context.validators[i]->IsValid())
662 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
663 +
664 + if (anyOf_.schemas) {
665 + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
666 + if (context.validators[i]->IsValid())
667 + goto foundAny;
668 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
669 + foundAny:;
670 + }
671 +
672 + if (oneOf_.schemas) {
673 + bool oneValid = false;
674 + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
675 + if (context.validators[i]->IsValid()) {
676 + if (oneValid)
677 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
678 + else
679 + oneValid = true;
680 + }
681 + if (!oneValid)
682 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
683 + }
684 +
685 + if (not_ && context.validators[notValidatorIndex_]->IsValid())
686 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
687 +
688 + return true;
689 + }
690 +
691 + bool Null(Context& context) const {
692 + if (!(type_ & (1 << kNullSchemaType)))
693 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
694 + return CreateParallelValidator(context);
695 + }
696 +
697 + bool Bool(Context& context, bool) const {
698 + if (!(type_ & (1 << kBooleanSchemaType)))
699 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
700 + return CreateParallelValidator(context);
701 + }
702 +
703 + bool Int(Context& context, int i) const {
704 + if (!CheckInt(context, i))
705 + return false;
706 + return CreateParallelValidator(context);
707 + }
708 +
709 + bool Uint(Context& context, unsigned u) const {
710 + if (!CheckUint(context, u))
711 + return false;
712 + return CreateParallelValidator(context);
713 + }
714 +
715 + bool Int64(Context& context, int64_t i) const {
716 + if (!CheckInt(context, i))
717 + return false;
718 + return CreateParallelValidator(context);
719 + }
720 +
721 + bool Uint64(Context& context, uint64_t u) const {
722 + if (!CheckUint(context, u))
723 + return false;
724 + return CreateParallelValidator(context);
725 + }
726 +
727 + bool Double(Context& context, double d) const {
728 + if (!(type_ & (1 << kNumberSchemaType)))
729 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
730 +
731 + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
732 + return false;
733 +
734 + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
735 + return false;
736 +
737 + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
738 + return false;
739 +
740 + return CreateParallelValidator(context);
741 + }
742 +
743 + bool String(Context& context, const Ch* str, SizeType length, bool) const {
744 + if (!(type_ & (1 << kStringSchemaType)))
745 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
746 +
747 + if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
748 + SizeType count;
749 + if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
750 + if (count < minLength_)
751 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
752 + if (count > maxLength_)
753 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
754 + }
755 + }
756 +
757 + if (pattern_ && !IsPatternMatch(pattern_, str, length))
758 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
759 +
760 + return CreateParallelValidator(context);
761 + }
762 +
763 + bool StartObject(Context& context) const {
764 + if (!(type_ & (1 << kObjectSchemaType)))
765 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
766 +
767 + if (hasDependencies_ || hasRequired_) {
768 + context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
769 + std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
770 + }
771 +
772 + if (patternProperties_) { // pre-allocate schema array
773 + SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
774 + context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
775 + context.patternPropertiesSchemaCount = 0;
776 + std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
777 + }
778 +
779 + return CreateParallelValidator(context);
780 + }
781 +
782 + bool Key(Context& context, const Ch* str, SizeType len, bool) const {
783 + if (patternProperties_) {
784 + context.patternPropertiesSchemaCount = 0;
785 + for (SizeType i = 0; i < patternPropertyCount_; i++)
786 + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
787 + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
788 + context.valueSchema = typeless_;
789 + }
790 + }
791 +
792 + SizeType index;
793 + if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
794 + if (context.patternPropertiesSchemaCount > 0) {
795 + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
796 + context.valueSchema = typeless_;
797 + context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
798 + }
799 + else
800 + context.valueSchema = properties_[index].schema;
801 +
802 + if (context.propertyExist)
803 + context.propertyExist[index] = true;
804 +
805 + return true;
806 + }
807 +
808 + if (additionalPropertiesSchema_) {
809 + if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
810 + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
811 + context.valueSchema = typeless_;
812 + context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
813 + }
814 + else
815 + context.valueSchema = additionalPropertiesSchema_;
816 + return true;
817 + }
818 + else if (additionalProperties_) {
819 + context.valueSchema = typeless_;
820 + return true;
821 + }
822 +
823 + if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
824 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
825 +
826 + return true;
827 + }
828 +
829 + bool EndObject(Context& context, SizeType memberCount) const {
830 + if (hasRequired_)
831 + for (SizeType index = 0; index < propertyCount_; index++)
832 + if (properties_[index].required)
833 + if (!context.propertyExist[index])
834 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
835 +
836 + if (memberCount < minProperties_)
837 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
838 +
839 + if (memberCount > maxProperties_)
840 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
841 +
842 + if (hasDependencies_) {
843 + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
844 + if (context.propertyExist[sourceIndex]) {
845 + if (properties_[sourceIndex].dependencies) {
846 + for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
847 + if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
848 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
849 + }
850 + else if (properties_[sourceIndex].dependenciesSchema)
851 + if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
852 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
853 + }
854 + }
855 +
856 + return true;
857 + }
858 +
859 + bool StartArray(Context& context) const {
860 + if (!(type_ & (1 << kArraySchemaType)))
861 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
862 +
863 + context.arrayElementIndex = 0;
864 + context.inArray = true;
865 +
866 + return CreateParallelValidator(context);
867 + }
868 +
869 + bool EndArray(Context& context, SizeType elementCount) const {
870 + context.inArray = false;
871 +
872 + if (elementCount < minItems_)
873 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
874 +
875 + if (elementCount > maxItems_)
876 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
877 +
878 + return true;
879 + }
880 +
881 + // Generate functions for string literal according to Ch
882 +#define RAPIDJSON_STRING_(name, ...) \
883 + static const ValueType& Get##name##String() {\
884 + static const Ch s[] = { __VA_ARGS__, '\0' };\
885 + static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
886 + return v;\
887 + }
888 +
889 + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
890 + RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
891 + RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
892 + RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
893 + RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
894 + RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
895 + RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
896 + RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
897 + RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
898 + RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
899 + RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
900 + RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
901 + RAPIDJSON_STRING_(Not, 'n', 'o', 't')
902 + RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
903 + RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
904 + RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
905 + RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
906 + RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
907 + RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
908 + RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
909 + RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
910 + RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
911 + RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
912 + RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
913 + RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
914 + RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
915 + RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
916 + RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
917 + RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
918 + RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
919 + RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
920 + RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
921 + RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
922 +
923 +#undef RAPIDJSON_STRING_
924 +
925 +private:
926 + enum SchemaValueType {
927 + kNullSchemaType,
928 + kBooleanSchemaType,
929 + kObjectSchemaType,
930 + kArraySchemaType,
931 + kStringSchemaType,
932 + kNumberSchemaType,
933 + kIntegerSchemaType,
934 + kTotalSchemaType
935 + };
936 +
937 +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
938 + typedef internal::GenericRegex<EncodingType> RegexType;
939 +#elif RAPIDJSON_SCHEMA_USE_STDREGEX
940 + typedef std::basic_regex<Ch> RegexType;
941 +#else
942 + typedef char RegexType;
943 +#endif
944 +
945 + struct SchemaArray {
946 + SchemaArray() : schemas(), count() {}
947 + ~SchemaArray() { AllocatorType::Free(schemas); }
948 + const SchemaType** schemas;
949 + SizeType begin; // begin index of context.validators
950 + SizeType count;
951 + };
952 +
953 + template <typename V1, typename V2>
954 + void AddUniqueElement(V1& a, const V2& v) {
955 + for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
956 + if (*itr == v)
957 + return;
958 + V1 c(v, *allocator_);
959 + a.PushBack(c, *allocator_);
960 + }
961 +
962 + static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
963 + typename ValueType::ConstMemberIterator itr = value.FindMember(name);
964 + return itr != value.MemberEnd() ? &(itr->value) : 0;
965 + }
966 +
967 + static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
968 + if (const ValueType* v = GetMember(value, name))
969 + if (v->IsBool())
970 + out = v->GetBool();
971 + }
972 +
973 + static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
974 + if (const ValueType* v = GetMember(value, name))
975 + if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
976 + out = static_cast<SizeType>(v->GetUint64());
977 + }
978 +
979 + void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
980 + if (const ValueType* v = GetMember(value, name)) {
981 + if (v->IsArray() && v->Size() > 0) {
982 + PointerType q = p.Append(name, allocator_);
983 + out.count = v->Size();
984 + out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
985 + memset(out.schemas, 0, sizeof(Schema*)* out.count);
986 + for (SizeType i = 0; i < out.count; i++)
987 + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
988 + out.begin = validatorCount_;
989 + validatorCount_ += out.count;
990 + }
991 + }
992 + }
993 +
994 +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
995 + template <typename ValueType>
996 + RegexType* CreatePattern(const ValueType& value) {
997 + if (value.IsString()) {
998 + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
999 + if (!r->IsValid()) {
1000 + r->~RegexType();
1001 + AllocatorType::Free(r);
1002 + r = 0;
1003 + }
1004 + return r;
1005 + }
1006 + return 0;
1007 + }
1008 +
1009 + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
1010 + GenericRegexSearch<RegexType> rs(*pattern);
1011 + return rs.Search(str);
1012 + }
1013 +#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1014 + template <typename ValueType>
1015 + RegexType* CreatePattern(const ValueType& value) {
1016 + if (value.IsString())
1017 + try {
1018 + return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1019 + }
1020 + catch (const std::regex_error&) {
1021 + }
1022 + return 0;
1023 + }
1024 +
1025 + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
1026 + std::match_results<const Ch*> r;
1027 + return std::regex_search(str, str + length, r, *pattern);
1028 + }
1029 +#else
1030 + template <typename ValueType>
1031 + RegexType* CreatePattern(const ValueType&) { return 0; }
1032 +
1033 + static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
1034 +#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1035 +
1036 + void AddType(const ValueType& type) {
1037 + if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1038 + else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1039 + else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1040 + else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1041 + else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1042 + else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1043 + else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1044 + }
1045 +
1046 + bool CreateParallelValidator(Context& context) const {
1047 + if (enum_ || context.arrayUniqueness)
1048 + context.hasher = context.factory.CreateHasher();
1049 +
1050 + if (validatorCount_) {
1051 + RAPIDJSON_ASSERT(context.validators == 0);
1052 + context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
1053 + context.validatorCount = validatorCount_;
1054 +
1055 + if (allOf_.schemas)
1056 + CreateSchemaValidators(context, allOf_);
1057 +
1058 + if (anyOf_.schemas)
1059 + CreateSchemaValidators(context, anyOf_);
1060 +
1061 + if (oneOf_.schemas)
1062 + CreateSchemaValidators(context, oneOf_);
1063 +
1064 + if (not_)
1065 + context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
1066 +
1067 + if (hasSchemaDependencies_) {
1068 + for (SizeType i = 0; i < propertyCount_; i++)
1069 + if (properties_[i].dependenciesSchema)
1070 + context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
1071 + }
1072 + }
1073 +
1074 + return true;
1075 + }
1076 +
1077 + void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
1078 + for (SizeType i = 0; i < schemas.count; i++)
1079 + context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
1080 + }
1081 +
1082 + // O(n)
1083 + bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
1084 + SizeType len = name.GetStringLength();
1085 + const Ch* str = name.GetString();
1086 + for (SizeType index = 0; index < propertyCount_; index++)
1087 + if (properties_[index].name.GetStringLength() == len &&
1088 + (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
1089 + {
1090 + *outIndex = index;
1091 + return true;
1092 + }
1093 + return false;
1094 + }
1095 +
1096 + bool CheckInt(Context& context, int64_t i) const {
1097 + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1098 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1099 +
1100 + if (!minimum_.IsNull()) {
1101 + if (minimum_.IsInt64()) {
1102 + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
1103 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1104 + }
1105 + else if (minimum_.IsUint64()) {
1106 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
1107 + }
1108 + else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1109 + return false;
1110 + }
1111 +
1112 + if (!maximum_.IsNull()) {
1113 + if (maximum_.IsInt64()) {
1114 + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
1115 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1116 + }
1117 + else if (maximum_.IsUint64()) { }
1118 + /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
1119 + else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1120 + return false;
1121 + }
1122 +
1123 + if (!multipleOf_.IsNull()) {
1124 + if (multipleOf_.IsUint64()) {
1125 + if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
1126 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1127 + }
1128 + else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1129 + return false;
1130 + }
1131 +
1132 + return true;
1133 + }
1134 +
1135 + bool CheckUint(Context& context, uint64_t i) const {
1136 + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1137 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1138 +
1139 + if (!minimum_.IsNull()) {
1140 + if (minimum_.IsUint64()) {
1141 + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
1142 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1143 + }
1144 + else if (minimum_.IsInt64())
1145 + /* do nothing */; // i >= 0 > minimum.Getint64()
1146 + else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1147 + return false;
1148 + }
1149 +
1150 + if (!maximum_.IsNull()) {
1151 + if (maximum_.IsUint64()) {
1152 + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
1153 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1154 + }
1155 + else if (maximum_.IsInt64())
1156 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
1157 + else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1158 + return false;
1159 + }
1160 +
1161 + if (!multipleOf_.IsNull()) {
1162 + if (multipleOf_.IsUint64()) {
1163 + if (i % multipleOf_.GetUint64() != 0)
1164 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1165 + }
1166 + else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1167 + return false;
1168 + }
1169 +
1170 + return true;
1171 + }
1172 +
1173 + bool CheckDoubleMinimum(Context& context, double d) const {
1174 + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
1175 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1176 + return true;
1177 + }
1178 +
1179 + bool CheckDoubleMaximum(Context& context, double d) const {
1180 + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
1181 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1182 + return true;
1183 + }
1184 +
1185 + bool CheckDoubleMultipleOf(Context& context, double d) const {
1186 + double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1187 + double q = std::floor(a / b);
1188 + double r = a - q * b;
1189 + if (r > 0.0)
1190 + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1191 + return true;
1192 + }
1193 +
1194 + struct Property {
1195 + Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
1196 + ~Property() { AllocatorType::Free(dependencies); }
1197 + SValue name;
1198 + const SchemaType* schema;
1199 + const SchemaType* dependenciesSchema;
1200 + SizeType dependenciesValidatorIndex;
1201 + bool* dependencies;
1202 + bool required;
1203 + };
1204 +
1205 + struct PatternProperty {
1206 + PatternProperty() : schema(), pattern() {}
1207 + ~PatternProperty() {
1208 + if (pattern) {
1209 + pattern->~RegexType();
1210 + AllocatorType::Free(pattern);
1211 + }
1212 + }
1213 + const SchemaType* schema;
1214 + RegexType* pattern;
1215 + };
1216 +
1217 + AllocatorType* allocator_;
1218 + const SchemaType* typeless_;
1219 + uint64_t* enum_;
1220 + SizeType enumCount_;
1221 + SchemaArray allOf_;
1222 + SchemaArray anyOf_;
1223 + SchemaArray oneOf_;
1224 + const SchemaType* not_;
1225 + unsigned type_; // bitmask of kSchemaType
1226 + SizeType validatorCount_;
1227 + SizeType notValidatorIndex_;
1228 +
1229 + Property* properties_;
1230 + const SchemaType* additionalPropertiesSchema_;
1231 + PatternProperty* patternProperties_;
1232 + SizeType patternPropertyCount_;
1233 + SizeType propertyCount_;
1234 + SizeType minProperties_;
1235 + SizeType maxProperties_;
1236 + bool additionalProperties_;
1237 + bool hasDependencies_;
1238 + bool hasRequired_;
1239 + bool hasSchemaDependencies_;
1240 +
1241 + const SchemaType* additionalItemsSchema_;
1242 + const SchemaType* itemsList_;
1243 + const SchemaType** itemsTuple_;
1244 + SizeType itemsTupleCount_;
1245 + SizeType minItems_;
1246 + SizeType maxItems_;
1247 + bool additionalItems_;
1248 + bool uniqueItems_;
1249 +
1250 + RegexType* pattern_;
1251 + SizeType minLength_;
1252 + SizeType maxLength_;
1253 +
1254 + SValue minimum_;
1255 + SValue maximum_;
1256 + SValue multipleOf_;
1257 + bool exclusiveMinimum_;
1258 + bool exclusiveMaximum_;
1259 +};
1260 +
1261 +template<typename Stack, typename Ch>
1262 +struct TokenHelper {
1263 + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1264 + *documentStack.template Push<Ch>() = '/';
1265 + char buffer[21];
1266 + size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1267 + for (size_t i = 0; i < length; i++)
1268 + *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
1269 + }
1270 +};
1271 +
1272 +// Partial specialized version for char to prevent buffer copying.
1273 +template <typename Stack>
1274 +struct TokenHelper<Stack, char> {
1275 + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1276 + if (sizeof(SizeType) == 4) {
1277 + char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
1278 + *buffer++ = '/';
1279 + const char* end = internal::u32toa(index, buffer);
1280 + documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
1281 + }
1282 + else {
1283 + char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
1284 + *buffer++ = '/';
1285 + const char* end = internal::u64toa(index, buffer);
1286 + documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
1287 + }
1288 + }
1289 +};
1290 +
1291 +} // namespace internal
1292 +
1293 +///////////////////////////////////////////////////////////////////////////////
1294 +// IGenericRemoteSchemaDocumentProvider
1295 +
1296 +template <typename SchemaDocumentType>
1297 +class IGenericRemoteSchemaDocumentProvider {
1298 +public:
1299 + typedef typename SchemaDocumentType::Ch Ch;
1300 +
1301 + virtual ~IGenericRemoteSchemaDocumentProvider() {}
1302 + virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
1303 +};
1304 +
1305 +///////////////////////////////////////////////////////////////////////////////
1306 +// GenericSchemaDocument
1307 +
1308 +//! JSON schema document.
1309 +/*!
1310 + A JSON schema document is a compiled version of a JSON schema.
1311 + It is basically a tree of internal::Schema.
1312 +
1313 + \note This is an immutable class (i.e. its instance cannot be modified after construction).
1314 + \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
1315 + \tparam Allocator Allocator type for allocating memory of this document.
1316 +*/
1317 +template <typename ValueT, typename Allocator = CrtAllocator>
1318 +class GenericSchemaDocument {
1319 +public:
1320 + typedef ValueT ValueType;
1321 + typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
1322 + typedef Allocator AllocatorType;
1323 + typedef typename ValueType::EncodingType EncodingType;
1324 + typedef typename EncodingType::Ch Ch;
1325 + typedef internal::Schema<GenericSchemaDocument> SchemaType;
1326 + typedef GenericPointer<ValueType, Allocator> PointerType;
1327 + friend class internal::Schema<GenericSchemaDocument>;
1328 + template <typename, typename, typename>
1329 + friend class GenericSchemaValidator;
1330 +
1331 + //! Constructor.
1332 + /*!
1333 + Compile a JSON document into schema document.
1334 +
1335 + \param document A JSON document as source.
1336 + \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
1337 + \param allocator An optional allocator instance for allocating memory. Can be null.
1338 + */
1339 + explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
1340 + remoteProvider_(remoteProvider),
1341 + allocator_(allocator),
1342 + ownAllocator_(),
1343 + root_(),
1344 + typeless_(),
1345 + schemaMap_(allocator, kInitialSchemaMapSize),
1346 + schemaRef_(allocator, kInitialSchemaRefSize)
1347 + {
1348 + if (!allocator_)
1349 + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
1350 +
1351 + typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
1352 + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
1353 +
1354 + // Generate root schema, it will call CreateSchema() to create sub-schemas,
1355 + // And call AddRefSchema() if there are $ref.
1356 + CreateSchemaRecursive(&root_, PointerType(), document, document);
1357 +
1358 + // Resolve $ref
1359 + while (!schemaRef_.Empty()) {
1360 + SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1361 + if (const SchemaType* s = GetSchema(refEntry->target)) {
1362 + if (refEntry->schema)
1363 + *refEntry->schema = s;
1364 +
1365 + // Create entry in map if not exist
1366 + if (!GetSchema(refEntry->source)) {
1367 + new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
1368 + }
1369 + }
1370 + else if (refEntry->schema)
1371 + *refEntry->schema = typeless_;
1372 +
1373 + refEntry->~SchemaRefEntry();
1374 + }
1375 +
1376 + RAPIDJSON_ASSERT(root_ != 0);
1377 +
1378 + schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
1379 + }
1380 +
1381 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1382 + //! Move constructor in C++11
1383 + GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
1384 + remoteProvider_(rhs.remoteProvider_),
1385 + allocator_(rhs.allocator_),
1386 + ownAllocator_(rhs.ownAllocator_),
1387 + root_(rhs.root_),
1388 + typeless_(rhs.typeless_),
1389 + schemaMap_(std::move(rhs.schemaMap_)),
1390 + schemaRef_(std::move(rhs.schemaRef_))
1391 + {
1392 + rhs.remoteProvider_ = 0;
1393 + rhs.allocator_ = 0;
1394 + rhs.ownAllocator_ = 0;
1395 + rhs.typeless_ = 0;
1396 + }
1397 +#endif
1398 +
1399 + //! Destructor
1400 + ~GenericSchemaDocument() {
1401 + while (!schemaMap_.Empty())
1402 + schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1403 +
1404 + if (typeless_) {
1405 + typeless_->~SchemaType();
1406 + Allocator::Free(typeless_);
1407 + }
1408 +
1409 + RAPIDJSON_DELETE(ownAllocator_);
1410 + }
1411 +
1412 + //! Get the root schema.
1413 + const SchemaType& GetRoot() const { return *root_; }
1414 +
1415 +private:
1416 + //! Prohibit copying
1417 + GenericSchemaDocument(const GenericSchemaDocument&);
1418 + //! Prohibit assignment
1419 + GenericSchemaDocument& operator=(const GenericSchemaDocument&);
1420 +
1421 + struct SchemaRefEntry {
1422 + SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
1423 + PointerType source;
1424 + PointerType target;
1425 + const SchemaType** schema;
1426 + };
1427 +
1428 + struct SchemaEntry {
1429 + SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
1430 + ~SchemaEntry() {
1431 + if (owned) {
1432 + schema->~SchemaType();
1433 + Allocator::Free(schema);
1434 + }
1435 + }
1436 + PointerType pointer;
1437 + SchemaType* schema;
1438 + bool owned;
1439 + };
1440 +
1441 + void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1442 + if (schema)
1443 + *schema = typeless_;
1444 +
1445 + if (v.GetType() == kObjectType) {
1446 + const SchemaType* s = GetSchema(pointer);
1447 + if (!s)
1448 + CreateSchema(schema, pointer, v, document);
1449 +
1450 + for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1451 + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
1452 + }
1453 + else if (v.GetType() == kArrayType)
1454 + for (SizeType i = 0; i < v.Size(); i++)
1455 + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
1456 + }
1457 +
1458 + void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1459 + RAPIDJSON_ASSERT(pointer.IsValid());
1460 + if (v.IsObject()) {
1461 + if (!HandleRefSchema(pointer, schema, v, document)) {
1462 + SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
1463 + new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
1464 + if (schema)
1465 + *schema = s;
1466 + }
1467 + }
1468 + }
1469 +
1470 + bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
1471 + static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
1472 + static const ValueType kRefValue(kRefString, 4);
1473 +
1474 + typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1475 + if (itr == v.MemberEnd())
1476 + return false;
1477 +
1478 + if (itr->value.IsString()) {
1479 + SizeType len = itr->value.GetStringLength();
1480 + if (len > 0) {
1481 + const Ch* s = itr->value.GetString();
1482 + SizeType i = 0;
1483 + while (i < len && s[i] != '#') // Find the first #
1484 + i++;
1485 +
1486 + if (i > 0) { // Remote reference, resolve immediately
1487 + if (remoteProvider_) {
1488 + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
1489 + PointerType pointer(&s[i], len - i, allocator_);
1490 + if (pointer.IsValid()) {
1491 + if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1492 + if (schema)
1493 + *schema = sc;
1494 + return true;
1495 + }
1496 + }
1497 + }
1498 + }
1499 + }
1500 + else if (s[i] == '#') { // Local reference, defer resolution
1501 + PointerType pointer(&s[i], len - i, allocator_);
1502 + if (pointer.IsValid()) {
1503 + if (const ValueType* nv = pointer.Get(document))
1504 + if (HandleRefSchema(source, schema, *nv, document))
1505 + return true;
1506 +
1507 + new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
1508 + return true;
1509 + }
1510 + }
1511 + }
1512 + }
1513 + return false;
1514 + }
1515 +
1516 + const SchemaType* GetSchema(const PointerType& pointer) const {
1517 + for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1518 + if (pointer == target->pointer)
1519 + return target->schema;
1520 + return 0;
1521 + }
1522 +
1523 + PointerType GetPointer(const SchemaType* schema) const {
1524 + for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1525 + if (schema == target->schema)
1526 + return target->pointer;
1527 + return PointerType();
1528 + }
1529 +
1530 + const SchemaType* GetTypeless() const { return typeless_; }
1531 +
1532 + static const size_t kInitialSchemaMapSize = 64;
1533 + static const size_t kInitialSchemaRefSize = 64;
1534 +
1535 + IRemoteSchemaDocumentProviderType* remoteProvider_;
1536 + Allocator *allocator_;
1537 + Allocator *ownAllocator_;
1538 + const SchemaType* root_; //!< Root schema.
1539 + SchemaType* typeless_;
1540 + internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
1541 + internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
1542 +};
1543 +
1544 +//! GenericSchemaDocument using Value type.
1545 +typedef GenericSchemaDocument<Value> SchemaDocument;
1546 +//! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
1547 +typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
1548 +
1549 +///////////////////////////////////////////////////////////////////////////////
1550 +// GenericSchemaValidator
1551 +
1552 +//! JSON Schema Validator.
1553 +/*!
1554 + A SAX style JSON schema validator.
1555 + It uses a \c GenericSchemaDocument to validate SAX events.
1556 + It delegates the incoming SAX events to an output handler.
1557 + The default output handler does nothing.
1558 + It can be reused multiple times by calling \c Reset().
1559 +
1560 + \tparam SchemaDocumentType Type of schema document.
1561 + \tparam OutputHandler Type of output handler. Default handler does nothing.
1562 + \tparam StateAllocator Allocator for storing the internal validation states.
1563 +*/
1564 +template <
1565 + typename SchemaDocumentType,
1566 + typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
1567 + typename StateAllocator = CrtAllocator>
1568 +class GenericSchemaValidator :
1569 + public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
1570 + public internal::ISchemaValidator
1571 +{
1572 +public:
1573 + typedef typename SchemaDocumentType::SchemaType SchemaType;
1574 + typedef typename SchemaDocumentType::PointerType PointerType;
1575 + typedef typename SchemaType::EncodingType EncodingType;
1576 + typedef typename EncodingType::Ch Ch;
1577 +
1578 + //! Constructor without output handler.
1579 + /*!
1580 + \param schemaDocument The schema document to conform to.
1581 + \param allocator Optional allocator for storing internal validation states.
1582 + \param schemaStackCapacity Optional initial capacity of schema path stack.
1583 + \param documentStackCapacity Optional initial capacity of document path stack.
1584 + */
1585 + GenericSchemaValidator(
1586 + const SchemaDocumentType& schemaDocument,
1587 + StateAllocator* allocator = 0,
1588 + size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1589 + size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1590 + :
1591 + schemaDocument_(&schemaDocument),
1592 + root_(schemaDocument.GetRoot()),
1593 + stateAllocator_(allocator),
1594 + ownStateAllocator_(0),
1595 + schemaStack_(allocator, schemaStackCapacity),
1596 + documentStack_(allocator, documentStackCapacity),
1597 + outputHandler_(CreateNullHandler()),
1598 + valid_(true)
1599 +#if RAPIDJSON_SCHEMA_VERBOSE
1600 + , depth_(0)
1601 +#endif
1602 + {
1603 + }
1604 +
1605 + //! Constructor with output handler.
1606 + /*!
1607 + \param schemaDocument The schema document to conform to.
1608 + \param allocator Optional allocator for storing internal validation states.
1609 + \param schemaStackCapacity Optional initial capacity of schema path stack.
1610 + \param documentStackCapacity Optional initial capacity of document path stack.
1611 + */
1612 + GenericSchemaValidator(
1613 + const SchemaDocumentType& schemaDocument,
1614 + OutputHandler& outputHandler,
1615 + StateAllocator* allocator = 0,
1616 + size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1617 + size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1618 + :
1619 + schemaDocument_(&schemaDocument),
1620 + root_(schemaDocument.GetRoot()),
1621 + stateAllocator_(allocator),
1622 + ownStateAllocator_(0),
1623 + schemaStack_(allocator, schemaStackCapacity),
1624 + documentStack_(allocator, documentStackCapacity),
1625 + outputHandler_(outputHandler),
1626 + nullHandler_(0),
1627 + valid_(true)
1628 +#if RAPIDJSON_SCHEMA_VERBOSE
1629 + , depth_(0)
1630 +#endif
1631 + {
1632 + }
1633 +
1634 + //! Destructor.
1635 + ~GenericSchemaValidator() {
1636 + Reset();
1637 + if (nullHandler_) {
1638 + nullHandler_->~OutputHandler();
1639 + StateAllocator::Free(nullHandler_);
1640 + }
1641 + RAPIDJSON_DELETE(ownStateAllocator_);
1642 + }
1643 +
1644 + //! Reset the internal states.
1645 + void Reset() {
1646 + while (!schemaStack_.Empty())
1647 + PopSchema();
1648 + documentStack_.Clear();
1649 + valid_ = true;
1650 + }
1651 +
1652 + //! Checks whether the current state is valid.
1653 + // Implementation of ISchemaValidator
1654 + virtual bool IsValid() const { return valid_; }
1655 +
1656 + //! Gets the JSON pointer pointed to the invalid schema.
1657 + PointerType GetInvalidSchemaPointer() const {
1658 + return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
1659 + }
1660 +
1661 + //! Gets the keyword of invalid schema.
1662 + const Ch* GetInvalidSchemaKeyword() const {
1663 + return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1664 + }
1665 +
1666 + //! Gets the JSON pointer pointed to the invalid value.
1667 + PointerType GetInvalidDocumentPointer() const {
1668 + return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
1669 + }
1670 +
1671 +#if RAPIDJSON_SCHEMA_VERBOSE
1672 +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
1673 +RAPIDJSON_MULTILINEMACRO_BEGIN\
1674 + *documentStack_.template Push<Ch>() = '\0';\
1675 + documentStack_.template Pop<Ch>(1);\
1676 + internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
1677 +RAPIDJSON_MULTILINEMACRO_END
1678 +#else
1679 +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
1680 +#endif
1681 +
1682 +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
1683 + if (!valid_) return false; \
1684 + if (!BeginValue() || !CurrentSchema().method arg1) {\
1685 + RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
1686 + return valid_ = false;\
1687 + }
1688 +
1689 +#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
1690 + for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
1691 + if (context->hasher)\
1692 + static_cast<HasherType*>(context->hasher)->method arg2;\
1693 + if (context->validators)\
1694 + for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
1695 + static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
1696 + if (context->patternPropertiesValidators)\
1697 + for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
1698 + static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
1699 + }
1700 +
1701 +#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
1702 + return valid_ = EndValue() && outputHandler_.method arg2
1703 +
1704 +#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
1705 + RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
1706 + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
1707 + RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
1708 +
1709 + bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
1710 + bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
1711 + bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
1712 + bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
1713 + bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
1714 + bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
1715 + bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
1716 + bool RawNumber(const Ch* str, SizeType length, bool copy)
1717 + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
1718 + bool String(const Ch* str, SizeType length, bool copy)
1719 + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
1720 +
1721 + bool StartObject() {
1722 + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
1723 + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
1724 + return valid_ = outputHandler_.StartObject();
1725 + }
1726 +
1727 + bool Key(const Ch* str, SizeType len, bool copy) {
1728 + if (!valid_) return false;
1729 + AppendToken(str, len);
1730 + if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
1731 + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
1732 + return valid_ = outputHandler_.Key(str, len, copy);
1733 + }
1734 +
1735 + bool EndObject(SizeType memberCount) {
1736 + if (!valid_) return false;
1737 + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
1738 + if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
1739 + RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
1740 + }
1741 +
1742 + bool StartArray() {
1743 + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
1744 + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
1745 + return valid_ = outputHandler_.StartArray();
1746 + }
1747 +
1748 + bool EndArray(SizeType elementCount) {
1749 + if (!valid_) return false;
1750 + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
1751 + if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
1752 + RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
1753 + }
1754 +
1755 +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
1756 +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
1757 +#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
1758 +#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
1759 +
1760 + // Implementation of ISchemaStateFactory<SchemaType>
1761 + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
1762 + return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
1763 +#if RAPIDJSON_SCHEMA_VERBOSE
1764 + depth_ + 1,
1765 +#endif
1766 + &GetStateAllocator());
1767 + }
1768 +
1769 + virtual void DestroySchemaValidator(ISchemaValidator* validator) {
1770 + GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
1771 + v->~GenericSchemaValidator();
1772 + StateAllocator::Free(v);
1773 + }
1774 +
1775 + virtual void* CreateHasher() {
1776 + return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
1777 + }
1778 +
1779 + virtual uint64_t GetHashCode(void* hasher) {
1780 + return static_cast<HasherType*>(hasher)->GetHashCode();
1781 + }
1782 +
1783 + virtual void DestroryHasher(void* hasher) {
1784 + HasherType* h = static_cast<HasherType*>(hasher);
1785 + h->~HasherType();
1786 + StateAllocator::Free(h);
1787 + }
1788 +
1789 + virtual void* MallocState(size_t size) {
1790 + return GetStateAllocator().Malloc(size);
1791 + }
1792 +
1793 + virtual void FreeState(void* p) {
1794 + StateAllocator::Free(p);
1795 + }
1796 +
1797 +private:
1798 + typedef typename SchemaType::Context Context;
1799 + typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
1800 + typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
1801 +
1802 + GenericSchemaValidator(
1803 + const SchemaDocumentType& schemaDocument,
1804 + const SchemaType& root,
1805 +#if RAPIDJSON_SCHEMA_VERBOSE
1806 + unsigned depth,
1807 +#endif
1808 + StateAllocator* allocator = 0,
1809 + size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1810 + size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1811 + :
1812 + schemaDocument_(&schemaDocument),
1813 + root_(root),
1814 + stateAllocator_(allocator),
1815 + ownStateAllocator_(0),
1816 + schemaStack_(allocator, schemaStackCapacity),
1817 + documentStack_(allocator, documentStackCapacity),
1818 + outputHandler_(CreateNullHandler()),
1819 + valid_(true)
1820 +#if RAPIDJSON_SCHEMA_VERBOSE
1821 + , depth_(depth)
1822 +#endif
1823 + {
1824 + }
1825 +
1826 + StateAllocator& GetStateAllocator() {
1827 + if (!stateAllocator_)
1828 + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
1829 + return *stateAllocator_;
1830 + }
1831 +
1832 + bool BeginValue() {
1833 + if (schemaStack_.Empty())
1834 + PushSchema(root_);
1835 + else {
1836 + if (CurrentContext().inArray)
1837 + internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
1838 +
1839 + if (!CurrentSchema().BeginValue(CurrentContext()))
1840 + return false;
1841 +
1842 + SizeType count = CurrentContext().patternPropertiesSchemaCount;
1843 + const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
1844 + typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
1845 + bool valueUniqueness = CurrentContext().valueUniqueness;
1846 + RAPIDJSON_ASSERT(CurrentContext().valueSchema);
1847 + PushSchema(*CurrentContext().valueSchema);
1848 +
1849 + if (count > 0) {
1850 + CurrentContext().objectPatternValidatorType = patternValidatorType;
1851 + ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
1852 + SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
1853 + va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
1854 + for (SizeType i = 0; i < count; i++)
1855 + va[validatorCount++] = CreateSchemaValidator(*sa[i]);
1856 + }
1857 +
1858 + CurrentContext().arrayUniqueness = valueUniqueness;
1859 + }
1860 + return true;
1861 + }
1862 +
1863 + bool EndValue() {
1864 + if (!CurrentSchema().EndValue(CurrentContext()))
1865 + return false;
1866 +
1867 +#if RAPIDJSON_SCHEMA_VERBOSE
1868 + GenericStringBuffer<EncodingType> sb;
1869 + schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
1870 +
1871 + *documentStack_.template Push<Ch>() = '\0';
1872 + documentStack_.template Pop<Ch>(1);
1873 + internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
1874 +#endif
1875 +
1876 + uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
1877 +
1878 + PopSchema();
1879 +
1880 + if (!schemaStack_.Empty()) {
1881 + Context& context = CurrentContext();
1882 + if (context.valueUniqueness) {
1883 + HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
1884 + if (!a)
1885 + CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
1886 + for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
1887 + if (itr->GetUint64() == h)
1888 + RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
1889 + a->PushBack(h, GetStateAllocator());
1890 + }
1891 + }
1892 +
1893 + // Remove the last token of document pointer
1894 + while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
1895 + ;
1896 +
1897 + return true;
1898 + }
1899 +
1900 + void AppendToken(const Ch* str, SizeType len) {
1901 + documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
1902 + *documentStack_.template PushUnsafe<Ch>() = '/';
1903 + for (SizeType i = 0; i < len; i++) {
1904 + if (str[i] == '~') {
1905 + *documentStack_.template PushUnsafe<Ch>() = '~';
1906 + *documentStack_.template PushUnsafe<Ch>() = '0';
1907 + }
1908 + else if (str[i] == '/') {
1909 + *documentStack_.template PushUnsafe<Ch>() = '~';
1910 + *documentStack_.template PushUnsafe<Ch>() = '1';
1911 + }
1912 + else
1913 + *documentStack_.template PushUnsafe<Ch>() = str[i];
1914 + }
1915 + }
1916 +
1917 + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
1918 +
1919 + RAPIDJSON_FORCEINLINE void PopSchema() {
1920 + Context* c = schemaStack_.template Pop<Context>(1);
1921 + if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
1922 + a->~HashCodeArray();
1923 + StateAllocator::Free(a);
1924 + }
1925 + c->~Context();
1926 + }
1927 +
1928 + const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
1929 + Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
1930 + const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
1931 +
1932 + OutputHandler& CreateNullHandler() {
1933 + return *(nullHandler_ = new (GetStateAllocator().Malloc(sizeof(OutputHandler))) OutputHandler);
1934 + }
1935 +
1936 + static const size_t kDefaultSchemaStackCapacity = 1024;
1937 + static const size_t kDefaultDocumentStackCapacity = 256;
1938 + const SchemaDocumentType* schemaDocument_;
1939 + const SchemaType& root_;
1940 + StateAllocator* stateAllocator_;
1941 + StateAllocator* ownStateAllocator_;
1942 + internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
1943 + internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
1944 + OutputHandler& outputHandler_;
1945 + OutputHandler* nullHandler_;
1946 + bool valid_;
1947 +#if RAPIDJSON_SCHEMA_VERBOSE
1948 + unsigned depth_;
1949 +#endif
1950 +};
1951 +
1952 +typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
1953 +
1954 +///////////////////////////////////////////////////////////////////////////////
1955 +// SchemaValidatingReader
1956 +
1957 +//! A helper class for parsing with validation.
1958 +/*!
1959 + This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
1960 +
1961 + \tparam parseFlags Combination of \ref ParseFlag.
1962 + \tparam InputStream Type of input stream, implementing Stream concept.
1963 + \tparam SourceEncoding Encoding of the input stream.
1964 + \tparam SchemaDocumentType Type of schema document.
1965 + \tparam StackAllocator Allocator type for stack.
1966 +*/
1967 +template <
1968 + unsigned parseFlags,
1969 + typename InputStream,
1970 + typename SourceEncoding,
1971 + typename SchemaDocumentType = SchemaDocument,
1972 + typename StackAllocator = CrtAllocator>
1973 +class SchemaValidatingReader {
1974 +public:
1975 + typedef typename SchemaDocumentType::PointerType PointerType;
1976 + typedef typename InputStream::Ch Ch;
1977 +
1978 + //! Constructor
1979 + /*!
1980 + \param is Input stream.
1981 + \param sd Schema document.
1982 + */
1983 + SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
1984 +
1985 + template <typename Handler>
1986 + bool operator()(Handler& handler) {
1987 + GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
1988 + GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
1989 + parseResult_ = reader.template Parse<parseFlags>(is_, validator);
1990 +
1991 + isValid_ = validator.IsValid();
1992 + if (isValid_) {
1993 + invalidSchemaPointer_ = PointerType();
1994 + invalidSchemaKeyword_ = 0;
1995 + invalidDocumentPointer_ = PointerType();
1996 + }
1997 + else {
1998 + invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
1999 + invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
2000 + invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
2001 + }
2002 +
2003 + return parseResult_;
2004 + }
2005 +
2006 + const ParseResult& GetParseResult() const { return parseResult_; }
2007 + bool IsValid() const { return isValid_; }
2008 + const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
2009 + const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
2010 + const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
2011 +
2012 +private:
2013 + InputStream& is_;
2014 + const SchemaDocumentType& sd_;
2015 +
2016 + ParseResult parseResult_;
2017 + PointerType invalidSchemaPointer_;
2018 + const Ch* invalidSchemaKeyword_;
2019 + PointerType invalidDocumentPointer_;
2020 + bool isValid_;
2021 +};
2022 +
2023 +RAPIDJSON_NAMESPACE_END
2024 +RAPIDJSON_DIAG_POP
2025 +
2026 +#endif // RAPIDJSON_SCHEMA_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#include "rapidjson.h"
16 +
17 +#ifndef RAPIDJSON_STREAM_H_
18 +#define RAPIDJSON_STREAM_H_
19 +
20 +#include "encodings.h"
21 +
22 +RAPIDJSON_NAMESPACE_BEGIN
23 +
24 +///////////////////////////////////////////////////////////////////////////////
25 +// Stream
26 +
27 +/*! \class rapidjson::Stream
28 + \brief Concept for reading and writing characters.
29 +
30 + For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
31 +
32 + For write-only stream, only need to implement Put() and Flush().
33 +
34 +\code
35 +concept Stream {
36 + typename Ch; //!< Character type of the stream.
37 +
38 + //! Read the current character from stream without moving the read cursor.
39 + Ch Peek() const;
40 +
41 + //! Read the current character from stream and moving the read cursor to next character.
42 + Ch Take();
43 +
44 + //! Get the current read cursor.
45 + //! \return Number of characters read from start.
46 + size_t Tell();
47 +
48 + //! Begin writing operation at the current read pointer.
49 + //! \return The begin writer pointer.
50 + Ch* PutBegin();
51 +
52 + //! Write a character.
53 + void Put(Ch c);
54 +
55 + //! Flush the buffer.
56 + void Flush();
57 +
58 + //! End the writing operation.
59 + //! \param begin The begin write pointer returned by PutBegin().
60 + //! \return Number of characters written.
61 + size_t PutEnd(Ch* begin);
62 +}
63 +\endcode
64 +*/
65 +
66 +//! Provides additional information for stream.
67 +/*!
68 + By using traits pattern, this type provides a default configuration for stream.
69 + For custom stream, this type can be specialized for other configuration.
70 + See TEST(Reader, CustomStringStream) in readertest.cpp for example.
71 +*/
72 +template<typename Stream>
73 +struct StreamTraits {
74 + //! Whether to make local copy of stream for optimization during parsing.
75 + /*!
76 + By default, for safety, streams do not use local copy optimization.
77 + Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
78 + */
79 + enum { copyOptimization = 0 };
80 +};
81 +
82 +//! Reserve n characters for writing to a stream.
83 +template<typename Stream>
84 +inline void PutReserve(Stream& stream, size_t count) {
85 + (void)stream;
86 + (void)count;
87 +}
88 +
89 +//! Write character to a stream, presuming buffer is reserved.
90 +template<typename Stream>
91 +inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
92 + stream.Put(c);
93 +}
94 +
95 +//! Put N copies of a character to a stream.
96 +template<typename Stream, typename Ch>
97 +inline void PutN(Stream& stream, Ch c, size_t n) {
98 + PutReserve(stream, n);
99 + for (size_t i = 0; i < n; i++)
100 + PutUnsafe(stream, c);
101 +}
102 +
103 +///////////////////////////////////////////////////////////////////////////////
104 +// StringStream
105 +
106 +//! Read-only string stream.
107 +/*! \note implements Stream concept
108 +*/
109 +template <typename Encoding>
110 +struct GenericStringStream {
111 + typedef typename Encoding::Ch Ch;
112 +
113 + GenericStringStream(const Ch *src) : src_(src), head_(src) {}
114 +
115 + Ch Peek() const { return *src_; }
116 + Ch Take() { return *src_++; }
117 + size_t Tell() const { return static_cast<size_t>(src_ - head_); }
118 +
119 + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
120 + void Put(Ch) { RAPIDJSON_ASSERT(false); }
121 + void Flush() { RAPIDJSON_ASSERT(false); }
122 + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
123 +
124 + const Ch* src_; //!< Current read position.
125 + const Ch* head_; //!< Original head of the string.
126 +};
127 +
128 +template <typename Encoding>
129 +struct StreamTraits<GenericStringStream<Encoding> > {
130 + enum { copyOptimization = 1 };
131 +};
132 +
133 +//! String stream with UTF8 encoding.
134 +typedef GenericStringStream<UTF8<> > StringStream;
135 +
136 +///////////////////////////////////////////////////////////////////////////////
137 +// InsituStringStream
138 +
139 +//! A read-write string stream.
140 +/*! This string stream is particularly designed for in-situ parsing.
141 + \note implements Stream concept
142 +*/
143 +template <typename Encoding>
144 +struct GenericInsituStringStream {
145 + typedef typename Encoding::Ch Ch;
146 +
147 + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
148 +
149 + // Read
150 + Ch Peek() { return *src_; }
151 + Ch Take() { return *src_++; }
152 + size_t Tell() { return static_cast<size_t>(src_ - head_); }
153 +
154 + // Write
155 + void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
156 +
157 + Ch* PutBegin() { return dst_ = src_; }
158 + size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
159 + void Flush() {}
160 +
161 + Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
162 + void Pop(size_t count) { dst_ -= count; }
163 +
164 + Ch* src_;
165 + Ch* dst_;
166 + Ch* head_;
167 +};
168 +
169 +template <typename Encoding>
170 +struct StreamTraits<GenericInsituStringStream<Encoding> > {
171 + enum { copyOptimization = 1 };
172 +};
173 +
174 +//! Insitu string stream with UTF8 encoding.
175 +typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
176 +
177 +RAPIDJSON_NAMESPACE_END
178 +
179 +#endif // RAPIDJSON_STREAM_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_STRINGBUFFER_H_
16 +#define RAPIDJSON_STRINGBUFFER_H_
17 +
18 +#include "stream.h"
19 +#include "internal/stack.h"
20 +
21 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
22 +#include <utility> // std::move
23 +#endif
24 +
25 +#include "internal/stack.h"
26 +
27 +#if defined(__clang__)
28 +RAPIDJSON_DIAG_PUSH
29 +RAPIDJSON_DIAG_OFF(c++98-compat)
30 +#endif
31 +
32 +RAPIDJSON_NAMESPACE_BEGIN
33 +
34 +//! Represents an in-memory output stream.
35 +/*!
36 + \tparam Encoding Encoding of the stream.
37 + \tparam Allocator type for allocating memory buffer.
38 + \note implements Stream concept
39 +*/
40 +template <typename Encoding, typename Allocator = CrtAllocator>
41 +class GenericStringBuffer {
42 +public:
43 + typedef typename Encoding::Ch Ch;
44 +
45 + GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
46 +
47 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
48 + GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
49 + GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
50 + if (&rhs != this)
51 + stack_ = std::move(rhs.stack_);
52 + return *this;
53 + }
54 +#endif
55 +
56 + void Put(Ch c) { *stack_.template Push<Ch>() = c; }
57 + void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
58 + void Flush() {}
59 +
60 + void Clear() { stack_.Clear(); }
61 + void ShrinkToFit() {
62 + // Push and pop a null terminator. This is safe.
63 + *stack_.template Push<Ch>() = '\0';
64 + stack_.ShrinkToFit();
65 + stack_.template Pop<Ch>(1);
66 + }
67 +
68 + void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
69 + Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
70 + Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
71 + void Pop(size_t count) { stack_.template Pop<Ch>(count); }
72 +
73 + const Ch* GetString() const {
74 + // Push and pop a null terminator. This is safe.
75 + *stack_.template Push<Ch>() = '\0';
76 + stack_.template Pop<Ch>(1);
77 +
78 + return stack_.template Bottom<Ch>();
79 + }
80 +
81 + //! Get the size of string in bytes in the string buffer.
82 + size_t GetSize() const { return stack_.GetSize(); }
83 +
84 + //! Get the length of string in Ch in the string buffer.
85 + size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
86 +
87 + static const size_t kDefaultCapacity = 256;
88 + mutable internal::Stack<Allocator> stack_;
89 +
90 +private:
91 + // Prohibit copy constructor & assignment operator.
92 + GenericStringBuffer(const GenericStringBuffer&);
93 + GenericStringBuffer& operator=(const GenericStringBuffer&);
94 +};
95 +
96 +//! String buffer with UTF8 encoding
97 +typedef GenericStringBuffer<UTF8<> > StringBuffer;
98 +
99 +template<typename Encoding, typename Allocator>
100 +inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
101 + stream.Reserve(count);
102 +}
103 +
104 +template<typename Encoding, typename Allocator>
105 +inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
106 + stream.PutUnsafe(c);
107 +}
108 +
109 +//! Implement specialized version of PutN() with memset() for better performance.
110 +template<>
111 +inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
112 + std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
113 +}
114 +
115 +RAPIDJSON_NAMESPACE_END
116 +
117 +#if defined(__clang__)
118 +RAPIDJSON_DIAG_POP
119 +#endif
120 +
121 +#endif // RAPIDJSON_STRINGBUFFER_H_
1 +// Tencent is pleased to support the open source community by making RapidJSON available.
2 +//
3 +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 +//
5 +// Licensed under the MIT License (the "License"); you may not use this file except
6 +// in compliance with the License. You may obtain a copy of the License at
7 +//
8 +// http://opensource.org/licenses/MIT
9 +//
10 +// Unless required by applicable law or agreed to in writing, software distributed
11 +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 +// CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 +// specific language governing permissions and limitations under the License.
14 +
15 +#ifndef RAPIDJSON_WRITER_H_
16 +#define RAPIDJSON_WRITER_H_
17 +
18 +#include "stream.h"
19 +#include "internal/meta.h"
20 +#include "internal/stack.h"
21 +#include "internal/strfunc.h"
22 +#include "internal/dtoa.h"
23 +#include "internal/itoa.h"
24 +#include "stringbuffer.h"
25 +#include <new> // placement new
26 +
27 +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
28 +#include <intrin.h>
29 +#pragma intrinsic(_BitScanForward)
30 +#endif
31 +#ifdef RAPIDJSON_SSE42
32 +#include <nmmintrin.h>
33 +#elif defined(RAPIDJSON_SSE2)
34 +#include <emmintrin.h>
35 +#elif defined(RAPIDJSON_NEON)
36 +#include <arm_neon.h>
37 +#endif
38 +
39 +#ifdef _MSC_VER
40 +RAPIDJSON_DIAG_PUSH
41 +RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
42 +#endif
43 +
44 +#ifdef __clang__
45 +RAPIDJSON_DIAG_PUSH
46 +RAPIDJSON_DIAG_OFF(padded)
47 +RAPIDJSON_DIAG_OFF(unreachable-code)
48 +RAPIDJSON_DIAG_OFF(c++98-compat)
49 +#endif
50 +
51 +RAPIDJSON_NAMESPACE_BEGIN
52 +
53 +///////////////////////////////////////////////////////////////////////////////
54 +// WriteFlag
55 +
56 +/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
57 + \ingroup RAPIDJSON_CONFIG
58 + \brief User-defined kWriteDefaultFlags definition.
59 +
60 + User can define this as any \c WriteFlag combinations.
61 +*/
62 +#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
63 +#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
64 +#endif
65 +
66 +//! Combination of writeFlags
67 +enum WriteFlag {
68 + kWriteNoFlags = 0, //!< No flags are set.
69 + kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
70 + kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
71 + kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
72 +};
73 +
74 +//! JSON writer
75 +/*! Writer implements the concept Handler.
76 + It generates JSON text by events to an output os.
77 +
78 + User may programmatically calls the functions of a writer to generate JSON text.
79 +
80 + On the other side, a writer can also be passed to objects that generates events,
81 +
82 + for example Reader::Parse() and Document::Accept().
83 +
84 + \tparam OutputStream Type of output stream.
85 + \tparam SourceEncoding Encoding of source string.
86 + \tparam TargetEncoding Encoding of output stream.
87 + \tparam StackAllocator Type of allocator for allocating memory of stack.
88 + \note implements Handler concept
89 +*/
90 +template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
91 +class Writer {
92 +public:
93 + typedef typename SourceEncoding::Ch Ch;
94 +
95 + static const int kDefaultMaxDecimalPlaces = 324;
96 +
97 + //! Constructor
98 + /*! \param os Output stream.
99 + \param stackAllocator User supplied allocator. If it is null, it will create a private one.
100 + \param levelDepth Initial capacity of stack.
101 + */
102 + explicit
103 + Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
104 + os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
105 +
106 + explicit
107 + Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
108 + os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
109 +
110 +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
111 + Writer(Writer&& rhs) :
112 + os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
113 + rhs.os_ = 0;
114 + }
115 +#endif
116 +
117 + //! Reset the writer with a new stream.
118 + /*!
119 + This function reset the writer with a new stream and default settings,
120 + in order to make a Writer object reusable for output multiple JSONs.
121 +
122 + \param os New output stream.
123 + \code
124 + Writer<OutputStream> writer(os1);
125 + writer.StartObject();
126 + // ...
127 + writer.EndObject();
128 +
129 + writer.Reset(os2);
130 + writer.StartObject();
131 + // ...
132 + writer.EndObject();
133 + \endcode
134 + */
135 + void Reset(OutputStream& os) {
136 + os_ = &os;
137 + hasRoot_ = false;
138 + level_stack_.Clear();
139 + }
140 +
141 + //! Checks whether the output is a complete JSON.
142 + /*!
143 + A complete JSON has a complete root object or array.
144 + */
145 + bool IsComplete() const {
146 + return hasRoot_ && level_stack_.Empty();
147 + }
148 +
149 + int GetMaxDecimalPlaces() const {
150 + return maxDecimalPlaces_;
151 + }
152 +
153 + //! Sets the maximum number of decimal places for double output.
154 + /*!
155 + This setting truncates the output with specified number of decimal places.
156 +
157 + For example,
158 +
159 + \code
160 + writer.SetMaxDecimalPlaces(3);
161 + writer.StartArray();
162 + writer.Double(0.12345); // "0.123"
163 + writer.Double(0.0001); // "0.0"
164 + writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
165 + writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
166 + writer.EndArray();
167 + \endcode
168 +
169 + The default setting does not truncate any decimal places. You can restore to this setting by calling
170 + \code
171 + writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
172 + \endcode
173 + */
174 + void SetMaxDecimalPlaces(int maxDecimalPlaces) {
175 + maxDecimalPlaces_ = maxDecimalPlaces;
176 + }
177 +
178 + /*!@name Implementation of Handler
179 + \see Handler
180 + */
181 + //@{
182 +
183 + bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
184 + bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
185 + bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
186 + bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
187 + bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
188 + bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
189 +
190 + //! Writes the given \c double value to the stream
191 + /*!
192 + \param d The value to be written.
193 + \return Whether it is succeed.
194 + */
195 + bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
196 +
197 + bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
198 + RAPIDJSON_ASSERT(str != 0);
199 + (void)copy;
200 + Prefix(kNumberType);
201 + return EndValue(WriteString(str, length));
202 + }
203 +
204 + bool String(const Ch* str, SizeType length, bool copy = false) {
205 + RAPIDJSON_ASSERT(str != 0);
206 + (void)copy;
207 + Prefix(kStringType);
208 + return EndValue(WriteString(str, length));
209 + }
210 +
211 +#if RAPIDJSON_HAS_STDSTRING
212 + bool String(const std::basic_string<Ch>& str) {
213 + return String(str.data(), SizeType(str.size()));
214 + }
215 +#endif
216 +
217 + bool StartObject() {
218 + Prefix(kObjectType);
219 + new (level_stack_.template Push<Level>()) Level(false);
220 + return WriteStartObject();
221 + }
222 +
223 + bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
224 +
225 +#if RAPIDJSON_HAS_STDSTRING
226 + bool Key(const std::basic_string<Ch>& str)
227 + {
228 + return Key(str.data(), SizeType(str.size()));
229 + }
230 +#endif
231 +
232 + bool EndObject(SizeType memberCount = 0) {
233 + (void)memberCount;
234 + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
235 + RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
236 + RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
237 + level_stack_.template Pop<Level>(1);
238 + return EndValue(WriteEndObject());
239 + }
240 +
241 + bool StartArray() {
242 + Prefix(kArrayType);
243 + new (level_stack_.template Push<Level>()) Level(true);
244 + return WriteStartArray();
245 + }
246 +
247 + bool EndArray(SizeType elementCount = 0) {
248 + (void)elementCount;
249 + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
250 + RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
251 + level_stack_.template Pop<Level>(1);
252 + return EndValue(WriteEndArray());
253 + }
254 + //@}
255 +
256 + /*! @name Convenience extensions */
257 + //@{
258 +
259 + //! Simpler but slower overload.
260 + bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
261 + bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
262 +
263 + //@}
264 +
265 + //! Write a raw JSON value.
266 + /*!
267 + For user to write a stringified JSON as a value.
268 +
269 + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
270 + \param length Length of the json.
271 + \param type Type of the root of json.
272 + */
273 + bool RawValue(const Ch* json, size_t length, Type type) {
274 + RAPIDJSON_ASSERT(json != 0);
275 + Prefix(type);
276 + return EndValue(WriteRawValue(json, length));
277 + }
278 +
279 + //! Flush the output stream.
280 + /*!
281 + Allows the user to flush the output stream immediately.
282 + */
283 + void Flush() {
284 + os_->Flush();
285 + }
286 +
287 +protected:
288 + //! Information for each nested level
289 + struct Level {
290 + Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
291 + size_t valueCount; //!< number of values in this level
292 + bool inArray; //!< true if in array, otherwise in object
293 + };
294 +
295 + static const size_t kDefaultLevelDepth = 32;
296 +
297 + bool WriteNull() {
298 + PutReserve(*os_, 4);
299 + PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
300 + }
301 +
302 + bool WriteBool(bool b) {
303 + if (b) {
304 + PutReserve(*os_, 4);
305 + PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
306 + }
307 + else {
308 + PutReserve(*os_, 5);
309 + PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
310 + }
311 + return true;
312 + }
313 +
314 + bool WriteInt(int i) {
315 + char buffer[11];
316 + const char* end = internal::i32toa(i, buffer);
317 + PutReserve(*os_, static_cast<size_t>(end - buffer));
318 + for (const char* p = buffer; p != end; ++p)
319 + PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
320 + return true;
321 + }
322 +
323 + bool WriteUint(unsigned u) {
324 + char buffer[10];
325 + const char* end = internal::u32toa(u, buffer);
326 + PutReserve(*os_, static_cast<size_t>(end - buffer));
327 + for (const char* p = buffer; p != end; ++p)
328 + PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
329 + return true;
330 + }
331 +
332 + bool WriteInt64(int64_t i64) {
333 + char buffer[21];
334 + const char* end = internal::i64toa(i64, buffer);
335 + PutReserve(*os_, static_cast<size_t>(end - buffer));
336 + for (const char* p = buffer; p != end; ++p)
337 + PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
338 + return true;
339 + }
340 +
341 + bool WriteUint64(uint64_t u64) {
342 + char buffer[20];
343 + char* end = internal::u64toa(u64, buffer);
344 + PutReserve(*os_, static_cast<size_t>(end - buffer));
345 + for (char* p = buffer; p != end; ++p)
346 + PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
347 + return true;
348 + }
349 +
350 + bool WriteDouble(double d) {
351 + if (internal::Double(d).IsNanOrInf()) {
352 + if (!(writeFlags & kWriteNanAndInfFlag))
353 + return false;
354 + if (internal::Double(d).IsNan()) {
355 + PutReserve(*os_, 3);
356 + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
357 + return true;
358 + }
359 + if (internal::Double(d).Sign()) {
360 + PutReserve(*os_, 9);
361 + PutUnsafe(*os_, '-');
362 + }
363 + else
364 + PutReserve(*os_, 8);
365 + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
366 + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
367 + return true;
368 + }
369 +
370 + char buffer[25];
371 + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
372 + PutReserve(*os_, static_cast<size_t>(end - buffer));
373 + for (char* p = buffer; p != end; ++p)
374 + PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
375 + return true;
376 + }
377 +
378 + bool WriteString(const Ch* str, SizeType length) {
379 + static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
380 + static const char escape[256] = {
381 +#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
382 + //0 1 2 3 4 5 6 7 8 9 A B C D E F
383 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
384 + 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
385 + 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
386 + Z16, Z16, // 30~4F
387 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
388 + Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
389 +#undef Z16
390 + };
391 +
392 + if (TargetEncoding::supportUnicode)
393 + PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
394 + else
395 + PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
396 +
397 + PutUnsafe(*os_, '\"');
398 + GenericStringStream<SourceEncoding> is(str);
399 + while (ScanWriteUnescapedString(is, length)) {
400 + const Ch c = is.Peek();
401 + if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
402 + // Unicode escaping
403 + unsigned codepoint;
404 + if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
405 + return false;
406 + PutUnsafe(*os_, '\\');
407 + PutUnsafe(*os_, 'u');
408 + if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
409 + PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
410 + PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
411 + PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
412 + PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
413 + }
414 + else {
415 + RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
416 + // Surrogate pair
417 + unsigned s = codepoint - 0x010000;
418 + unsigned lead = (s >> 10) + 0xD800;
419 + unsigned trail = (s & 0x3FF) + 0xDC00;
420 + PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
421 + PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
422 + PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
423 + PutUnsafe(*os_, hexDigits[(lead ) & 15]);
424 + PutUnsafe(*os_, '\\');
425 + PutUnsafe(*os_, 'u');
426 + PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
427 + PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
428 + PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
429 + PutUnsafe(*os_, hexDigits[(trail ) & 15]);
430 + }
431 + }
432 + else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
433 + is.Take();
434 + PutUnsafe(*os_, '\\');
435 + PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
436 + if (escape[static_cast<unsigned char>(c)] == 'u') {
437 + PutUnsafe(*os_, '0');
438 + PutUnsafe(*os_, '0');
439 + PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
440 + PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
441 + }
442 + }
443 + else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
444 + Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
445 + Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
446 + return false;
447 + }
448 + PutUnsafe(*os_, '\"');
449 + return true;
450 + }
451 +
452 + bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
453 + return RAPIDJSON_LIKELY(is.Tell() < length);
454 + }
455 +
456 + bool WriteStartObject() { os_->Put('{'); return true; }
457 + bool WriteEndObject() { os_->Put('}'); return true; }
458 + bool WriteStartArray() { os_->Put('['); return true; }
459 + bool WriteEndArray() { os_->Put(']'); return true; }
460 +
461 + bool WriteRawValue(const Ch* json, size_t length) {
462 + PutReserve(*os_, length);
463 + for (size_t i = 0; i < length; i++) {
464 + RAPIDJSON_ASSERT(json[i] != '\0');
465 + PutUnsafe(*os_, json[i]);
466 + }
467 + return true;
468 + }
469 +
470 + void Prefix(Type type) {
471 + (void)type;
472 + if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
473 + Level* level = level_stack_.template Top<Level>();
474 + if (level->valueCount > 0) {
475 + if (level->inArray)
476 + os_->Put(','); // add comma if it is not the first element in array
477 + else // in object
478 + os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
479 + }
480 + if (!level->inArray && level->valueCount % 2 == 0)
481 + RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
482 + level->valueCount++;
483 + }
484 + else {
485 + RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
486 + hasRoot_ = true;
487 + }
488 + }
489 +
490 + // Flush the value if it is the top level one.
491 + bool EndValue(bool ret) {
492 + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
493 + Flush();
494 + return ret;
495 + }
496 +
497 + OutputStream* os_;
498 + internal::Stack<StackAllocator> level_stack_;
499 + int maxDecimalPlaces_;
500 + bool hasRoot_;
501 +
502 +private:
503 + // Prohibit copy constructor & assignment operator.
504 + Writer(const Writer&);
505 + Writer& operator=(const Writer&);
506 +};
507 +
508 +// Full specialization for StringStream to prevent memory copying
509 +
510 +template<>
511 +inline bool Writer<StringBuffer>::WriteInt(int i) {
512 + char *buffer = os_->Push(11);
513 + const char* end = internal::i32toa(i, buffer);
514 + os_->Pop(static_cast<size_t>(11 - (end - buffer)));
515 + return true;
516 +}
517 +
518 +template<>
519 +inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
520 + char *buffer = os_->Push(10);
521 + const char* end = internal::u32toa(u, buffer);
522 + os_->Pop(static_cast<size_t>(10 - (end - buffer)));
523 + return true;
524 +}
525 +
526 +template<>
527 +inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
528 + char *buffer = os_->Push(21);
529 + const char* end = internal::i64toa(i64, buffer);
530 + os_->Pop(static_cast<size_t>(21 - (end - buffer)));
531 + return true;
532 +}
533 +
534 +template<>
535 +inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
536 + char *buffer = os_->Push(20);
537 + const char* end = internal::u64toa(u, buffer);
538 + os_->Pop(static_cast<size_t>(20 - (end - buffer)));
539 + return true;
540 +}
541 +
542 +template<>
543 +inline bool Writer<StringBuffer>::WriteDouble(double d) {
544 + if (internal::Double(d).IsNanOrInf()) {
545 + // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
546 + if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
547 + return false;
548 + if (internal::Double(d).IsNan()) {
549 + PutReserve(*os_, 3);
550 + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
551 + return true;
552 + }
553 + if (internal::Double(d).Sign()) {
554 + PutReserve(*os_, 9);
555 + PutUnsafe(*os_, '-');
556 + }
557 + else
558 + PutReserve(*os_, 8);
559 + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
560 + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
561 + return true;
562 + }
563 +
564 + char *buffer = os_->Push(25);
565 + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
566 + os_->Pop(static_cast<size_t>(25 - (end - buffer)));
567 + return true;
568 +}
569 +
570 +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
571 +template<>
572 +inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
573 + if (length < 16)
574 + return RAPIDJSON_LIKELY(is.Tell() < length);
575 +
576 + if (!RAPIDJSON_LIKELY(is.Tell() < length))
577 + return false;
578 +
579 + const char* p = is.src_;
580 + const char* end = is.head_ + length;
581 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
582 + const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
583 + if (nextAligned > end)
584 + return true;
585 +
586 + while (p != nextAligned)
587 + if (*p < 0x20 || *p == '\"' || *p == '\\') {
588 + is.src_ = p;
589 + return RAPIDJSON_LIKELY(is.Tell() < length);
590 + }
591 + else
592 + os_->PutUnsafe(*p++);
593 +
594 + // The rest of string using SIMD
595 + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
596 + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
597 + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
598 + const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
599 + const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
600 + const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
601 +
602 + for (; p != endAligned; p += 16) {
603 + const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
604 + const __m128i t1 = _mm_cmpeq_epi8(s, dq);
605 + const __m128i t2 = _mm_cmpeq_epi8(s, bs);
606 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
607 + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
608 + unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
609 + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
610 + SizeType len;
611 +#ifdef _MSC_VER // Find the index of first escaped
612 + unsigned long offset;
613 + _BitScanForward(&offset, r);
614 + len = offset;
615 +#else
616 + len = static_cast<SizeType>(__builtin_ffs(r) - 1);
617 +#endif
618 + char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
619 + for (size_t i = 0; i < len; i++)
620 + q[i] = p[i];
621 +
622 + p += len;
623 + break;
624 + }
625 + _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
626 + }
627 +
628 + is.src_ = p;
629 + return RAPIDJSON_LIKELY(is.Tell() < length);
630 +}
631 +#elif defined(RAPIDJSON_NEON)
632 +template<>
633 +inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
634 + if (length < 16)
635 + return RAPIDJSON_LIKELY(is.Tell() < length);
636 +
637 + if (!RAPIDJSON_LIKELY(is.Tell() < length))
638 + return false;
639 +
640 + const char* p = is.src_;
641 + const char* end = is.head_ + length;
642 + const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
643 + const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
644 + if (nextAligned > end)
645 + return true;
646 +
647 + while (p != nextAligned)
648 + if (*p < 0x20 || *p == '\"' || *p == '\\') {
649 + is.src_ = p;
650 + return RAPIDJSON_LIKELY(is.Tell() < length);
651 + }
652 + else
653 + os_->PutUnsafe(*p++);
654 +
655 + // The rest of string using SIMD
656 + const uint8x16_t s0 = vmovq_n_u8('"');
657 + const uint8x16_t s1 = vmovq_n_u8('\\');
658 + const uint8x16_t s2 = vmovq_n_u8('\b');
659 + const uint8x16_t s3 = vmovq_n_u8(32);
660 +
661 + for (; p != endAligned; p += 16) {
662 + const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
663 + uint8x16_t x = vceqq_u8(s, s0);
664 + x = vorrq_u8(x, vceqq_u8(s, s1));
665 + x = vorrq_u8(x, vceqq_u8(s, s2));
666 + x = vorrq_u8(x, vcltq_u8(s, s3));
667 +
668 + x = vrev64q_u8(x); // Rev in 64
669 + uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
670 + uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
671 +
672 + SizeType len = 0;
673 + bool escaped = false;
674 + if (low == 0) {
675 + if (high != 0) {
676 + unsigned lz = (unsigned)__builtin_clzll(high);
677 + len = 8 + (lz >> 3);
678 + escaped = true;
679 + }
680 + } else {
681 + unsigned lz = (unsigned)__builtin_clzll(low);
682 + len = lz >> 3;
683 + escaped = true;
684 + }
685 + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
686 + char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
687 + for (size_t i = 0; i < len; i++)
688 + q[i] = p[i];
689 +
690 + p += len;
691 + break;
692 + }
693 + vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
694 + }
695 +
696 + is.src_ = p;
697 + return RAPIDJSON_LIKELY(is.Tell() < length);
698 +}
699 +#endif // RAPIDJSON_NEON
700 +
701 +RAPIDJSON_NAMESPACE_END
702 +
703 +#ifdef _MSC_VER
704 +RAPIDJSON_DIAG_POP
705 +#endif
706 +
707 +#ifdef __clang__
708 +RAPIDJSON_DIAG_POP
709 +#endif
710 +
711 +#endif // RAPIDJSON_RAPIDJSON_H_
...@@ -2,50 +2,26 @@ ...@@ -2,50 +2,26 @@
2 #include "PaperGraphWidget.h" 2 #include "PaperGraphWidget.h"
3 #include "MainWindow.h" 3 #include "MainWindow.h"
4 4
5 -size_t write_callback(void *contents, size_t size, 5 +int main(int argc, char *argv[]) {
6 - size_t nmemb, void *userp) {
7 - std::string* p_str = (std::string*)userp;
8 -
9 - //clear
10 - if (!p_str->empty())
11 - p_str->clear();
12 -
13 - //write
14 - p_str->append((char*)contents, size*nmemb);
15 - return size*nmemb;
16 -}
17 -
18 -int main(int argc, char *argv[])
19 -{
20 if (1) { 6 if (1) {
21 - CURL *curl; 7 + _curl_processor.set_url("http://dblp.uni-trier.de/rec/bib1/conf/sbrn/WedemannCD06");
22 - CURLcode res; 8 + _curl_processor.perform();
23 - std::string read_buffer; 9 + printf("%s", _curl_processor.get_buffer().c_str());
24 10
25 - curl = curl_easy_init(); 11 + _bibtex_processor.read(_curl_processor.get_buffer());
26 - if (curl) { 12 + std::string doi;
27 - curl_easy_setopt(curl, CURLOPT_URL, "http://dblp.uni-trier.de/rec/bib/conf/sbrn/WedemannCD06"); 13 + _bibtex_processor.get_value("doi", doi);
28 - /* example.com is redirected, so we tell libcurl to follow redirection */
29 14
30 - //write option 15 + std::string address = std::string("http://api.crossref.org/works/")+doi;
31 - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); 16 + _curl_processor.set_url(address.c_str());
32 - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &read_buffer); 17 + _curl_processor.perform();
33 18
34 - /* Perform the request, res will get the return code */ 19 + printf("json: %s\n", _curl_processor.get_buffer().c_str());
35 - res = curl_easy_perform(curl);
36 - res = curl_easy_perform(curl);
37 20
21 + //rapidjson test
22 + rapidjson::Document d;
23 + d.Parse(_curl_processor.get_buffer().c_str());
38 24
39 - printf("%s\n", read_buffer.c_str());
40 -
41 - /* Check for errors */
42 - if (res != CURLE_OK)
43 - fprintf(stderr, "curl_easy_perform() failed: %s\n",
44 - curl_easy_strerror(res));
45 -
46 - /* always cleanup */
47 - curl_easy_cleanup(curl);
48 - }
49 return 0; 25 return 0;
50 } 26 }
51 27
......
1 #include "stdafx.h" 1 #include "stdafx.h"
2 +
3 +size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) {
4 + //copy ptr
5 + std::string* p_str = (std::string*)userp;
6 +
7 + //clear
8 + if (!p_str->empty())
9 + p_str->clear();
10 +
11 + //write
12 + p_str->append((char*)contents, size*nmemb);
13 + return size*nmemb;
14 +}
...\ No newline at end of file ...\ No newline at end of file
......
1 #pragma once 1 #pragma once
2 +#define _CRT_SECURE_NO_WARNINGS
3 +
2 #include <QColor> 4 #include <QColor>
3 #include <QComboBox> 5 #include <QComboBox>
4 #include <QDebug> 6 #include <QDebug>
...@@ -47,17 +49,32 @@ ...@@ -47,17 +49,32 @@
47 #include <utility> 49 #include <utility>
48 #include <vector> 50 #include <vector>
49 51
52 +#include <bibtexreader.hpp>
53 +
54 +#include <rapidjson/document.h>
55 +#include <rapidjson/writer.h>
56 +#include <rapidjson/stringbuffer.h>
57 +
58 +#include "bibtex_processor.h"
59 +#include "curl_processor.h"
60 +
61 +using bibtex::BibTeXEntry;
50 using namespace boost; 62 using namespace boost;
51 using namespace std; 63 using namespace std;
52 64
65 +/* function declaration */
66 +size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp);
67 +
53 /* enums */ 68 /* enums */
54 enum vertex_position_t { vertex_position }; 69 enum vertex_position_t { vertex_position };
55 enum vertex_type_t { vertex_type }; 70 enum vertex_type_t { vertex_type };
56 enum vertex_record_t { vertex_record }; 71 enum vertex_record_t { vertex_record };
72 +enum vertex_citation_t { vertex_citation };
57 namespace boost { 73 namespace boost {
58 BOOST_INSTALL_PROPERTY(vertex, position); 74 BOOST_INSTALL_PROPERTY(vertex, position);
59 BOOST_INSTALL_PROPERTY(vertex, type); 75 BOOST_INSTALL_PROPERTY(vertex, type);
60 BOOST_INSTALL_PROPERTY(vertex, record); 76 BOOST_INSTALL_PROPERTY(vertex, record);
77 + BOOST_INSTALL_PROPERTY(vertex, citation);
61 } 78 }
62 enum NODE_TYPE { 79 enum NODE_TYPE {
63 NODE_PAPER, 80 NODE_PAPER,
...@@ -75,9 +92,11 @@ typedef boost::bimap<string, int> bm_type; ...@@ -75,9 +92,11 @@ typedef boost::bimap<string, int> bm_type;
75 typedef square_topology<>::point_type point; 92 typedef square_topology<>::point_type point;
76 typedef boost::property<vertex_index_t, int, 93 typedef boost::property<vertex_index_t, int,
77 boost::property<vertex_name_t, std::string, 94 boost::property<vertex_name_t, std::string,
78 - boost::property<vertex_position_t, point, 95 + boost::property<vertex_position_t, point, //좌표값
79 - boost::property<vertex_type_t, int, 96 + boost::property<vertex_type_t, int, //타입. enum NODE_TYPE에 정의됨
80 - boost::property<vertex_record_t, int>>>> 97 + boost::property<vertex_record_t, int, //이웃 노드 개수
98 + boost::property<vertex_citation_t, int>
99 + >>>>
81 > VertexProperties; 100 > VertexProperties;
82 typedef boost::adjacency_list< 101 typedef boost::adjacency_list<
83 listS, //outEdgeList 102 listS, //outEdgeList
...@@ -108,11 +127,11 @@ namespace { ...@@ -108,11 +127,11 @@ namespace {
108 //const int READ_LINE_UNIT = 20; //한 번에 몇 라인을 읽을지 127 //const int READ_LINE_UNIT = 20; //한 번에 몇 라인을 읽을지
109 const int READ_LINE_UNIT = 100; 128 const int READ_LINE_UNIT = 100;
110 129
111 - /* topK */ 130 + /* curl processor */
112 - //const int TOP_K = 5; //상위 몇 개 아이템에 대해 highlight 할 지 131 + curl_processor _curl_processor;
113 132
114 - /* a research you might know */ 133 + /* bibtex processor */
115 - //const char* TARGET_AUTHOR_NAME = "Shuichi Itoh"; 134 + bibtex_processor _bibtex_processor;
116 } 135 }
117 136
118 /* boost */ 137 /* boost */
......