Coverage Report

Created: 2024-02-11 07:55

/src/opencv/modules/core/src/persistence_json.cpp
Line
Count
Source (jump to first uncovered line)
1
// This file is part of OpenCV project.
2
// It is subject to the license terms in the LICENSE file found in the top-level directory
3
// of this distribution and at http://opencv.org/license.html
4
5
#include "precomp.hpp"
6
#include "persistence.hpp"
7
8
namespace cv
9
{
10
11
class JSONEmitter : public FileStorageEmitter
12
{
13
public:
14
    JSONEmitter(FileStorage_API* _fs) : fs(_fs)
15
0
    {
16
0
    }
17
0
    virtual ~JSONEmitter() {}
18
19
    FStructData startWriteStruct( const FStructData& parent, const char* key,
20
                                  int struct_flags, const char* type_name=0 )
21
0
    {
22
0
        char data[CV_FS_MAX_LEN + 1024];
23
24
0
        struct_flags = (struct_flags & (FileNode::TYPE_MASK|FileNode::FLOW)) | FileNode::EMPTY;
25
0
        if( !FileNode::isCollection(struct_flags))
26
0
            CV_Error( cv::Error::StsBadArg,
27
0
                     "Some collection type - FileNode::SEQ or FileNode::MAP, must be specified" );
28
29
0
        if( type_name && *type_name == '\0' )
30
0
            type_name = 0;
31
32
0
        bool is_real_collection = true;
33
0
        if (type_name && memcmp(type_name, "binary", 6) == 0)
34
0
        {
35
0
            struct_flags = FileNode::STR;
36
0
            data[0] = '\0';
37
0
            is_real_collection = false;
38
0
        }
39
40
0
        if ( is_real_collection )
41
0
        {
42
0
            char c = FileNode::isMap(struct_flags) ? '{' : '[';
43
0
            data[0] = c;
44
0
            data[1] = '\0';
45
0
        }
46
47
0
        writeScalar( key, data );
48
0
        FStructData current_struct("", struct_flags, parent.indent + 4);
49
50
0
        return current_struct;
51
0
    }
52
53
    void endWriteStruct(const FStructData& current_struct)
54
0
    {
55
0
        int struct_flags = current_struct.flags;
56
57
0
        if (FileNode::isCollection(struct_flags)) {
58
0
            if (!FileNode::isFlow(struct_flags)) {
59
0
                if (fs->bufferPtr() <= fs->bufferStart() + fs->get_space()) {
60
                    /* some bad code for base64_writer... */
61
0
                    char *ptr = fs->bufferPtr();
62
0
                    *ptr++ = '\n';
63
0
                    *ptr++ = '\0';
64
0
                    fs->puts(fs->bufferStart());
65
0
                    fs->setBufferPtr(fs->bufferStart());
66
0
                }
67
0
                fs->flush();
68
0
            }
69
70
0
            char *ptr = fs->bufferPtr();
71
0
            if (ptr > fs->bufferStart() + current_struct.indent && !FileNode::isEmptyCollection(struct_flags))
72
0
                *ptr++ = ' ';
73
0
            *ptr++ = FileNode::isMap(struct_flags) ? '}' : ']';
74
0
            fs->setBufferPtr(ptr);
75
0
        }
76
0
    }
77
78
    void write(const char* key, int value)
79
0
    {
80
0
        char buf[128];
81
0
        writeScalar( key, fs::itoa( value, buf, 10 ));
82
0
    }
83
84
    void write( const char* key, double value )
85
0
    {
86
0
        char buf[128];
87
0
        writeScalar( key, fs::doubleToString( buf, sizeof(buf), value, true ));
88
0
    }
89
90
    void write(const char* key, const char* str, bool quote)
91
0
    {
92
0
        char buf[CV_FS_MAX_LEN*4+16];
93
0
        char* data = (char*)str;
94
0
        int i, len;
95
96
0
        if( !str )
97
0
            CV_Error( cv::Error::StsNullPtr, "Null string pointer" );
98
99
0
        len = (int)strlen(str);
100
0
        if( len > CV_FS_MAX_LEN )
101
0
            CV_Error( cv::Error::StsBadArg, "The written string is too long" );
102
103
0
        if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
104
0
        {
105
0
            int need_quote = 1;
106
0
            data = buf;
107
0
            *data++ = '\"';
108
0
            for( i = 0; i < len; i++ )
109
0
            {
110
0
                char c = str[i];
111
112
0
                switch ( c )
113
0
                {
114
0
                case '\\':
115
0
                case '\"':
116
0
                case '\'': { *data++ = '\\'; *data++ = c;   break; }
117
0
                case '\n': { *data++ = '\\'; *data++ = 'n'; break; }
118
0
                case '\r': { *data++ = '\\'; *data++ = 'r'; break; }
119
0
                case '\t': { *data++ = '\\'; *data++ = 't'; break; }
120
0
                case '\b': { *data++ = '\\'; *data++ = 'b'; break; }
121
0
                case '\f': { *data++ = '\\'; *data++ = 'f'; break; }
122
0
                default  : { *data++ = c; }
123
0
                }
124
0
            }
125
126
0
            *data++ = '\"';
127
0
            *data++ = '\0';
128
0
            data = buf + !need_quote;
129
0
        }
130
131
0
        writeScalar( key, data);
132
0
    }
133
134
    void writeScalar(const char* key, const char* data)
135
0
    {
136
        /* check write_struct */
137
138
0
        fs->check_if_write_struct_is_delayed(false);
139
0
        if ( fs->get_state_of_writing_base64() == FileStorage_API::Uncertain )
140
0
        {
141
0
            fs->switch_to_Base64_state( FileStorage_API::NotUse );
142
0
        }
143
0
        else if ( fs->get_state_of_writing_base64() == FileStorage_API::InUse )
144
0
        {
145
0
            CV_Error( cv::Error::StsError, "At present, output Base64 data only." );
146
0
        }
147
148
        /* check parameters */
149
150
0
        size_t key_len = 0u;
151
0
        if( key && *key == '\0' )
152
0
            key = 0;
153
0
        if ( key )
154
0
        {
155
0
            key_len = strlen(key);
156
0
            if ( key_len == 0u )
157
0
                CV_Error( cv::Error::StsBadArg, "The key is an empty" );
158
0
            else if ( static_cast<int>(key_len) > CV_FS_MAX_LEN )
159
0
                CV_Error( cv::Error::StsBadArg, "The key is too long" );
160
0
        }
161
162
0
        size_t data_len = 0u;
163
0
        if ( data )
164
0
            data_len = strlen(data);
165
166
0
        FStructData& current_struct = fs->getCurrentStruct();
167
0
        int struct_flags = current_struct.flags;
168
0
        if( FileNode::isCollection(struct_flags) )
169
0
        {
170
0
            if ( (FileNode::isMap(struct_flags) ^ (key != 0)) )
171
0
                CV_Error( cv::Error::StsBadArg, "An attempt to add element without a key to a map, "
172
0
                         "or add element with key to sequence" );
173
0
        } else {
174
0
            fs->setNonEmpty();
175
0
            struct_flags = FileNode::EMPTY | (key ? FileNode::MAP : FileNode::SEQ);
176
0
        }
177
178
        // start to write
179
0
        char* ptr = 0;
180
181
0
        if( FileNode::isFlow(struct_flags) )
182
0
        {
183
0
            int new_offset;
184
0
            ptr = fs->bufferPtr();
185
0
            if( !FileNode::isEmptyCollection(struct_flags) )
186
0
                *ptr++ = ',';
187
0
            new_offset = static_cast<int>(ptr - fs->bufferStart() + key_len + data_len);
188
0
            if( new_offset > fs->wrapMargin() && new_offset - current_struct.indent > 10 )
189
0
            {
190
0
                fs->setBufferPtr(ptr);
191
0
                ptr = fs->flush();
192
0
            }
193
0
            else
194
0
                *ptr++ = ' ';
195
0
        }
196
0
        else
197
0
        {
198
0
            if ( !FileNode::isEmptyCollection(struct_flags) )
199
0
            {
200
0
                ptr = fs->bufferPtr();
201
0
                *ptr++ = ',';
202
0
                *ptr++ = '\n';
203
0
                *ptr++ = '\0';
204
0
                fs->puts( fs->bufferStart() );
205
0
                fs->setBufferPtr(fs->bufferStart());
206
0
            }
207
0
            ptr = fs->flush();
208
0
        }
209
210
0
        if( key )
211
0
        {
212
0
            if( !cv_isalpha(key[0]) && key[0] != '_' )
213
0
                CV_Error( cv::Error::StsBadArg, "Key must start with a letter or _" );
214
215
0
            ptr = fs->resizeWriteBuffer( ptr, static_cast<int>(key_len) );
216
0
            *ptr++ = '\"';
217
218
0
            for( size_t i = 0u; i < key_len; i++ )
219
0
            {
220
0
                char c = key[i];
221
222
0
                ptr[i] = c;
223
0
                if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
224
0
                    CV_Error( cv::Error::StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
225
0
            }
226
227
0
            ptr += key_len;
228
0
            *ptr++ = '\"';
229
0
            *ptr++ = ':';
230
0
            *ptr++ = ' ';
231
0
        }
232
233
0
        if( data )
234
0
        {
235
0
            ptr = fs->resizeWriteBuffer( ptr, static_cast<int>(data_len) );
236
0
            memcpy( ptr, data, data_len );
237
0
            ptr += data_len;
238
0
        }
239
240
0
        fs->setBufferPtr(ptr);
241
0
        current_struct.flags &= ~FileNode::EMPTY;
242
0
    }
243
244
    void writeComment(const char* comment, bool eol_comment)
245
0
    {
246
0
        if( !comment )
247
0
            CV_Error( cv::Error::StsNullPtr, "Null comment" );
248
249
0
        int len = static_cast<int>(strlen(comment));
250
0
        char* ptr = fs->bufferPtr();
251
0
        const char* eol = strchr(comment, '\n');
252
0
        bool multiline = eol != 0;
253
254
0
        if( !eol_comment || multiline || fs->bufferEnd() - ptr < len || ptr == fs->bufferStart() )
255
0
            ptr = fs->flush();
256
0
        else
257
0
            *ptr++ = ' ';
258
259
0
        while( comment )
260
0
        {
261
0
            *ptr++ = '/';
262
0
            *ptr++ = '/';
263
0
            *ptr++ = ' ';
264
0
            if( eol )
265
0
            {
266
0
                ptr = fs->resizeWriteBuffer( ptr, (int)(eol - comment) + 1 );
267
0
                memcpy( ptr, comment, eol - comment + 1 );
268
0
                fs->setBufferPtr(ptr + (eol - comment));
269
0
                comment = eol + 1;
270
0
                eol = strchr( comment, '\n' );
271
0
            }
272
0
            else
273
0
            {
274
0
                len = (int)strlen(comment);
275
0
                ptr = fs->resizeWriteBuffer( ptr, len );
276
0
                memcpy( ptr, comment, len );
277
0
                fs->setBufferPtr(ptr + len);
278
0
                comment = 0;
279
0
            }
280
0
            ptr = fs->flush();
281
0
        }
282
0
    }
283
284
    void startNextStream()
285
0
    {
286
0
        fs->puts( "...\n" );
287
0
        fs->puts( "---\n" );
288
0
    }
289
290
protected:
291
    FileStorage_API* fs;
292
};
293
294
class JSONParser : public FileStorageParser
295
{
296
public:
297
    JSONParser(FileStorage_API* _fs) : fs(_fs)
298
0
    {
299
0
    }
300
301
0
    virtual ~JSONParser() {}
302
303
    char* skipSpaces( char* ptr )
304
0
    {
305
0
        bool is_eof = false;
306
0
        bool is_completed = false;
307
308
0
        while ( is_eof == false && is_completed == false )
309
0
        {
310
0
            if (!ptr)
311
0
                CV_PARSE_ERROR_CPP("Invalid input");
312
0
            switch ( *ptr )
313
0
            {
314
                /* comment */
315
0
                case '/' : {
316
0
                    ptr++;
317
0
                    if ( *ptr == '\0' )
318
0
                    {
319
0
                        ptr = fs->gets();
320
0
                        if( !ptr || !*ptr ) { is_eof = true; break; }
321
0
                    }
322
323
0
                    if ( *ptr == '/' )
324
0
                    {
325
0
                        while ( *ptr != '\n' && *ptr != '\r' )
326
0
                        {
327
0
                            if ( *ptr == '\0' )
328
0
                            {
329
0
                                ptr = fs->gets();
330
0
                                if( !ptr || !*ptr ) { is_eof = true; break; }
331
0
                            }
332
0
                            else
333
0
                            {
334
0
                                ptr++;
335
0
                            }
336
0
                        }
337
0
                    }
338
0
                    else if ( *ptr == '*' )
339
0
                    {
340
0
                        ptr++;
341
0
                        for (;;)
342
0
                        {
343
0
                            if ( *ptr == '\0' )
344
0
                            {
345
0
                                ptr = fs->gets();
346
0
                                if( !ptr || !*ptr ) { is_eof = true; break; }
347
0
                            }
348
0
                            else if ( *ptr == '*' )
349
0
                            {
350
0
                                ptr++;
351
0
                                if ( *ptr == '\0' )
352
0
                                {
353
0
                                    ptr = fs->gets();
354
0
                                    if( !ptr || !*ptr ) { is_eof = true; break; }
355
0
                                }
356
0
                                if ( *ptr == '/' )
357
0
                                {
358
0
                                    ptr++;
359
0
                                    break;
360
0
                                }
361
0
                            }
362
0
                            else
363
0
                            {
364
0
                                ptr++;
365
0
                            }
366
0
                        }
367
0
                    }
368
0
                    else
369
0
                    {
370
0
                        CV_PARSE_ERROR_CPP( "Not supported escape character" );
371
0
                    }
372
0
                } break;
373
                    /* whitespace */
374
0
                case '\t':
375
0
                case ' ' : {
376
0
                    ptr++;
377
0
                } break;
378
                    /* newline || end mark */
379
0
                case '\0':
380
0
                case '\n':
381
0
                case '\r': {
382
0
                    ptr = fs->gets();
383
0
                    if( !ptr || !*ptr ) { is_eof = true; break; }
384
0
                } break;
385
                    /* other character */
386
0
                default: {
387
0
                    if( !cv_isprint(*ptr) )
388
0
                        CV_PARSE_ERROR_CPP( "Invalid character in the stream" );
389
0
                    is_completed = true;
390
0
                } break;
391
0
            }
392
0
        }
393
394
0
        if ( is_eof || !is_completed )
395
0
        {
396
0
            ptr = fs->bufferStart();
397
0
            CV_Assert(ptr);
398
0
            *ptr = '\0';
399
0
            fs->setEof();
400
0
            if( !is_completed )
401
0
                CV_PARSE_ERROR_CPP( "Abort at parse time" );
402
0
        }
403
404
0
        return ptr;
405
0
    }
406
407
    char* parseKey( char* ptr, FileNode& collection, FileNode& value_placeholder )
408
0
    {
409
0
        if (!ptr)
410
0
            CV_PARSE_ERROR_CPP("Invalid input");
411
412
0
        if( *ptr != '"' )
413
0
            CV_PARSE_ERROR_CPP( "Key must start with \'\"\'" );
414
415
0
        char * beg = ptr + 1;
416
417
0
        do {
418
0
            ++ptr;
419
0
            CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();
420
0
        } while( cv_isprint(*ptr) && *ptr != '"' );
421
422
0
        if( *ptr != '"' )
423
0
            CV_PARSE_ERROR_CPP( "Key must end with \'\"\'" );
424
425
0
        if( ptr == beg )
426
0
            CV_PARSE_ERROR_CPP( "Key is empty" );
427
0
        value_placeholder = fs->addNode(collection, std::string(beg, (size_t)(ptr - beg)), FileNode::NONE);
428
429
0
        ptr++;
430
0
        ptr = skipSpaces( ptr );
431
0
        if( !ptr || !*ptr )
432
0
            return 0;
433
434
0
        if( *ptr != ':' )
435
0
            CV_PARSE_ERROR_CPP( "Missing \':\' between key and value" );
436
437
0
        return ++ptr;
438
0
    }
439
440
    bool getBase64Row(char* ptr, int /*indent*/, char* &beg, char* &end)
441
0
    {
442
0
        beg = end = ptr;
443
0
        if( !ptr || !*ptr )
444
0
            return false;
445
446
        // find end of the row
447
0
        while( cv_isprint(*ptr) && (*ptr != ',') && (*ptr != '"'))
448
0
            ++ptr;
449
0
        if ( *ptr == '\0' )
450
0
            CV_PARSE_ERROR_CPP( "Unexpected end of line" );
451
452
0
        end = ptr;
453
0
        return true;
454
0
    }
455
456
    char* parseValue( char* ptr, FileNode& node )
457
0
    {
458
0
        if (!ptr)
459
0
            CV_PARSE_ERROR_CPP("Invalid value input");
460
461
0
        ptr = skipSpaces( ptr );
462
0
        if( !ptr || !*ptr )
463
0
            CV_PARSE_ERROR_CPP( "Unexpected End-Of-File" );
464
465
0
        if( *ptr == '"' )
466
0
        {   /* must be string or Base64 string */
467
0
            ptr++;
468
0
            char * beg = ptr;
469
0
            size_t len = 0u;
470
0
            for ( ; (cv_isalnum(*ptr) || *ptr == '$' ) && len <= 9u; ptr++ )
471
0
                len++;
472
473
0
            if ((len >= 8u) && (memcmp( beg, "$base64$", 8u ) == 0) )
474
0
            {   /**************** Base64 string ****************/
475
0
                ptr = beg + 8;
476
0
                ptr = fs->parseBase64(ptr, 0, node);
477
478
0
                if ( *ptr != '\"' )
479
0
                    CV_PARSE_ERROR_CPP( "'\"' - right-quote of string is missing" );
480
0
                else
481
0
                    ptr++;
482
0
            }
483
0
            else
484
0
            {   /**************** normal string ****************/
485
0
                int i = 0, sz;
486
487
0
                ptr = beg;
488
0
                bool is_matching = false;
489
0
                while ( !is_matching )
490
0
                {
491
0
                    switch ( *ptr )
492
0
                    {
493
0
                        case '\\':
494
0
                        {
495
0
                            sz = (int)(ptr - beg);
496
0
                            if( sz > 0 )
497
0
                            {
498
0
                                if (i + sz >= CV_FS_MAX_LEN)
499
0
                                    CV_PARSE_ERROR_CPP("string is too long");
500
0
                                memcpy(buf + i, beg, sz);
501
0
                                i += sz;
502
0
                            }
503
0
                            ptr++;
504
0
                            if (i + 1 >= CV_FS_MAX_LEN)
505
0
                                CV_PARSE_ERROR_CPP("string is too long");
506
0
                            switch ( *ptr )
507
0
                            {
508
0
                            case '\\':
509
0
                            case '\"':
510
0
                            case '\'': { buf[i++] = *ptr; break; }
511
0
                            case 'n' : { buf[i++] = '\n'; break; }
512
0
                            case 'r' : { buf[i++] = '\r'; break; }
513
0
                            case 't' : { buf[i++] = '\t'; break; }
514
0
                            case 'b' : { buf[i++] = '\b'; break; }
515
0
                            case 'f' : { buf[i++] = '\f'; break; }
516
0
                            case 'u' : { CV_PARSE_ERROR_CPP( "'\\uXXXX' currently not supported" ); break; }
517
0
                            default  : { CV_PARSE_ERROR_CPP( "Invalid escape character" ); }
518
0
                            break;
519
0
                            }
520
0
                            ptr++;
521
0
                            beg = ptr;
522
0
                            break;
523
0
                        }
524
0
                        case '\0':
525
0
                        {
526
0
                            sz = (int)(ptr - beg);
527
0
                            if( sz > 0 )
528
0
                            {
529
0
                                if (i + sz >= CV_FS_MAX_LEN)
530
0
                                    CV_PARSE_ERROR_CPP("string is too long");
531
0
                                memcpy(buf + i, beg, sz);
532
0
                                i += sz;
533
0
                            }
534
0
                            ptr = fs->gets();
535
0
                            if ( !ptr || !*ptr )
536
0
                                CV_PARSE_ERROR_CPP( "'\"' - right-quote of string is missing" );
537
538
0
                            beg = ptr;
539
0
                            break;
540
0
                        }
541
0
                        case '\"':
542
0
                        {
543
0
                            sz = (int)(ptr - beg);
544
0
                            if( sz > 0 )
545
0
                            {
546
0
                                if (i + sz >= CV_FS_MAX_LEN)
547
0
                                    CV_PARSE_ERROR_CPP("string is too long");
548
0
                                memcpy(buf + i, beg, sz);
549
0
                                i += sz;
550
0
                            }
551
0
                            beg = ptr;
552
0
                            is_matching = true;
553
0
                            break;
554
0
                        }
555
0
                        case '\n':
556
0
                        case '\r':
557
0
                        {
558
0
                            CV_PARSE_ERROR_CPP( "'\"' - right-quote of string is missing" );
559
0
                            break;
560
0
                        }
561
0
                        default:
562
0
                        {
563
0
                            ptr++;
564
0
                            break;
565
0
                        }
566
0
                    }
567
0
                }
568
569
0
                if ( *ptr != '\"' )
570
0
                    CV_PARSE_ERROR_CPP( "'\"' - right-quote of string is missing" );
571
0
                else
572
0
                    ptr++;
573
574
0
                node.setValue(FileNode::STRING, buf, i);
575
0
            }
576
0
        }
577
0
        else if ( cv_isdigit(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.' )
578
0
        {    /**************** number ****************/
579
0
            char * beg = ptr;
580
0
            if ( *ptr == '+' || *ptr == '-' )
581
0
            {
582
0
                ptr++;
583
0
                CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();
584
0
            }
585
0
            while( cv_isdigit(*ptr) )
586
0
            {
587
0
                ptr++;
588
0
                CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();
589
0
            }
590
0
            if (*ptr == '.' || *ptr == 'e')
591
0
            {
592
0
                double fval = fs->strtod( beg, &ptr );
593
0
                CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();
594
595
0
                node.setValue(FileNode::REAL, &fval);
596
0
            }
597
0
            else
598
0
            {
599
0
                int ival = (int)strtol( beg, &ptr, 0 );
600
0
                CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();
601
602
0
                node.setValue(FileNode::INT, &ival);
603
0
            }
604
605
0
            if ( beg >= ptr )
606
0
                CV_PARSE_ERROR_CPP( "Invalid numeric value (inconsistent explicit type specification?)" );
607
0
        }
608
0
        else
609
0
        {    /**************** other data ****************/
610
0
            const char* beg = ptr;
611
0
            int len = 0;
612
0
            for ( ; cv_isalpha(*ptr) && len <= 6; )
613
0
            {
614
0
                len++;
615
0
                ptr++;
616
0
                CV_PERSISTENCE_CHECK_END_OF_BUFFER_BUG_CPP();
617
0
            }
618
619
0
            if( len == 4 && memcmp( beg, "null", 4 ) == 0 )
620
0
            {
621
0
                CV_PARSE_ERROR_CPP( "Value 'null' is not supported by this parser" );
622
0
            }
623
0
            else if( (len == 4 && memcmp( beg, "true", 4 ) == 0) ||
624
0
                     (len == 5 && memcmp( beg, "false", 5 ) == 0) )
625
0
            {
626
0
                int ival = *beg == 't' ? 1 : 0;
627
0
                node.setValue(FileNode::INT, &ival);
628
0
            }
629
0
            else
630
0
            {
631
0
                CV_PARSE_ERROR_CPP( "Unrecognized value" );
632
0
            }
633
0
        }
634
635
0
        return ptr;
636
0
    }
637
638
    char* parseSeq( char* ptr, FileNode& node )
639
0
    {
640
0
        if (!ptr)
641
0
            CV_PARSE_ERROR_CPP( "ptr is NULL" );
642
643
0
        if ( *ptr != '[' )
644
0
            CV_PARSE_ERROR_CPP( "'[' - left-brace of seq is missing" );
645
0
        else
646
0
            ptr++;
647
648
0
        fs->convertToCollection(FileNode::SEQ, node);
649
650
0
        for (;;)
651
0
        {
652
0
            ptr = skipSpaces( ptr );
653
0
            if( !ptr || !*ptr )
654
0
                break;
655
656
0
            if ( *ptr != ']' )
657
0
            {
658
0
                FileNode child = fs->addNode(node, std::string(), FileNode::NONE );
659
660
0
                if ( *ptr == '[' )
661
0
                    ptr = parseSeq( ptr, child );
662
0
                else if ( *ptr == '{' )
663
0
                    ptr = parseMap( ptr, child );
664
0
                else
665
0
                    ptr = parseValue( ptr, child );
666
0
            }
667
668
0
            ptr = skipSpaces( ptr );
669
0
            if( !ptr || !*ptr )
670
0
                break;
671
672
0
            if ( *ptr == ',' )
673
0
                ptr++;
674
0
            else if ( *ptr == ']' )
675
0
                break;
676
0
            else
677
0
                CV_PARSE_ERROR_CPP( "Unexpected character" );
678
0
        }
679
680
0
        if (!ptr)
681
0
            CV_PARSE_ERROR_CPP("ptr is NULL");
682
683
0
        if ( *ptr != ']' )
684
0
            CV_PARSE_ERROR_CPP( "']' - right-brace of seq is missing" );
685
0
        else
686
0
            ptr++;
687
688
0
        fs->finalizeCollection(node);
689
0
        return ptr;
690
0
    }
691
692
    char* parseMap( char* ptr, FileNode& node )
693
0
    {
694
0
        if (!ptr)
695
0
            CV_PARSE_ERROR_CPP("ptr is NULL");
696
697
0
        if ( *ptr != '{' )
698
0
            CV_PARSE_ERROR_CPP( "'{' - left-brace of map is missing" );
699
0
        else
700
0
            ptr++;
701
702
0
        fs->convertToCollection(FileNode::MAP, node);
703
704
0
        for( ;; )
705
0
        {
706
0
            ptr = skipSpaces( ptr );
707
0
            if( !ptr || !*ptr )
708
0
                break;
709
710
0
            if ( *ptr == '"' )
711
0
            {
712
0
                FileNode child;
713
0
                ptr = parseKey( ptr, node, child );
714
0
                if( !ptr || !*ptr )
715
0
                    break;
716
0
                ptr = skipSpaces( ptr );
717
0
                if( !ptr || !*ptr )
718
0
                    break;
719
720
0
                if ( *ptr == '[' )
721
0
                    ptr = parseSeq( ptr, child );
722
0
                else if ( *ptr == '{' )
723
0
                    ptr = parseMap( ptr, child );
724
0
                else
725
0
                    ptr = parseValue( ptr, child );
726
0
            }
727
728
0
            ptr = skipSpaces( ptr );
729
0
            if( !ptr || !*ptr )
730
0
                break;
731
732
0
            if ( *ptr == ',' )
733
0
                ptr++;
734
0
            else if ( *ptr == '}' )
735
0
                break;
736
0
            else
737
0
            {
738
0
                CV_PARSE_ERROR_CPP( "Unexpected character" );
739
0
            }
740
0
        }
741
742
0
        if (!ptr)
743
0
            CV_PARSE_ERROR_CPP("ptr is NULL");
744
745
0
        if ( *ptr != '}' )
746
0
            CV_PARSE_ERROR_CPP( "'}' - right-brace of map is missing" );
747
0
        else
748
0
            ptr++;
749
750
0
        fs->finalizeCollection(node);
751
0
        return ptr;
752
0
    }
753
754
    bool parse( char* ptr )
755
0
    {
756
0
        if (!ptr)
757
0
            CV_PARSE_ERROR_CPP("Invalid input");
758
759
0
        ptr = skipSpaces( ptr );
760
0
        if ( !ptr || !*ptr )
761
0
            return false;
762
763
0
        FileNode root_collection(fs->getFS(), 0, 0);
764
765
0
        if( *ptr == '{' )
766
0
        {
767
0
            FileNode root_node = fs->addNode(root_collection, std::string(), FileNode::MAP);
768
0
            parseMap( ptr, root_node );
769
0
        }
770
0
        else if ( *ptr == '[' )
771
0
        {
772
0
            FileNode root_node = fs->addNode(root_collection, std::string(), FileNode::SEQ);
773
0
            parseSeq( ptr, root_node );
774
0
        }
775
0
        else
776
0
        {
777
0
            CV_PARSE_ERROR_CPP( "left-brace of top level is missing" );
778
0
        }
779
780
0
        return true;
781
0
    }
782
783
    FileStorage_API* fs;
784
    char buf[CV_FS_MAX_LEN+1024];
785
};
786
787
Ptr<FileStorageEmitter> createJSONEmitter(FileStorage_API* fs)
788
0
{
789
0
    return makePtr<JSONEmitter>(fs);
790
0
}
791
792
Ptr<FileStorageParser> createJSONParser(FileStorage_API* fs)
793
0
{
794
0
    return makePtr<JSONParser>(fs);
795
0
}
796
797
}