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