1 /******************************************************************************
2 *
3 * Project: CPL - Common Portability Library
4 * Purpose: JSon streaming parser
5 * Author: Even Rouault, even.rouault at spatialys.com
6 *
7 ******************************************************************************
8 * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ****************************************************************************/
28
29 /*! @cond Doxygen_Suppress */
30
31 #include <assert.h>
32 #include <ctype.h> // isdigit...
33 #include <stdio.h> // snprintf
34 #include <string.h> // strlen
35 #include <vector>
36 #include <string>
37
38 #include "cpl_conv.h"
39 #include "cpl_string.h"
40 #include "cpl_json_streaming_parser.h"
41
42 /************************************************************************/
43 /* CPLJSonStreamingParser() */
44 /************************************************************************/
45
CPLJSonStreamingParser()46 CPLJSonStreamingParser::CPLJSonStreamingParser()
47 {
48 m_aState.push_back(INIT);
49 }
50
51 /************************************************************************/
52 /* ~CPLJSonStreamingParser() */
53 /************************************************************************/
54
~CPLJSonStreamingParser()55 CPLJSonStreamingParser::~CPLJSonStreamingParser()
56 {
57 }
58
59 /************************************************************************/
60 /* SetMaxDepth() */
61 /************************************************************************/
62
SetMaxDepth(size_t nVal)63 void CPLJSonStreamingParser::SetMaxDepth(size_t nVal)
64 {
65 m_nMaxDepth = nVal;
66 }
67 /************************************************************************/
68 /* SetMaxStringSize() */
69 /************************************************************************/
70
SetMaxStringSize(size_t nVal)71 void CPLJSonStreamingParser::SetMaxStringSize(size_t nVal)
72 {
73 m_nMaxStringSize = nVal;
74 }
75
76 /************************************************************************/
77 /* Reset() */
78 /************************************************************************/
79
Reset()80 void CPLJSonStreamingParser::Reset()
81 {
82 m_bExceptionOccurred = false;
83 m_bElementFound = false;
84 m_nLastChar = 0;
85 m_nLineCounter = 1;
86 m_nCharCounter = 1;
87 m_aState.clear();
88 m_aState.push_back(INIT);
89 m_osToken.clear();
90 m_abArrayState.clear();
91 m_aeObjectState.clear();
92 m_bInStringEscape = false;
93 m_bInUnicode = false;
94 m_osUnicodeHex.clear();
95 }
96
97 /************************************************************************/
98 /* AdvanceChar() */
99 /************************************************************************/
100
AdvanceChar(const char * & pStr,size_t & nLength)101 void CPLJSonStreamingParser::AdvanceChar(const char*& pStr, size_t& nLength)
102 {
103 if( *pStr == 13 && m_nLastChar != 10 )
104 {
105 m_nLineCounter ++;
106 m_nCharCounter = 0;
107 }
108 else if( *pStr == 10 && m_nLastChar != 13 )
109 {
110 m_nLineCounter ++;
111 m_nCharCounter = 0;
112 }
113 m_nLastChar = *pStr;
114
115 pStr ++;
116 nLength --;
117 m_nCharCounter ++;
118 }
119
120 /************************************************************************/
121 /* SkipSpace() */
122 /************************************************************************/
123
SkipSpace(const char * & pStr,size_t & nLength)124 void CPLJSonStreamingParser::SkipSpace(const char*& pStr, size_t& nLength)
125 {
126 while( nLength > 0 && isspace(*pStr) )
127 {
128 AdvanceChar(pStr, nLength);
129 }
130 }
131
132 /************************************************************************/
133 /* EmitException() */
134 /************************************************************************/
135
EmitException(const char * pszMessage)136 bool CPLJSonStreamingParser::EmitException(const char* pszMessage)
137 {
138 m_bExceptionOccurred = true;
139 char szMessage[108];
140 snprintf(szMessage, sizeof(szMessage),
141 "At line %d, character %d: %s",
142 m_nLineCounter, m_nCharCounter, pszMessage);
143 Exception(szMessage);
144 return false;
145 }
146
147 /************************************************************************/
148 /* EmitUnexpectedChar() */
149 /************************************************************************/
150
EmitUnexpectedChar(char ch,const char * pszExpecting)151 bool CPLJSonStreamingParser::EmitUnexpectedChar(char ch,
152 const char* pszExpecting)
153 {
154 char szMessage[64];
155 if( pszExpecting )
156 {
157 snprintf(szMessage, sizeof(szMessage),
158 "Unexpected character (%c). Expecting %s", ch, pszExpecting);
159 }
160 else
161 {
162 snprintf(szMessage, sizeof(szMessage),
163 "Unexpected character (%c)", ch);
164 }
165 return EmitException(szMessage);
166 }
167
168 /************************************************************************/
169 /* IsValidNewToken() */
170 /************************************************************************/
171
IsValidNewToken(char ch)172 static bool IsValidNewToken(char ch)
173 {
174 return ch == '[' || ch == '{' || ch == '"' || ch == '-' ||
175 ch == '.' || isdigit(ch) || ch == 't' || ch == 'f' || ch == 'n' ||
176 ch == 'i' || ch == 'I' || ch == 'N';
177 }
178
179 /************************************************************************/
180 /* StartNewToken() */
181 /************************************************************************/
182
StartNewToken(const char * & pStr,size_t & nLength)183 bool CPLJSonStreamingParser::StartNewToken(const char*& pStr, size_t& nLength)
184 {
185 char ch = *pStr;
186 if( ch == '{' )
187 {
188 if( m_aState.size() == m_nMaxDepth )
189 {
190 return EmitException("Too many nested objects and/or arrays");
191 }
192 StartObject();
193 m_aeObjectState.push_back(WAITING_KEY);
194 m_aState.push_back(OBJECT);
195 AdvanceChar(pStr, nLength);
196 }
197 else if( ch == '"' )
198 {
199 m_aState.push_back(STRING);
200 AdvanceChar(pStr, nLength);
201 }
202 else if( ch == '[' )
203 {
204 if( m_aState.size() == m_nMaxDepth )
205 {
206 return EmitException("Too many nested objects and/or arrays");
207 }
208 StartArray();
209 m_abArrayState.push_back(ArrayState::INIT);
210 m_aState.push_back(ARRAY);
211 AdvanceChar(pStr, nLength);
212 }
213 else if( ch == '-' || ch == '.' || isdigit(ch) ||
214 ch == 'i' || ch == 'I' || ch == 'N' )
215 {
216 m_aState.push_back(NUMBER);
217 }
218 else if( ch == 't' )
219 {
220 m_aState.push_back(STATE_TRUE);
221 }
222 else if( ch == 'f' )
223 {
224 m_aState.push_back(STATE_FALSE);
225 }
226 else if( ch == 'n' )
227 {
228 m_aState.push_back(STATE_NULL); /* might be nan */
229 }
230 else
231 {
232 assert( false );
233 }
234 return true;
235 }
236
237 /************************************************************************/
238 /* CheckAndEmitTrueFalseOrNull() */
239 /************************************************************************/
240
CheckAndEmitTrueFalseOrNull(char ch)241 bool CPLJSonStreamingParser::CheckAndEmitTrueFalseOrNull(char ch)
242 {
243 State eCurState = currentState();
244
245 if( eCurState == STATE_TRUE )
246 {
247 if( m_osToken == "true" )
248 {
249 Boolean(true);
250 }
251 else
252 {
253 return EmitUnexpectedChar(ch);
254 }
255 }
256 else if( eCurState == STATE_FALSE)
257 {
258 if( m_osToken == "false" )
259 {
260 Boolean(false);
261 }
262 else
263 {
264 return EmitUnexpectedChar(ch);
265 }
266 }
267 else /* if( eCurState == STATE_NULL ) */
268 {
269 if( m_osToken == "null" )
270 {
271 Null();
272 }
273 else
274 {
275 return EmitUnexpectedChar(ch);
276 }
277 }
278 m_aState.pop_back();
279 m_osToken.clear();
280 return true;
281 }
282
283 /************************************************************************/
284 /* CheckStackEmpty() */
285 /************************************************************************/
286
CheckStackEmpty()287 bool CPLJSonStreamingParser::CheckStackEmpty()
288 {
289 if( !m_aeObjectState.empty() )
290 {
291 return EmitException("Unterminated object");
292 }
293 else if( !m_abArrayState.empty() )
294 {
295 return EmitException("Unterminated array");
296 }
297 return true;
298 }
299
300 /************************************************************************/
301 /* IsHighSurrogate() */
302 /************************************************************************/
303
IsHighSurrogate(unsigned uc)304 static bool IsHighSurrogate(unsigned uc)
305 {
306 return (uc & 0xFC00) == 0xD800;
307 }
308
309 /************************************************************************/
310 /* IsLowSurrogate() */
311 /************************************************************************/
312
IsLowSurrogate(unsigned uc)313 static bool IsLowSurrogate(unsigned uc)
314 {
315 return (uc & 0xFC00) == 0xDC00;
316 }
317
318 /************************************************************************/
319 /* GetSurrogatePair() */
320 /************************************************************************/
321
GetSurrogatePair(unsigned hi,unsigned lo)322 static unsigned GetSurrogatePair(unsigned hi, unsigned lo)
323 {
324 return ((hi & 0x3FF) << 10) + (lo & 0x3FF) + 0x10000;
325 }
326
327 /************************************************************************/
328 /* IsHexDigit() */
329 /************************************************************************/
330
IsHexDigit(char ch)331 static bool IsHexDigit(char ch)
332 {
333 return (ch >= '0' && ch <= '9') ||
334 (ch >= 'a' && ch <= 'f') ||
335 (ch >= 'A' && ch <= 'F');
336 }
337
338 /************************************************************************/
339 /* HexToDecimal() */
340 /************************************************************************/
341
HexToDecimal(char ch)342 static unsigned HexToDecimal(char ch)
343 {
344 if( ch >= '0' && ch <= '9' )
345 return ch - '0';
346 if (ch >= 'a' && ch <= 'f' )
347 return 10 + ch - 'a';
348 //if (ch >= 'A' && ch <= 'F' )
349 return 10 + ch - 'A';
350 }
351
352 /************************************************************************/
353 /* getUCSChar() */
354 /************************************************************************/
355
getUCSChar(const std::string & unicode4HexChar)356 static unsigned getUCSChar(const std::string& unicode4HexChar)
357 {
358 return (HexToDecimal(unicode4HexChar[0]) << 12) |
359 (HexToDecimal(unicode4HexChar[1]) << 8) |
360 (HexToDecimal(unicode4HexChar[2]) << 4) |
361 (HexToDecimal(unicode4HexChar[3]));
362 }
363
364 /************************************************************************/
365 /* DecodeUnicode() */
366 /************************************************************************/
367
DecodeUnicode()368 void CPLJSonStreamingParser::DecodeUnicode()
369 {
370 constexpr char szReplacementUTF8[] = "\xEF\xBF\xBD";
371 unsigned nUCSChar;
372 if( m_osUnicodeHex.size() == 8 )
373 {
374 unsigned nUCSHigh = getUCSChar(m_osUnicodeHex);
375 assert( IsHighSurrogate(nUCSHigh) );
376 unsigned nUCSLow = getUCSChar(m_osUnicodeHex.substr(4));
377 if( IsLowSurrogate(nUCSLow) )
378 {
379 nUCSChar = GetSurrogatePair(nUCSHigh, nUCSLow);
380 }
381 else
382 {
383 /* Invalid code point. Insert the replacement char */
384 nUCSChar = 0xFFFFFFFFU;
385 }
386 }
387 else
388 {
389 assert( m_osUnicodeHex.size() == 4 );
390 nUCSChar = getUCSChar(m_osUnicodeHex);
391 }
392
393 if( nUCSChar < 0x80)
394 {
395 m_osToken += static_cast<char>(nUCSChar);
396 }
397 else if( nUCSChar < 0x800)
398 {
399 m_osToken += static_cast<char>(0xC0 | (nUCSChar >> 6));
400 m_osToken += static_cast<char>(0x80 | (nUCSChar & 0x3F));
401 }
402 else if (IsLowSurrogate(nUCSChar) ||
403 IsHighSurrogate(nUCSChar) )
404 {
405 /* Invalid code point. Insert the replacement char */
406 m_osToken += szReplacementUTF8;
407 }
408 else if (nUCSChar < 0x10000)
409 {
410 m_osToken += static_cast<char>(0xE0 | (nUCSChar >> 12));
411 m_osToken += static_cast<char>(0x80 | ((nUCSChar >> 6) & 0x3F));
412 m_osToken += static_cast<char>(0x80 | (nUCSChar & 0x3F));
413 }
414 else if (nUCSChar < 0x110000)
415 {
416 m_osToken += static_cast<char>(0xF0 | ((nUCSChar >> 18) & 0x07));
417 m_osToken += static_cast<char>(0x80 | ((nUCSChar >> 12) & 0x3F));
418 m_osToken += static_cast<char>(0x80 | ((nUCSChar >> 6) & 0x3F));
419 m_osToken += static_cast<char>(0x80 | (nUCSChar & 0x3F));
420 }
421 else
422 {
423 /* Invalid code point. Insert the replacement char */
424 m_osToken += szReplacementUTF8;
425 }
426
427 m_bInUnicode = false;
428 m_osUnicodeHex.clear();
429 }
430
431 /************************************************************************/
432 /* Parse() */
433 /************************************************************************/
434
Parse(const char * pStr,size_t nLength,bool bFinished)435 bool CPLJSonStreamingParser::Parse(const char* pStr, size_t nLength,
436 bool bFinished)
437 {
438 if( m_bExceptionOccurred )
439 return false;
440
441 while( true )
442 {
443 State eCurState = currentState();
444 if( eCurState == INIT )
445 {
446 SkipSpace(pStr, nLength);
447 if( nLength == 0 )
448 return true;
449 if( m_bElementFound || !IsValidNewToken(*pStr) )
450 {
451 return EmitUnexpectedChar(*pStr);
452 }
453 if( !StartNewToken(pStr, nLength) )
454 {
455 return false;
456 }
457 m_bElementFound = true;
458 }
459 else if( eCurState == NUMBER )
460 {
461 while(nLength)
462 {
463 char ch = *pStr;
464 if( ch == '+' || ch == '-' || isdigit(ch) ||
465 ch == '.' || ch == 'e' || ch == 'E' )
466 {
467 if( m_osToken.size() == 1024 )
468 {
469 return EmitException("Too many characters in number");
470 }
471 m_osToken += ch;
472 }
473 else if( isspace(ch) || ch == ',' || ch == '}' || ch == ']' )
474 {
475 SkipSpace(pStr, nLength);
476 break;
477 }
478 else
479 {
480 CPLString extendedToken(m_osToken + ch);
481 if( (STARTS_WITH_CI("Infinity", extendedToken) &&
482 m_osToken.size() + 1 <= strlen("Infinity")) ||
483 (STARTS_WITH_CI("-Infinity", extendedToken) &&
484 m_osToken.size() + 1 <= strlen("-Infinity")) ||
485 (STARTS_WITH_CI("NaN", extendedToken) &&
486 m_osToken.size() + 1 <= strlen("NaN")) )
487 {
488 m_osToken += ch;
489 }
490 else
491 {
492 return EmitUnexpectedChar(ch);
493 }
494 }
495 AdvanceChar(pStr, nLength);
496 }
497
498 if( nLength != 0 || bFinished )
499 {
500 const char firstCh = m_osToken[0];
501 if( firstCh == 'i' || firstCh == 'I' )
502 {
503 if( !EQUAL(m_osToken.c_str(), "Infinity") )
504 {
505 return EmitException("Invalid number");
506 }
507 }
508 else if( firstCh == '-' )
509 {
510 if( m_osToken[1] == 'i' || m_osToken[1] == 'I' )
511 {
512 if( !EQUAL(m_osToken.c_str(), "-Infinity") )
513 {
514 return EmitException("Invalid number");
515 }
516 }
517 }
518 else if( firstCh == 'n' || firstCh == 'N' )
519 {
520 if( m_osToken[1] == 'a' || m_osToken[1] == 'A' )
521 {
522 if( !EQUAL(m_osToken.c_str(), "NaN") )
523 {
524 return EmitException("Invalid number");
525 }
526 }
527 }
528
529 Number(m_osToken.c_str(), m_osToken.size());
530 m_osToken.clear();
531 m_aState.pop_back();
532 }
533
534 if( nLength == 0 )
535 {
536 if( bFinished )
537 {
538 return CheckStackEmpty();
539 }
540 return true;
541 }
542 }
543 else if( eCurState == STRING )
544 {
545 bool bEOS = false;
546 while( nLength )
547 {
548 if( m_osToken.size() == m_nMaxStringSize )
549 {
550 return EmitException("Too many characters in number");
551 }
552
553 char ch = *pStr;
554 if( m_bInUnicode)
555 {
556 if( m_osUnicodeHex.size() == 8 )
557 {
558 DecodeUnicode();
559 }
560 else if( m_osUnicodeHex.size() == 4 )
561 {
562 /* Start of next surrogate pair ? */
563 if( m_nLastChar == '\\' )
564 {
565 if( ch == 'u' )
566 {
567 AdvanceChar(pStr, nLength);
568 continue;
569 }
570 else
571 {
572 /* will be replacement character */
573 DecodeUnicode();
574 m_bInStringEscape = true;
575 }
576 }
577 else if( m_nLastChar == 'u' )
578 {
579 if( IsHexDigit(ch) )
580 {
581 m_osUnicodeHex += ch;
582 }
583 else
584 {
585 char szMessage[64];
586 snprintf(szMessage, sizeof(szMessage),
587 "Illegal character in unicode "
588 "sequence (\\%c)", ch);
589 return EmitException(szMessage);
590 }
591 AdvanceChar(pStr, nLength);
592 continue;
593 }
594 else if( ch == '\\' )
595 {
596 AdvanceChar(pStr, nLength);
597 continue;
598 }
599 else
600 {
601 /* will be replacement character */
602 DecodeUnicode();
603 }
604 }
605 else
606 {
607 if( IsHexDigit(ch) )
608 {
609 m_osUnicodeHex += ch;
610 if( m_osUnicodeHex.size() == 4 &&
611 !IsHighSurrogate(getUCSChar(m_osUnicodeHex)) )
612 {
613 DecodeUnicode();
614 }
615 }
616 else
617 {
618 char szMessage[64];
619 snprintf(szMessage, sizeof(szMessage),
620 "Illegal character in unicode "
621 "sequence (\\%c)", ch);
622 return EmitException(szMessage);
623 }
624 AdvanceChar(pStr, nLength);
625 continue;
626 }
627 }
628
629 if( m_bInStringEscape )
630 {
631 if( ch == '"' || ch == '\\' || ch == '/' )
632 m_osToken += ch;
633 else if( ch == 'b' )
634 m_osToken += '\b';
635 else if( ch == 'f' )
636 m_osToken += '\f';
637 else if( ch == 'n' )
638 m_osToken += '\n';
639 else if( ch == 'r' )
640 m_osToken += '\r';
641 else if( ch == 't' )
642 m_osToken += '\t';
643 else if( ch == 'u' )
644 {
645 m_bInUnicode = true;
646 }
647 else
648 {
649 char szMessage[32];
650 snprintf(szMessage, sizeof(szMessage),
651 "Illegal escape sequence (\\%c)", ch);
652 return EmitException(szMessage);
653 }
654 m_bInStringEscape = false;
655 AdvanceChar(pStr, nLength);
656 continue;
657 }
658 else if( ch == '\\' )
659 {
660 m_bInStringEscape = true;
661 AdvanceChar(pStr, nLength);
662 continue;
663 }
664 else if( ch == '"' )
665 {
666 bEOS = true;
667 AdvanceChar(pStr, nLength);
668 SkipSpace(pStr, nLength);
669
670 if( !m_aeObjectState.empty() &&
671 m_aeObjectState.back() == IN_KEY )
672 {
673 StartObjectMember(m_osToken.c_str(), m_osToken.size());
674 }
675 else
676 {
677 String(m_osToken.c_str(), m_osToken.size());
678 }
679 m_osToken.clear();
680 m_aState.pop_back();
681
682 break;
683 }
684
685 m_osToken += ch;
686 AdvanceChar(pStr, nLength);
687 }
688
689 if( nLength == 0 )
690 {
691 if( bFinished )
692 {
693 if( !bEOS )
694 {
695 return EmitException("Unterminated string");
696 }
697 return CheckStackEmpty();
698 }
699 return true;
700 }
701 }
702 else if( eCurState == ARRAY )
703 {
704 SkipSpace(pStr, nLength);
705 if( nLength == 0 )
706 {
707 if( bFinished )
708 {
709 return EmitException("Unterminated array");
710 }
711 return true;
712 }
713
714 char ch = *pStr;
715 if( ch == ',' )
716 {
717 if( m_abArrayState.back() != ArrayState::AFTER_VALUE )
718 {
719 return EmitUnexpectedChar(ch, "','");
720 }
721 m_abArrayState.back() = ArrayState::AFTER_COMMA;
722 AdvanceChar(pStr, nLength);
723 }
724 else if( ch == ']' )
725 {
726 if( m_abArrayState.back() == ArrayState::AFTER_COMMA)
727 {
728 return EmitException("Missing value");
729 }
730
731 EndArray();
732 AdvanceChar(pStr, nLength);
733 m_abArrayState.pop_back();
734 m_aState.pop_back();
735 }
736 else if( IsValidNewToken(ch) )
737 {
738 if( m_abArrayState.back() == ArrayState::AFTER_VALUE )
739 {
740 return EmitException("Unexpected state: ',' or ']' expected");
741 }
742 m_abArrayState.back() = ArrayState::AFTER_VALUE;
743
744 StartArrayMember();
745 if( !StartNewToken(pStr, nLength) )
746 {
747 return false;
748 }
749 }
750 else
751 {
752 return EmitUnexpectedChar(ch);
753 }
754 }
755 else if( eCurState == OBJECT )
756 {
757 SkipSpace(pStr, nLength);
758 if( nLength == 0 )
759 {
760 if( bFinished )
761 {
762 return EmitException("Unterminated object");
763 }
764 return true;
765 }
766
767 char ch = *pStr;
768 if( ch == ',' )
769 {
770 if( m_aeObjectState.back() != IN_VALUE )
771 {
772 return EmitUnexpectedChar(ch, "','");
773 }
774
775 m_aeObjectState.back() = WAITING_KEY;
776 AdvanceChar(pStr, nLength);
777 }
778 else if( ch == ':' )
779 {
780 if( m_aeObjectState.back() != IN_KEY )
781 {
782 return EmitUnexpectedChar(ch, "':'");
783 }
784 m_aeObjectState.back() = KEY_FINISHED;
785 AdvanceChar(pStr, nLength);
786 }
787 else if( ch == '}' )
788 {
789 if( m_aeObjectState.back() == WAITING_KEY ||
790 m_aeObjectState.back() == IN_VALUE )
791 {
792 // nothing
793 }
794 else
795 {
796 return EmitException("Missing value");
797 }
798
799 EndObject();
800 AdvanceChar(pStr, nLength);
801 m_aeObjectState.pop_back();
802 m_aState.pop_back();
803 }
804 else if( IsValidNewToken(ch) )
805 {
806 if( m_aeObjectState.back() == WAITING_KEY )
807 {
808 if( ch != '"' )
809 {
810 return EmitUnexpectedChar(ch, "'\"'");
811 }
812 m_aeObjectState.back() = IN_KEY;
813 }
814 else if( m_aeObjectState.back() == KEY_FINISHED )
815 {
816 m_aeObjectState.back() = IN_VALUE;
817 }
818 else
819 {
820 return EmitException("Unexpected state");
821 }
822 if( !StartNewToken(pStr, nLength) )
823 {
824 return false;
825 }
826 }
827 else
828 {
829 return EmitUnexpectedChar(ch);
830 }
831 }
832 else /* if( eCurState == STATE_TRUE || eCurState == STATE_FALSE ||
833 eCurState == STATE_NULL ) */
834 {
835 while(nLength)
836 {
837 char ch = *pStr;
838 if( eCurState == STATE_NULL && (ch == 'a' || ch == 'A') &&
839 m_osToken.size() == 1 )
840 {
841 m_aState.back() = NUMBER;
842 break;
843 }
844 if( isalpha(ch) )
845 {
846 m_osToken += ch;
847 if( eCurState == STATE_TRUE &&
848 (m_osToken.size() > strlen("true") ||
849 memcmp(m_osToken.c_str(), "true",
850 m_osToken.size()) != 0) )
851 {
852 return EmitUnexpectedChar(*pStr);
853 }
854 else if( eCurState == STATE_FALSE &&
855 (m_osToken.size() > strlen("false") ||
856 memcmp(m_osToken.c_str(), "false",
857 m_osToken.size()) != 0) )
858 {
859 return EmitUnexpectedChar(*pStr);
860 }
861 else if( eCurState == STATE_NULL &&
862 (m_osToken.size() > strlen("null") ||
863 memcmp(m_osToken.c_str(), "null",
864 m_osToken.size()) != 0) )
865 {
866 return EmitUnexpectedChar(*pStr);
867 }
868 }
869 else if( isspace(ch) || ch == ',' || ch == '}' || ch == ']' )
870 {
871 SkipSpace(pStr, nLength);
872 break;
873 }
874 else
875 {
876 return EmitUnexpectedChar(ch);
877 }
878 AdvanceChar(pStr, nLength);
879 }
880 if( m_aState.back() == NUMBER )
881 {
882 continue;
883 }
884 if( nLength == 0 )
885 {
886 if( bFinished )
887 {
888 if( !CheckAndEmitTrueFalseOrNull(0) )
889 return false;
890 return CheckStackEmpty();
891 }
892 return true;
893 }
894
895 if( !CheckAndEmitTrueFalseOrNull(*pStr) )
896 return false;
897 }
898 }
899 }
900
901
902 /************************************************************************/
903 /* GetSerializedString() */
904 /************************************************************************/
905
GetSerializedString(const char * pszStr)906 std::string CPLJSonStreamingParser::GetSerializedString(const char* pszStr)
907 {
908 std::string osStr("\"");
909 for( int i = 0; pszStr[i]; i++ )
910 {
911 char ch = pszStr[i];
912 if( ch == '\b' )
913 osStr += "\\b";
914 else if( ch == '\f' )
915 osStr += "\\f";
916 else if( ch == '\n' )
917 osStr += "\\n";
918 else if( ch == '\r' )
919 osStr += "\\r";
920 else if( ch == '\t' )
921 osStr += "\\t";
922 else if( ch == '"' )
923 osStr += "\\\"";
924 else if( ch == '\\' )
925 osStr += "\\\\";
926 else if( static_cast<unsigned char>(ch) < ' ' )
927 osStr += CPLSPrintf("\\u%04X", ch);
928 else
929 osStr += ch;
930 }
931 osStr += "\"";
932 return osStr;
933 }
934
935 /*! @endcond */
936