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