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