rapidjson A fast JSON parser/generator for C++ with both SAX/DOM style API

- Main Page
- Related Pages
- Classes
- Files

- File List

All Classes Functions Variables Typedefs Pages
reader.h
1 #ifndef RAPIDJSON_READER_H_
2 #define RAPIDJSON_READER_H_
3
4 // Copyright (c) 2011 Milo Yip (miloyip@gmail.com)
5 // Version 0.1
6
7 #include "rapidjson.h"
8 #include "internal/pow10.h"
9 #include "internal/stack.h"
10 #include <csetjmp>
11
12 #ifdef RAPIDJSON_SSE42
13 #include <nmmintrin.h>
14 #elif defined(RAPIDJSON_SSE2)
15 #include <emmintrin.h>
16 #endif
17
18 #ifdef _MSC_VER
19 #pragma warning(push)
20 #pragma warning(disable : 4127) // conditional expression is constant
21 #endif
22
23 #ifndef RAPIDJSON_PARSE_ERROR
24 #define RAPIDJSON_PARSE_ERROR(msg, offset) \
25 RAPIDJSON_MULTILINEMACRO_BEGIN \
26 parseError_ = msg; \
27 errorOffset_ = offset; \
28 longjmp(jmpbuf_, 1); \
29 RAPIDJSON_MULTILINEMACRO_END
30 #endif
31
32 namespace rapidjson {
33
34 ///////////////////////////////////////////////////////////////////////////////
35 // ParseFlag
36
37 //! Combination of parseFlags
38 enum ParseFlag {
39 kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
40 kParseInsituFlag = 1 //!< In-situ(destructive) parsing.
41 };
42
43 ///////////////////////////////////////////////////////////////////////////////
44 // Handler
45
46 /*! \class rapidjson::Handler
47 \brief Concept for receiving events from GenericReader upon parsing.
48 \code
49 concept Handler {
50 typename Ch;
51
52 void Null();
53 void Bool(bool b);
54 void Int(int i);
55 void Uint(unsigned i);
56 void Int64(int64_t i);
57 void Uint64(uint64_t i);
58 void Double(double d);
59 void String(const Ch* str, SizeType length, bool copy);
60 void StartObject();
61 void EndObject(SizeType memberCount);
62 void StartArray();
63 void EndArray(SizeType elementCount);
64 };
65 \endcode
66 */
67 ///////////////////////////////////////////////////////////////////////////////
68 // BaseReaderHandler
69
70 //! Default implementation of Handler.
71 /*! This can be used as base class of any reader handler.
72 \implements Handler
73 */
74 template<typename Encoding = UTF8<> >
75 struct BaseReaderHandler {
76 typedef typename Encoding::Ch Ch;
77
78 void Default() {}
79 void Null() { Default(); }
80 void Bool(bool) { Default(); }
81 void Int(int) { Default(); }
82 void Uint(unsigned) { Default(); }
83 void Int64(int64_t) { Default(); }
84 void Uint64(uint64_t) { Default(); }
85 void Double(double) { Default(); }
86 void String(const Ch*, SizeType, bool) { Default(); }
87 void StartObject() { Default(); }
88 void EndObject(SizeType) { Default(); }
89 void StartArray() { Default(); }
90 void EndArray(SizeType) { Default(); }
91 };
92
93 ///////////////////////////////////////////////////////////////////////////////
94 // SkipWhitespace
95
96 //! Skip the JSON white spaces in a stream.
97 /*! \param stream A input stream for skipping white spaces.
98 \note This function has SSE2/SSE4.2 specialization.
99 */
100 template<typename Stream>
101 void SkipWhitespace(Stream& stream) {
102 Stream s = stream; // Use a local copy for optimization
103 while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t')
104 s.Take();
105 stream = s;
106 }
107
108 #ifdef RAPIDJSON_SSE42
109 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
110 inline const char *SkipWhitespace_SIMD(const char* p) {
111 static const char whitespace[16] = " \n\r\t";
112 __m128i w = _mm_loadu_si128((const __m128i *)&whitespace[0]);
113
114 for (;;) {
115 __m128i s = _mm_loadu_si128((const __m128i *)p);
116 unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
117 if (r == 0) // all 16 characters are whitespace
118 p += 16;
119 else { // some of characters may be non-whitespace
120 #ifdef _MSC_VER // Find the index of first non-whitespace
121 unsigned long offset;
122 if (_BitScanForward(&offset, r))
123 return p + offset;
124 #else
125 if (r != 0)
126 return p + __builtin_ffs(r) - 1;
127 #endif
128 }
129 }
130 }
131
132 #elif defined(RAPIDJSON_SSE2)
133
134 //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
135 inline const char *SkipWhitespace_SIMD(const char* p) {
136 static const char whitespaces[4][17] = {
137 " ",
138 "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
139 "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r",
140 "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"};
141
142 __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]);
143 __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]);
144 __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]);
145 __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]);
146
147 for (;;) {
148 __m128i s = _mm_loadu_si128((const __m128i *)p);
149 __m128i x = _mm_cmpeq_epi8(s, w0);
150 x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
151 x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
152 x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
153 unsigned short r = ~_mm_movemask_epi8(x);
154 if (r == 0) // all 16 characters are whitespace
155 p += 16;
156 else { // some of characters may be non-whitespace
157 #ifdef _MSC_VER // Find the index of first non-whitespace
158 unsigned long offset;
159 if (_BitScanForward(&offset, r))
160 return p + offset;
161 #else
162 if (r != 0)
163 return p + __builtin_ffs(r) - 1;
164 #endif
165 }
166 }
167 }
168
169 #endif // RAPIDJSON_SSE2
170
171 #ifdef RAPIDJSON_SIMD
172 //! Template function specialization for InsituStringStream
173 template<> inline void SkipWhitespace(InsituStringStream& stream) {
174 stream.src_ = const_cast<char*>(SkipWhitespace_SIMD(stream.src_));
175 }
176
177 //! Template function specialization for StringStream
178 template<> inline void SkipWhitespace(StringStream& stream) {
179 stream.src_ = SkipWhitespace_SIMD(stream.src_);
180 }
181 #endif // RAPIDJSON_SIMD
182
183 ///////////////////////////////////////////////////////////////////////////////
184 // GenericReader
185
186 //! SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
187 /*! GenericReader parses JSON text from a stream, and send events synchronously to an
188 object implementing Handler concept.
189
190 It needs to allocate a stack for storing a single decoded string during
191 non-destructive parsing.
192
193 For in-situ parsing, the decoded string is directly written to the source
194 text string, no temporary buffer is required.
195
196 A GenericReader object can be reused for parsing multiple JSON text.
197
198 \tparam Encoding Encoding of both the stream and the parse output.
199 \tparam Allocator Allocator type for stack.
200 */
201 template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
202 class GenericReader {
203 public:
204 typedef typename Encoding::Ch Ch;
205
206 //! Constructor.
207 /*! \param allocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
208 \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
209 */
210 GenericReader(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(allocator, stackCapacity), parseError_(0), errorOffset_(0) {}
211
212 //! Parse JSON text.
213 /*! \tparam parseFlags Combination of ParseFlag.
214 \tparam Stream Type of input stream.
215 \tparam Handler Type of handler which must implement Handler concept.
216 \param stream Input stream to be parsed.
217 \param handler The handler to receive events.
218 \return Whether the parsing is successful.
219 */
220 template <unsigned parseFlags, typename Stream, typename Handler>
221 bool Parse(Stream& stream, Handler& handler) {
222 parseError_ = 0;
223 errorOffset_ = 0;
224
225 #ifdef _MSC_VER
226 #pragma warning(push)
227 #pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
228 #endif
229 if (setjmp(jmpbuf_)) {
230 #ifdef _MSC_VER
231 #pragma warning(pop)
232 #endif
233 stack_.Clear();
234 return false;
235 }
236
237 SkipWhitespace(stream);
238
239 if (stream.Peek() == '\0')
240 RAPIDJSON_PARSE_ERROR("Text only contains white space(s)", stream.Tell());
241 else {
242 switch (stream.Peek()) {
243 case '{': ParseObject<parseFlags>(stream, handler); break;
244 case '[': ParseArray<parseFlags>(stream, handler); break;
245 default: RAPIDJSON_PARSE_ERROR("Expect either an object or array at root", stream.Tell());
246 }
247 SkipWhitespace(stream);
248
249 if (stream.Peek() != '\0')
250 RAPIDJSON_PARSE_ERROR("Nothing should follow the root object or array.", stream.Tell());
251 }
252
253 return true;
254 }
255
256 bool HasParseError() const { return parseError_ != 0; }
257 const char* GetParseError() const { return parseError_; }
258 size_t GetErrorOffset() const { return errorOffset_; }
259
260 private:
261 // Parse object: { string : value, ... }
262 template<unsigned parseFlags, typename Stream, typename Handler>
263 void ParseObject(Stream& stream, Handler& handler) {
264 RAPIDJSON_ASSERT(stream.Peek() == '{');
265 stream.Take(); // Skip '{'
266 handler.StartObject();
267 SkipWhitespace(stream);
268
269 if (stream.Peek() == '}') {
270 stream.Take();
271 handler.EndObject(0); // empty object
272 return;
273 }
274
275 for (SizeType memberCount = 0;;) {
276 if (stream.Peek() != '"') {
277 RAPIDJSON_PARSE_ERROR("Name of an object member must be a string", stream.Tell());
278 break;
279 }
280
281 ParseString<parseFlags>(stream, handler);
282 SkipWhitespace(stream);
283
284 if (stream.Take() != ':') {
285 RAPIDJSON_PARSE_ERROR("There must be a colon after the name of object member", stream.Tell());
286 break;
287 }
288 SkipWhitespace(stream);
289
290 ParseValue<parseFlags>(stream, handler);
291 SkipWhitespace(stream);
292
293 ++memberCount;
294
295 switch(stream.Take()) {
296 case ',': SkipWhitespace(stream); break;
297 case '}': handler.EndObject(memberCount); return;
298 default: RAPIDJSON_PARSE_ERROR("Must be a comma or '}' after an object member", stream.Tell());
299 }
300 }
301 }
302
303 // Parse array: [ value, ... ]
304 template<unsigned parseFlags, typename Stream, typename Handler>
305 void ParseArray(Stream& stream, Handler& handler) {
306 RAPIDJSON_ASSERT(stream.Peek() == '[');
307 stream.Take(); // Skip '['
308 handler.StartArray();
309 SkipWhitespace(stream);
310
311 if (stream.Peek() == ']') {
312 stream.Take();
313 handler.EndArray(0); // empty array
314 return;
315 }
316
317 for (SizeType elementCount = 0;;) {
318 ParseValue<parseFlags>(stream, handler);
319 ++elementCount;
320 SkipWhitespace(stream);
321
322 switch (stream.Take()) {
323 case ',': SkipWhitespace(stream); break;
324 case ']': handler.EndArray(elementCount); return;
325 default: RAPIDJSON_PARSE_ERROR("Must be a comma or ']' after an array element.", stream.Tell());
326 }
327 }
328 }
329
330 template<unsigned parseFlags, typename Stream, typename Handler>
331 void ParseNull(Stream& stream, Handler& handler) {
332 RAPIDJSON_ASSERT(stream.Peek() == 'n');
333 stream.Take();
334
335 if (stream.Take() == 'u' && stream.Take() == 'l' && stream.Take() == 'l')
336 handler.Null();
337 else
338 RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
339 }
340
341 template<unsigned parseFlags, typename Stream, typename Handler>
342 void ParseTrue(Stream& stream, Handler& handler) {
343 RAPIDJSON_ASSERT(stream.Peek() == 't');
344 stream.Take();
345
346 if (stream.Take() == 'r' && stream.Take() == 'u' && stream.Take() == 'e')
347 handler.Bool(true);
348 else
349 RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell());
350 }
351
352 template<unsigned parseFlags, typename Stream, typename Handler>
353 void ParseFalse(Stream& stream, Handler& handler) {
354 RAPIDJSON_ASSERT(stream.Peek() == 'f');
355 stream.Take();
356
357 if (stream.Take() == 'a' && stream.Take() == 'l' && stream.Take() == 's' && stream.Take() == 'e')
358 handler.Bool(false);
359 else
360 RAPIDJSON_PARSE_ERROR("Invalid value", stream.Tell() - 1);
361 }
362
363 // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
364 template<typename Stream>
365 unsigned ParseHex4(Stream& stream) {
366 Stream s = stream; // Use a local copy for optimization
367 unsigned codepoint = 0;
368 for (int i = 0; i < 4; i++) {
369 Ch c = s.Take();
370 codepoint <<= 4;
371 codepoint += c;
372 if (c >= '0' && c <= '9')
373 codepoint -= '0';
374 else if (c >= 'A' && c <= 'F')
375 codepoint -= 'A' - 10;
376 else if (c >= 'a' && c <= 'f')
377 codepoint -= 'a' - 10;
378 else
379 RAPIDJSON_PARSE_ERROR("Incorrect hex digit after \\u escape", s.Tell() - 1);
380 }
381 stream = s; // Restore stream
382 return codepoint;
383 }
384
385 // Parse string, handling the prefix and suffix double quotes and escaping.
386 template<unsigned parseFlags, typename Stream, typename Handler>
387 void ParseString(Stream& stream, Handler& handler) {
388 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
389 static const Ch escape[256] = {
390 Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
391 Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
392 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
393 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
394 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
395 };
396 #undef Z16
397
398 Stream s = stream; // Use a local copy for optimization
399 RAPIDJSON_ASSERT(s.Peek() == '\"');
400 s.Take(); // Skip '\"'
401 Ch *head;
402 SizeType len;
403 if (parseFlags & kParseInsituFlag)
404 head = s.PutBegin();
405 else
406 len = 0;
407
408 #define RAPIDJSON_PUT(x) \
409 do { \
410 if (parseFlags & kParseInsituFlag) \
411 s.Put(x); \
412 else { \
413 *stack_.template Push<Ch>() = x; \
414 ++len; \
415 } \
416 } while(false)
417
418 for (;;) {
419 Ch c = s.Take();
420 if (c == '\\') { // Escape
421 Ch e = s.Take();
422 if ((sizeof(Ch) == 1 || e < 256) && escape[(unsigned char)e])
423 RAPIDJSON_PUT(escape[(unsigned char)e]);
424 else if (e == 'u') { // Unicode
425 unsigned codepoint = ParseHex4(s);
426 if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { // Handle UTF-16 surrogate pair
427 if (s.Take() != '\\' || s.Take() != 'u') {
428 RAPIDJSON_PARSE_ERROR("Missing the second \\u in surrogate pair", s.Tell() - 2);
429 return;
430 }
431 unsigned codepoint2 = ParseHex4(s);
432 if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) {
433 RAPIDJSON_PARSE_ERROR("The second \\u in surrogate pair is invalid", s.Tell() - 2);
434 return;
435 }
436 codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
437 }
438
439 Ch buffer[4];
440 SizeType count = SizeType(Encoding::Encode(buffer, codepoint) - &buffer[0]);
441
442 if (parseFlags & kParseInsituFlag)
443 for (SizeType i = 0; i < count; i++)
444 s.Put(buffer[i]);
445 else {
446 memcpy(stack_.template Push<Ch>(count), buffer, count * sizeof(Ch));
447 len += count;
448 }
449 }
450 else {
451 RAPIDJSON_PARSE_ERROR("Unknown escape character", stream.Tell() - 1);
452 return;
453 }
454 }
455 else if (c == '"') { // Closing double quote
456 if (parseFlags & kParseInsituFlag) {
457 size_t length = s.PutEnd(head);
458 RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
459 RAPIDJSON_PUT('\0'); // null-terminate the string
460 handler.String(head, SizeType(length), false);
461 }
462 else {
463 RAPIDJSON_PUT('\0');
464 handler.String(stack_.template Pop<Ch>(len), len - 1, true);
465 }
466 stream = s; // restore stream
467 return;
468 }
469 else if (c == '\0') {
470 RAPIDJSON_PARSE_ERROR("lacks ending quotation before the end of string", stream.Tell() - 1);
471 return;
472 }
473 else if ((unsigned)c < 0x20) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
474 RAPIDJSON_PARSE_ERROR("Incorrect unescaped character in string", stream.Tell() - 1);
475 return;
476 }
477 else
478 RAPIDJSON_PUT(c); // Normal character, just copy
479 }
480 #undef RAPIDJSON_PUT
481 }
482
483 template<unsigned parseFlags, typename Stream, typename Handler>
484 void ParseNumber(Stream& stream, Handler& handler) {
485 Stream s = stream; // Local copy for optimization
486 // Parse minus
487 bool minus = false;
488 if (s.Peek() == '-') {
489 minus = true;
490 s.Take();
491 }
492
493 // Parse int: zero / ( digit1-9 *DIGIT )
494 unsigned i;
495 bool try64bit = false;
496 if (s.Peek() == '0') {
497 i = 0;
498 s.Take();
499 }
500 else if (s.Peek() >= '1' && s.Peek() <= '9') {
501 i = s.Take() - '0';
502
503 if (minus)
504 while (s.Peek() >= '0' && s.Peek() <= '9') {
505 if (i >= 214748364) { // 2^31 = 2147483648
506 if (i != 214748364 || s.Peek() > '8') {
507 try64bit = true;
508 break;
509 }
510 }
511 i = i * 10 + (s.Take() - '0');
512 }
513 else
514 while (s.Peek() >= '0' && s.Peek() <= '9') {
515 if (i >= 429496729) { // 2^32 - 1 = 4294967295
516 if (i != 429496729 || s.Peek() > '5') {
517 try64bit = true;
518 break;
519 }
520 }
521 i = i * 10 + (s.Take() - '0');
522 }
523 }
524 else {
525 RAPIDJSON_PARSE_ERROR("Expect a value here.", stream.Tell());
526 return;
527 }
528
529 // Parse 64bit int
530 uint64_t i64 = 0;
531 bool useDouble = false;
532 if (try64bit) {
533 i64 = i;
534 if (minus)
535 while (s.Peek() >= '0' && s.Peek() <= '9') {
536 if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808
537 if (i64 != 922337203685477580uLL || s.Peek() > '8') {
538 useDouble = true;
539 break;
540 }
541 i64 = i64 * 10 + (s.Take() - '0');
542 }
543 else
544 while (s.Peek() >= '0' && s.Peek() <= '9') {
545 if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615
546 if (i64 != 1844674407370955161uLL || s.Peek() > '5') {
547 useDouble = true;
548 break;
549 }
550 i64 = i64 * 10 + (s.Take() - '0');
551 }
552 }
553
554 // Force double for big integer
555 double d = 0.0;
556 if (useDouble) {
557 d = (double)i64;
558 while (s.Peek() >= '0' && s.Peek() <= '9') {
559 if (d >= 1E307) {
560 RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
561 return;
562 }
563 d = d * 10 + (s.Take() - '0');
564 }
565 }
566
567 // Parse frac = decimal-point 1*DIGIT
568 int expFrac = 0;
569 if (s.Peek() == '.') {
570 if (!useDouble) {
571 d = try64bit ? (double)i64 : (double)i;
572 useDouble = true;
573 }
574 s.Take();
575
576 if (s.Peek() >= '0' && s.Peek() <= '9') {
577 d = d * 10 + (s.Take() - '0');
578 --expFrac;
579 }
580 else {
581 RAPIDJSON_PARSE_ERROR("At least one digit in fraction part", stream.Tell());
582 return;
583 }
584
585 while (s.Peek() >= '0' && s.Peek() <= '9') {
586 if (expFrac > -16) {
587 d = d * 10 + (s.Peek() - '0');
588 --expFrac;
589 }
590 s.Take();
591 }
592 }
593
594 // Parse exp = e [ minus / plus ] 1*DIGIT
595 int exp = 0;
596 if (s.Peek() == 'e' || s.Peek() == 'E') {
597 if (!useDouble) {
598 d = try64bit ? (double)i64 : (double)i;
599 useDouble = true;
600 }
601 s.Take();
602
603 bool expMinus = false;
604 if (s.Peek() == '+')
605 s.Take();
606 else if (s.Peek() == '-') {
607 s.Take();
608 expMinus = true;
609 }
610
611 if (s.Peek() >= '0' && s.Peek() <= '9') {
612 exp = s.Take() - '0';
613 while (s.Peek() >= '0' && s.Peek() <= '9') {
614 exp = exp * 10 + (s.Take() - '0');
615 if (exp > 308) {
616 RAPIDJSON_PARSE_ERROR("Number too big to store in double", stream.Tell());
617 return;
618 }
619 }
620 }
621 else {
622 RAPIDJSON_PARSE_ERROR("At least one digit in exponent", s.Tell());
623 return;
624 }
625
626 if (expMinus)
627 exp = -exp;
628 }
629
630 // Finish parsing, call event according to the type of number.
631 if (useDouble) {
632 d *= internal::Pow10(exp + expFrac);
633 handler.Double(minus ? -d : d);
634 }
635 else {
636 if (try64bit) {
637 if (minus)
638 handler.Int64(-(int64_t)i64);
639 else
640 handler.Uint64(i64);
641 }
642 else {
643 if (minus)
644 handler.Int(-(int)i);
645 else
646 handler.Uint(i);
647 }
648 }
649
650 stream = s; // restore stream
651 }
652
653 // Parse any JSON value
654 template<unsigned parseFlags, typename Stream, typename Handler>
655 void ParseValue(Stream& stream, Handler& handler) {
656 switch (stream.Peek()) {
657 case 'n': ParseNull <parseFlags>(stream, handler); break;
658 case 't': ParseTrue <parseFlags>(stream, handler); break;
659 case 'f': ParseFalse <parseFlags>(stream, handler); break;
660 case '"': ParseString<parseFlags>(stream, handler); break;
661 case '{': ParseObject<parseFlags>(stream, handler); break;
662 case '[': ParseArray <parseFlags>(stream, handler); break;
663 default : ParseNumber<parseFlags>(stream, handler);
664 }
665 }
666
667 static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
668 internal::Stack<Allocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
669 jmp_buf jmpbuf_; //!< setjmp buffer for fast exit from nested parsing function calls.
670 const char* parseError_;
671 size_t errorOffset_;
672 }; // class GenericReader
673
674 //! Reader with UTF8 encoding and default allocator.
675 typedef GenericReader<UTF8<> > Reader;
676
677 } // namespace rapidjson
678
679 #ifdef _MSC_VER
680 #pragma warning(pop)
681 #endif
682
683 #endif // RAPIDJSON_READER_H_