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 3381 : CPLJSonStreamingParser::CPLJSonStreamingParser()
31 : {
32 3381 : m_aState.push_back(INIT);
33 3381 : }
34 :
35 : /************************************************************************/
36 : /* ~CPLJSonStreamingParser() */
37 : /************************************************************************/
38 :
39 3381 : CPLJSonStreamingParser::~CPLJSonStreamingParser()
40 : {
41 3381 : }
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 2 : void CPLJSonStreamingParser::SetMaxStringSize(size_t nVal)
57 : {
58 2 : m_nMaxStringSize = nVal;
59 2 : }
60 :
61 : /************************************************************************/
62 : /* Reset() */
63 : /************************************************************************/
64 :
65 23 : void CPLJSonStreamingParser::Reset()
66 : {
67 23 : m_bExceptionOccurred = false;
68 23 : m_bElementFound = false;
69 23 : m_nLastChar = 0;
70 23 : m_nLineCounter = 1;
71 23 : m_nCharCounter = 1;
72 23 : m_aState.clear();
73 23 : m_aState.push_back(INIT);
74 23 : m_osToken.clear();
75 23 : m_abArrayState.clear();
76 23 : m_aeObjectState.clear();
77 23 : m_bInStringEscape = false;
78 23 : m_bInUnicode = false;
79 23 : m_osUnicodeHex.clear();
80 23 : }
81 :
82 : /************************************************************************/
83 : /* AdvanceChar() */
84 : /************************************************************************/
85 :
86 14956400 : void CPLJSonStreamingParser::AdvanceChar(const char *&pStr, size_t &nLength)
87 : {
88 14956400 : if (*pStr == 13 && m_nLastChar != 10)
89 : {
90 26 : m_nLineCounter++;
91 26 : m_nCharCounter = 0;
92 : }
93 14956400 : else if (*pStr == 10 && m_nLastChar != 13)
94 : {
95 201213 : m_nLineCounter++;
96 201213 : m_nCharCounter = 0;
97 : }
98 14956400 : m_nLastChar = *pStr;
99 :
100 14956400 : pStr++;
101 14956400 : nLength--;
102 14956400 : m_nCharCounter++;
103 14956400 : }
104 :
105 : /************************************************************************/
106 : /* SkipSpace() */
107 : /************************************************************************/
108 :
109 15927300 : void CPLJSonStreamingParser::SkipSpace(const char *&pStr, size_t &nLength)
110 : {
111 15927300 : while (nLength > 0 && isspace(static_cast<unsigned char>(*pStr)))
112 : {
113 13801400 : AdvanceChar(pStr, nLength);
114 : }
115 2125900 : }
116 :
117 : /************************************************************************/
118 : /* EmitException() */
119 : /************************************************************************/
120 :
121 88 : bool CPLJSonStreamingParser::EmitException(const char *pszMessage)
122 : {
123 88 : m_bExceptionOccurred = true;
124 88 : CPLString osMsg;
125 : osMsg.Printf("At line %d, character %d: %s", m_nLineCounter, m_nCharCounter,
126 88 : pszMessage);
127 88 : Exception(osMsg.c_str());
128 176 : return false;
129 : }
130 :
131 : /************************************************************************/
132 : /* StopParsing() */
133 : /************************************************************************/
134 :
135 2268 : void CPLJSonStreamingParser::StopParsing()
136 : {
137 2268 : m_bStopParsing = true;
138 2268 : }
139 :
140 : /************************************************************************/
141 : /* EmitUnexpectedChar() */
142 : /************************************************************************/
143 :
144 34 : bool CPLJSonStreamingParser::EmitUnexpectedChar(char ch,
145 : const char *pszExpecting)
146 : {
147 : char szMessage[64];
148 34 : if (pszExpecting)
149 : {
150 7 : snprintf(szMessage, sizeof(szMessage),
151 : "Unexpected character (%c). Expecting %s", ch, pszExpecting);
152 : }
153 : else
154 : {
155 27 : snprintf(szMessage, sizeof(szMessage), "Unexpected character (%c)", ch);
156 : }
157 68 : return EmitException(szMessage);
158 : }
159 :
160 : /************************************************************************/
161 : /* IsValidNewToken() */
162 : /************************************************************************/
163 :
164 793187 : static bool IsValidNewToken(char ch)
165 : {
166 566485 : return ch == '[' || ch == '{' || ch == '"' || ch == '-' || ch == '.' ||
167 371093 : isdigit(static_cast<unsigned char>(ch)) || ch == 't' || ch == 'f' ||
168 1359670 : ch == 'n' || ch == 'i' || ch == 'I' || ch == 'N';
169 : }
170 :
171 : /************************************************************************/
172 : /* StartNewToken() */
173 : /************************************************************************/
174 :
175 793173 : bool CPLJSonStreamingParser::StartNewToken(const char *&pStr, size_t &nLength)
176 : {
177 793173 : char ch = *pStr;
178 793173 : if (ch == '{')
179 : {
180 24059 : if (m_aState.size() == m_nMaxDepth)
181 : {
182 1 : return EmitException("Too many nested objects and/or arrays");
183 : }
184 24058 : StartObject();
185 24058 : m_aeObjectState.push_back(WAITING_KEY);
186 24058 : m_aState.push_back(OBJECT);
187 24058 : AdvanceChar(pStr, nLength);
188 : }
189 769114 : else if (ch == '"')
190 : {
191 97354 : m_aState.push_back(STRING);
192 97354 : AdvanceChar(pStr, nLength);
193 : }
194 671760 : else if (ch == '[')
195 : {
196 226702 : if (m_aState.size() == m_nMaxDepth)
197 : {
198 1 : return EmitException("Too many nested objects and/or arrays");
199 : }
200 226701 : StartArray();
201 226701 : m_abArrayState.push_back(ArrayState::INIT);
202 226701 : m_aState.push_back(ARRAY);
203 226701 : AdvanceChar(pStr, nLength);
204 : }
205 445058 : else if (ch == '-' || ch == '.' ||
206 371079 : isdigit(static_cast<unsigned char>(ch)) || ch == 'i' ||
207 1793 : ch == 'I' || ch == 'N')
208 : {
209 443267 : m_aState.push_back(NUMBER);
210 : }
211 1791 : else if (ch == 't')
212 : {
213 202 : m_aState.push_back(STATE_TRUE);
214 : }
215 1589 : else if (ch == 'f')
216 : {
217 11 : m_aState.push_back(STATE_FALSE);
218 : }
219 1578 : else if (ch == 'n')
220 : {
221 1578 : m_aState.push_back(STATE_NULL); /* might be nan */
222 : }
223 : else
224 : {
225 0 : assert(false);
226 : }
227 793171 : return true;
228 : }
229 :
230 : /************************************************************************/
231 : /* CheckAndEmitTrueFalseOrNull() */
232 : /************************************************************************/
233 :
234 1779 : bool CPLJSonStreamingParser::CheckAndEmitTrueFalseOrNull(char ch)
235 : {
236 1779 : State eCurState = currentState();
237 :
238 1779 : if (eCurState == STATE_TRUE)
239 : {
240 199 : if (m_osToken == "true")
241 : {
242 198 : Boolean(true);
243 : }
244 : else
245 : {
246 1 : return EmitUnexpectedChar(ch);
247 : }
248 : }
249 1580 : 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 1571 : if (m_osToken == "null")
263 : {
264 1570 : Null();
265 : }
266 : else
267 : {
268 1 : return EmitUnexpectedChar(ch);
269 : }
270 : }
271 1776 : m_aState.pop_back();
272 1776 : m_osToken.clear();
273 1776 : return true;
274 : }
275 :
276 : /************************************************************************/
277 : /* CheckStackEmpty() */
278 : /************************************************************************/
279 :
280 32 : bool CPLJSonStreamingParser::CheckStackEmpty()
281 : {
282 32 : if (!m_aeObjectState.empty())
283 : {
284 1 : return EmitException("Unterminated object");
285 : }
286 31 : else if (!m_abArrayState.empty())
287 : {
288 1 : return EmitException("Unterminated array");
289 : }
290 30 : return true;
291 : }
292 :
293 : /************************************************************************/
294 : /* IsHighSurrogate() */
295 : /************************************************************************/
296 :
297 39 : static bool IsHighSurrogate(unsigned uc)
298 : {
299 39 : return (uc & 0xFC00) == 0xD800;
300 : }
301 :
302 : /************************************************************************/
303 : /* IsLowSurrogate() */
304 : /************************************************************************/
305 :
306 16 : static bool IsLowSurrogate(unsigned uc)
307 : {
308 16 : return (uc & 0xFC00) == 0xDC00;
309 : }
310 :
311 : /************************************************************************/
312 : /* GetSurrogatePair() */
313 : /************************************************************************/
314 :
315 2 : static unsigned GetSurrogatePair(unsigned hi, unsigned lo)
316 : {
317 2 : return ((hi & 0x3FF) << 10) + (lo & 0x3FF) + 0x10000;
318 : }
319 :
320 : /************************************************************************/
321 : /* IsHexDigit() */
322 : /************************************************************************/
323 :
324 121 : static bool IsHexDigit(char ch)
325 : {
326 142 : return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
327 142 : (ch >= 'A' && ch <= 'F');
328 : }
329 :
330 : /************************************************************************/
331 : /* HexToDecimal() */
332 : /************************************************************************/
333 :
334 212 : static unsigned HexToDecimal(char ch)
335 : {
336 212 : if (ch >= '0' && ch <= '9')
337 167 : return ch - '0';
338 45 : if (ch >= 'a' && ch <= 'f')
339 16 : return 10 + ch - 'a';
340 : // if (ch >= 'A' && ch <= 'F' )
341 29 : return 10 + ch - 'A';
342 : }
343 :
344 : /************************************************************************/
345 : /* getUCSChar() */
346 : /************************************************************************/
347 :
348 53 : static unsigned getUCSChar(const std::string &unicode4HexChar)
349 : {
350 53 : return (HexToDecimal(unicode4HexChar[0]) << 12) |
351 53 : (HexToDecimal(unicode4HexChar[1]) << 8) |
352 53 : (HexToDecimal(unicode4HexChar[2]) << 4) |
353 53 : (HexToDecimal(unicode4HexChar[3]));
354 : }
355 :
356 : /************************************************************************/
357 : /* DecodeUnicode() */
358 : /************************************************************************/
359 :
360 24 : void CPLJSonStreamingParser::DecodeUnicode()
361 : {
362 24 : constexpr char szReplacementUTF8[] = "\xEF\xBF\xBD";
363 : unsigned nUCSChar;
364 24 : if (m_osUnicodeHex.size() == 8)
365 : {
366 4 : unsigned nUCSHigh = getUCSChar(m_osUnicodeHex);
367 4 : assert(IsHighSurrogate(nUCSHigh));
368 4 : unsigned nUCSLow = getUCSChar(m_osUnicodeHex.substr(4));
369 4 : if (IsLowSurrogate(nUCSLow))
370 : {
371 2 : nUCSChar = GetSurrogatePair(nUCSHigh, nUCSLow);
372 : }
373 : else
374 : {
375 : /* Invalid code point. Insert the replacement char */
376 2 : nUCSChar = 0xFFFFFFFFU;
377 : }
378 : }
379 : else
380 : {
381 20 : assert(m_osUnicodeHex.size() == 4);
382 20 : nUCSChar = getUCSChar(m_osUnicodeHex);
383 : }
384 :
385 24 : if (nUCSChar < 0x80)
386 : {
387 10 : m_osToken += static_cast<char>(nUCSChar);
388 : }
389 14 : else if (nUCSChar < 0x800)
390 : {
391 2 : m_osToken += static_cast<char>(0xC0 | (nUCSChar >> 6));
392 2 : m_osToken += static_cast<char>(0x80 | (nUCSChar & 0x3F));
393 : }
394 12 : else if (IsLowSurrogate(nUCSChar) || IsHighSurrogate(nUCSChar))
395 : {
396 : /* Invalid code point. Insert the replacement char */
397 8 : m_osToken += szReplacementUTF8;
398 : }
399 4 : 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 4 : else if (nUCSChar < 0x110000)
406 : {
407 2 : m_osToken += static_cast<char>(0xF0 | ((nUCSChar >> 18) & 0x07));
408 2 : m_osToken += static_cast<char>(0x80 | ((nUCSChar >> 12) & 0x3F));
409 2 : m_osToken += static_cast<char>(0x80 | ((nUCSChar >> 6) & 0x3F));
410 2 : m_osToken += static_cast<char>(0x80 | (nUCSChar & 0x3F));
411 : }
412 : else
413 : {
414 : /* Invalid code point. Insert the replacement char */
415 2 : m_osToken += szReplacementUTF8;
416 : }
417 :
418 24 : m_bInUnicode = false;
419 24 : m_osUnicodeHex.clear();
420 24 : }
421 :
422 : /************************************************************************/
423 : /* Parse() */
424 : /************************************************************************/
425 :
426 5609 : bool CPLJSonStreamingParser::Parse(std::string_view sStr, bool bFinished)
427 : {
428 5609 : const char *pStr = sStr.data();
429 5609 : size_t nLength = sStr.size();
430 : while (true)
431 : {
432 2129530 : if (m_bExceptionOccurred || m_bStopParsing)
433 2272 : return false;
434 2127260 : State eCurState = currentState();
435 2127260 : if (eCurState == INIT)
436 : {
437 4419 : SkipSpace(pStr, nLength);
438 4419 : if (nLength == 0)
439 1129 : return true;
440 3290 : if (m_bElementFound || !IsValidNewToken(*pStr))
441 : {
442 9 : return EmitUnexpectedChar(*pStr);
443 : }
444 3281 : if (!StartNewToken(pStr, nLength))
445 : {
446 2 : return false;
447 : }
448 3279 : m_bElementFound = true;
449 : }
450 2122840 : else if (eCurState == NUMBER)
451 : {
452 443475 : if (m_osToken.empty())
453 : {
454 : // Optimization to avoid using temporary buffer
455 : auto nPos =
456 443267 : std::string_view(pStr, nLength).find_first_of(" \t\r\n,}]");
457 443267 : if (nPos != std::string::npos)
458 : {
459 443088 : Number(std::string_view(pStr, nPos));
460 443088 : m_aState.pop_back();
461 443088 : pStr += nPos;
462 443088 : nLength -= nPos;
463 443088 : SkipSpace(pStr, nLength);
464 443088 : continue;
465 : }
466 : }
467 :
468 2992 : while (nLength)
469 : {
470 2789 : char ch = *pStr;
471 2789 : if (ch == '+' || ch == '-' ||
472 2753 : isdigit(static_cast<unsigned char>(ch)) || ch == '.' ||
473 256 : ch == 'e' || ch == 'E')
474 : {
475 2535 : if (m_osToken.size() == 1024)
476 : {
477 0 : return EmitException("Too many characters in number");
478 : }
479 2535 : m_osToken += ch;
480 : }
481 254 : else if (isspace(static_cast<unsigned char>(ch)) || ch == ',' ||
482 78 : ch == '}' || ch == ']')
483 : {
484 179 : SkipSpace(pStr, nLength);
485 179 : break;
486 : }
487 : else
488 : {
489 75 : CPLString extendedToken(m_osToken + ch);
490 75 : if ((STARTS_WITH_CI("Infinity", extendedToken) &&
491 31 : m_osToken.size() + 1 <= strlen("Infinity")) ||
492 44 : (STARTS_WITH_CI("-Infinity", extendedToken) &&
493 150 : m_osToken.size() + 1 <= strlen("-Infinity")) ||
494 13 : (STARTS_WITH_CI("NaN", extendedToken) &&
495 8 : m_osToken.size() + 1 <= strlen("NaN")))
496 : {
497 70 : m_osToken += ch;
498 : }
499 : else
500 : {
501 5 : return EmitUnexpectedChar(ch);
502 : }
503 : }
504 2605 : AdvanceChar(pStr, nLength);
505 : }
506 :
507 382 : if (nLength != 0 || bFinished)
508 : {
509 179 : const char firstCh = m_osToken[0];
510 179 : if (firstCh == 'i' || firstCh == 'I')
511 : {
512 3 : if (!EQUAL(m_osToken.c_str(), "Infinity"))
513 : {
514 1 : return EmitException("Invalid number");
515 : }
516 : }
517 176 : else if (firstCh == '-')
518 : {
519 33 : if (m_osToken[1] == 'i' || m_osToken[1] == 'I')
520 : {
521 3 : if (!EQUAL(m_osToken.c_str(), "-Infinity"))
522 : {
523 1 : return EmitException("Invalid number");
524 : }
525 : }
526 : }
527 143 : else if (firstCh == 'n' || firstCh == 'N')
528 : {
529 3 : if (m_osToken[1] == 'a' || m_osToken[1] == 'A')
530 : {
531 3 : if (!EQUAL(m_osToken.c_str(), "NaN"))
532 : {
533 1 : return EmitException("Invalid number");
534 : }
535 : }
536 : }
537 :
538 176 : Number(m_osToken);
539 176 : m_osToken.clear();
540 176 : m_aState.pop_back();
541 : }
542 :
543 379 : if (nLength == 0)
544 : {
545 214 : if (bFinished)
546 : {
547 11 : return CheckStackEmpty();
548 : }
549 203 : return true;
550 : }
551 : }
552 1679360 : else if (eCurState == STRING)
553 : {
554 98364 : bool bEOS = false;
555 :
556 98364 : if (m_osToken.empty() && !m_bInStringEscape && !m_bInUnicode)
557 : {
558 : // Optimization to avoid using temporary buffer
559 : auto nPos =
560 97491 : std::string_view(pStr, nLength).find_first_of("\"\\");
561 97491 : if (nPos != std::string::npos && pStr[nPos] == '"')
562 : {
563 97122 : if (nPos > m_nMaxStringSize)
564 : {
565 2 : return EmitException("Too many characters in number");
566 : }
567 194237 : if (!m_aeObjectState.empty() &&
568 97117 : m_aeObjectState.back() == IN_KEY)
569 : {
570 69899 : StartObjectMember(std::string_view(pStr, nPos));
571 : }
572 : else
573 : {
574 27221 : String(std::string_view(pStr, nPos));
575 : }
576 97120 : m_aState.pop_back();
577 97120 : pStr += nPos + 1;
578 97120 : nLength -= nPos + 1;
579 97120 : SkipSpace(pStr, nLength);
580 97120 : if (nLength != 0)
581 97116 : continue;
582 4 : bEOS = true;
583 : }
584 : }
585 :
586 9581 : while (nLength)
587 : {
588 8562 : if (m_osToken.size() == m_nMaxStringSize)
589 : {
590 0 : return EmitException("Too many characters in number");
591 : }
592 :
593 8562 : char ch = *pStr;
594 8562 : if (m_bInUnicode)
595 : {
596 143 : if (m_osUnicodeHex.size() == 8)
597 : {
598 4 : DecodeUnicode();
599 : }
600 139 : else if (m_osUnicodeHex.size() == 4)
601 : {
602 : /* Start of next surrogate pair ? */
603 23 : if (m_nLastChar == '\\')
604 : {
605 7 : if (ch == 'u')
606 : {
607 5 : AdvanceChar(pStr, nLength);
608 5 : continue;
609 : }
610 : else
611 : {
612 : /* will be replacement character */
613 2 : DecodeUnicode();
614 2 : m_bInStringEscape = true;
615 : }
616 : }
617 16 : else if (m_nLastChar == 'u')
618 : {
619 5 : if (IsHexDigit(ch))
620 : {
621 4 : m_osUnicodeHex += ch;
622 : }
623 : else
624 : {
625 : char szMessage[64];
626 1 : snprintf(szMessage, sizeof(szMessage),
627 : "Illegal character in unicode "
628 : "sequence (\\%c)",
629 : ch);
630 1 : return EmitException(szMessage);
631 : }
632 4 : AdvanceChar(pStr, nLength);
633 4 : continue;
634 : }
635 11 : else if (ch == '\\')
636 : {
637 7 : AdvanceChar(pStr, nLength);
638 7 : continue;
639 : }
640 : else
641 : {
642 : /* will be replacement character */
643 4 : DecodeUnicode();
644 : }
645 : }
646 : else
647 : {
648 116 : if (IsHexDigit(ch))
649 : {
650 115 : m_osUnicodeHex += ch;
651 140 : if (m_osUnicodeHex.size() == 4 &&
652 25 : !IsHighSurrogate(getUCSChar(m_osUnicodeHex)))
653 : {
654 14 : DecodeUnicode();
655 : }
656 : }
657 : else
658 : {
659 : char szMessage[64];
660 1 : snprintf(szMessage, sizeof(szMessage),
661 : "Illegal character in unicode "
662 : "sequence (\\%c)",
663 : ch);
664 1 : return EmitException(szMessage);
665 : }
666 115 : AdvanceChar(pStr, nLength);
667 115 : continue;
668 : }
669 : }
670 :
671 8429 : if (m_bInStringEscape)
672 : {
673 460 : if (ch == '"' || ch == '\\' || ch == '/')
674 419 : m_osToken += ch;
675 41 : else if (ch == 'b')
676 2 : m_osToken += '\b';
677 39 : else if (ch == 'f')
678 2 : m_osToken += '\f';
679 37 : else if (ch == 'n')
680 2 : m_osToken += '\n';
681 35 : else if (ch == 'r')
682 2 : m_osToken += '\r';
683 33 : else if (ch == 't')
684 4 : m_osToken += '\t';
685 29 : else if (ch == 'u')
686 : {
687 28 : m_bInUnicode = true;
688 : }
689 : else
690 : {
691 : char szMessage[32];
692 1 : snprintf(szMessage, sizeof(szMessage),
693 : "Illegal escape sequence (\\%c)", ch);
694 1 : return EmitException(szMessage);
695 : }
696 459 : m_bInStringEscape = false;
697 459 : AdvanceChar(pStr, nLength);
698 459 : continue;
699 : }
700 7969 : else if (ch == '\\')
701 : {
702 459 : m_bInStringEscape = true;
703 459 : AdvanceChar(pStr, nLength);
704 459 : continue;
705 : }
706 7510 : else if (ch == '"')
707 : {
708 224 : bEOS = true;
709 224 : AdvanceChar(pStr, nLength);
710 224 : SkipSpace(pStr, nLength);
711 :
712 437 : if (!m_aeObjectState.empty() &&
713 213 : m_aeObjectState.back() == IN_KEY)
714 : {
715 113 : StartObjectMember(m_osToken);
716 : }
717 : else
718 : {
719 111 : String(m_osToken);
720 : }
721 224 : m_osToken.clear();
722 224 : m_aState.pop_back();
723 :
724 224 : break;
725 : }
726 :
727 7286 : m_osToken += ch;
728 7286 : AdvanceChar(pStr, nLength);
729 : }
730 :
731 1243 : if (nLength == 0)
732 : {
733 1159 : if (bFinished)
734 : {
735 20 : if (!bEOS)
736 : {
737 5 : return EmitException("Unterminated string");
738 : }
739 15 : return CheckStackEmpty();
740 : }
741 1139 : return true;
742 : }
743 : }
744 1581000 : else if (eCurState == ARRAY)
745 : {
746 1299950 : SkipSpace(pStr, nLength);
747 1299950 : if (nLength == 0)
748 : {
749 180 : if (bFinished)
750 : {
751 23 : return EmitException("Unterminated array");
752 : }
753 157 : return true;
754 : }
755 :
756 1299770 : char ch = *pStr;
757 1299770 : if (ch == ',')
758 : {
759 423290 : if (m_abArrayState.back() != ArrayState::AFTER_VALUE)
760 : {
761 3 : return EmitUnexpectedChar(ch, "','");
762 : }
763 423287 : m_abArrayState.back() = ArrayState::AFTER_COMMA;
764 423287 : AdvanceChar(pStr, nLength);
765 : }
766 876482 : else if (ch == ']')
767 : {
768 226601 : if (m_abArrayState.back() == ArrayState::AFTER_COMMA)
769 : {
770 3 : return EmitException("Missing value");
771 : }
772 :
773 226598 : EndArray();
774 226598 : AdvanceChar(pStr, nLength);
775 226598 : m_abArrayState.pop_back();
776 226598 : m_aState.pop_back();
777 : }
778 649881 : else if (IsValidNewToken(ch))
779 : {
780 649880 : if (m_abArrayState.back() == ArrayState::AFTER_VALUE)
781 : {
782 1 : return EmitException(
783 1 : "Unexpected state: ',' or ']' expected");
784 : }
785 649879 : m_abArrayState.back() = ArrayState::AFTER_VALUE;
786 :
787 649879 : StartArrayMember();
788 649879 : if (!StartNewToken(pStr, nLength))
789 : {
790 0 : return false;
791 : }
792 : }
793 : else
794 : {
795 1 : return EmitUnexpectedChar(ch);
796 : }
797 : }
798 281047 : else if (eCurState == OBJECT)
799 : {
800 279126 : SkipSpace(pStr, nLength);
801 279126 : if (nLength == 0)
802 : {
803 469 : if (bFinished)
804 : {
805 4 : return EmitException("Unterminated object");
806 : }
807 465 : return true;
808 : }
809 :
810 278657 : char ch = *pStr;
811 278657 : if (ch == ',')
812 : {
813 46928 : if (m_aeObjectState.back() != IN_VALUE)
814 : {
815 2 : return EmitUnexpectedChar(ch, "','");
816 : }
817 :
818 46926 : m_aeObjectState.back() = WAITING_KEY;
819 46926 : AdvanceChar(pStr, nLength);
820 : }
821 231729 : else if (ch == ':')
822 : {
823 70003 : if (m_aeObjectState.back() != IN_KEY)
824 : {
825 1 : return EmitUnexpectedChar(ch, "':'");
826 : }
827 70002 : m_aeObjectState.back() = KEY_FINISHED;
828 70002 : AdvanceChar(pStr, nLength);
829 : }
830 161726 : else if (ch == '}')
831 : {
832 42453 : if (m_aeObjectState.back() == WAITING_KEY ||
833 20744 : m_aeObjectState.back() == IN_VALUE)
834 : {
835 : // nothing
836 : }
837 : else
838 : {
839 1 : return EmitException("Missing value");
840 : }
841 :
842 21708 : EndObject();
843 21708 : AdvanceChar(pStr, nLength);
844 21708 : m_aeObjectState.pop_back();
845 21708 : m_aState.pop_back();
846 : }
847 140017 : else if (IsValidNewToken(ch))
848 : {
849 140015 : if (m_aeObjectState.back() == WAITING_KEY)
850 : {
851 70013 : if (ch != '"')
852 : {
853 1 : return EmitUnexpectedChar(ch, "'\"'");
854 : }
855 70012 : m_aeObjectState.back() = IN_KEY;
856 : }
857 70002 : else if (m_aeObjectState.back() == KEY_FINISHED)
858 : {
859 70001 : m_aeObjectState.back() = IN_VALUE;
860 : }
861 : else
862 : {
863 1 : return EmitException("Unexpected state");
864 : }
865 140013 : if (!StartNewToken(pStr, nLength))
866 : {
867 0 : return false;
868 : }
869 : }
870 : else
871 : {
872 2 : return EmitUnexpectedChar(ch);
873 : }
874 : }
875 : else /* if( eCurState == STATE_TRUE || eCurState == STATE_FALSE ||
876 : eCurState == STATE_NULL ) */
877 : {
878 9074 : while (nLength)
879 : {
880 8954 : char ch = *pStr;
881 8959 : if (eCurState == STATE_NULL && (ch == 'a' || ch == 'A') &&
882 5 : m_osToken.size() == 1)
883 : {
884 5 : m_aState.back() = NUMBER;
885 5 : break;
886 : }
887 8949 : if (isalpha(static_cast<unsigned char>(ch)))
888 : {
889 7159 : m_osToken += ch;
890 8772 : if (eCurState == STATE_TRUE &&
891 807 : (m_osToken.size() > strlen("true") ||
892 806 : memcmp(m_osToken.c_str(), "true", m_osToken.size()) !=
893 : 0))
894 : {
895 2 : return EmitUnexpectedChar(*pStr);
896 : }
897 7266 : else if (eCurState == STATE_FALSE &&
898 55 : (m_osToken.size() > strlen("false") ||
899 54 : memcmp(m_osToken.c_str(), "false",
900 : m_osToken.size()) != 0))
901 : {
902 2 : return EmitUnexpectedChar(*pStr);
903 : }
904 19748 : else if (eCurState == STATE_NULL &&
905 6297 : (m_osToken.size() > strlen("null") ||
906 6296 : memcmp(m_osToken.c_str(), "null",
907 : m_osToken.size()) != 0))
908 : {
909 2 : return EmitUnexpectedChar(*pStr);
910 : }
911 : }
912 1790 : else if (isspace(static_cast<unsigned char>(ch)) || ch == ',' ||
913 55 : ch == '}' || ch == ']')
914 : {
915 1789 : SkipSpace(pStr, nLength);
916 1789 : break;
917 : }
918 : else
919 : {
920 1 : return EmitUnexpectedChar(ch);
921 : }
922 7153 : AdvanceChar(pStr, nLength);
923 : }
924 1914 : if (m_aState.back() == NUMBER)
925 : {
926 5 : continue;
927 : }
928 1909 : if (nLength == 0)
929 : {
930 139 : if (bFinished)
931 : {
932 9 : if (!CheckAndEmitTrueFalseOrNull(0))
933 3 : return false;
934 6 : return CheckStackEmpty();
935 : }
936 130 : return true;
937 : }
938 :
939 1770 : if (!CheckAndEmitTrueFalseOrNull(*pStr))
940 0 : return false;
941 : }
942 2123920 : }
943 : }
944 :
945 : /************************************************************************/
946 : /* GetSerializedString() */
947 : /************************************************************************/
948 :
949 11180 : std::string CPLJSonStreamingParser::GetSerializedString(std::string_view s)
950 : {
951 11180 : std::string osStr("\"");
952 87598 : for (char ch : s)
953 : {
954 76418 : if (ch == '\b')
955 2 : osStr += "\\b";
956 76416 : else if (ch == '\f')
957 2 : osStr += "\\f";
958 76414 : else if (ch == '\n')
959 2 : osStr += "\\n";
960 76412 : else if (ch == '\r')
961 2 : osStr += "\\r";
962 76410 : else if (ch == '\t')
963 4 : osStr += "\\t";
964 76406 : else if (ch == '"')
965 2 : osStr += "\\\"";
966 76404 : else if (ch == '\\')
967 2 : osStr += "\\\\";
968 76402 : else if (static_cast<unsigned char>(ch) < ' ')
969 4 : osStr += CPLSPrintf("\\u%04X", ch);
970 : else
971 76398 : osStr += ch;
972 : }
973 11180 : osStr += "\"";
974 11180 : return osStr;
975 : }
976 :
977 : /*! @endcond */
|