Coverage Report

Created: 2025-06-13 06:29

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