Coverage Report

Created: 2023-11-19 08:11

/src/opencv/modules/core/src/persistence.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
#include "persistence_impl.hpp"
8
#include "persistence_base64_encoding.hpp"
9
#include <unordered_map>
10
#include <iterator>
11
12
#include <opencv2/core/utils/logger.hpp>
13
14
namespace cv
15
{
16
17
namespace fs
18
{
19
20
int strcasecmp(const char* s1, const char* s2)
21
0
{
22
0
    const char* dummy="";
23
0
    if(!s1) s1=dummy;
24
0
    if(!s2) s2=dummy;
25
26
0
    size_t len1 = strlen(s1);
27
0
    size_t len2 = strlen(s2);
28
0
    size_t i, len = std::min(len1, len2);
29
0
    for( i = 0; i < len; i++ )
30
0
    {
31
0
        int d = tolower((int)s1[i]) - tolower((int)s2[i]);
32
0
        if( d != 0 )
33
0
            return d;
34
0
    }
35
0
    return len1 < len2 ? -1 : len1 > len2 ? 1 : 0;
36
0
}
37
38
char* itoa( int _val, char* buffer, int /*radix*/ )
39
0
{
40
0
    const int radix = 10;
41
0
    char* ptr=buffer + 23 /* enough even for 64-bit integers */;
42
0
    unsigned val = abs(_val);
43
44
0
    *ptr = '\0';
45
0
    do
46
0
    {
47
0
        unsigned r = val / radix;
48
0
        *--ptr = (char)(val - (r*radix) + '0');
49
0
        val = r;
50
0
    }
51
0
    while( val != 0 );
52
53
0
    if( _val < 0 )
54
0
        *--ptr = '-';
55
56
0
    return ptr;
57
0
}
58
59
char* doubleToString( char* buf, size_t bufSize, double value, bool explicitZero )
60
0
{
61
0
    Cv64suf val;
62
0
    unsigned ieee754_hi;
63
64
0
    val.f = value;
65
0
    ieee754_hi = (unsigned)(val.u >> 32);
66
67
0
    if( (ieee754_hi & 0x7ff00000) != 0x7ff00000 )
68
0
    {
69
0
        int ivalue = cvRound(value);
70
0
        if( ivalue == value )
71
0
        {
72
0
            if( explicitZero )
73
0
                snprintf( buf, bufSize, "%d.0", ivalue );
74
0
            else
75
0
                snprintf( buf, bufSize, "%d.", ivalue );
76
0
        }
77
0
        else
78
0
        {
79
0
            static const char* fmt = "%.16e";
80
0
            char* ptr = buf;
81
0
            snprintf( buf, bufSize, fmt, value );
82
0
            if( *ptr == '+' || *ptr == '-' )
83
0
                ptr++;
84
0
            for( ; cv_isdigit(*ptr); ptr++ )
85
0
                ;
86
0
            if( *ptr == ',' )
87
0
                *ptr = '.';
88
0
        }
89
0
    }
90
0
    else
91
0
    {
92
0
        unsigned ieee754_lo = (unsigned)val.u;
93
0
        if( (ieee754_hi & 0x7fffffff) + (ieee754_lo != 0) > 0x7ff00000 )
94
0
            strcpy( buf, ".Nan" );
95
0
        else
96
0
            strcpy( buf, (int)ieee754_hi < 0 ? "-.Inf" : ".Inf" );
97
0
    }
98
99
0
    return buf;
100
0
}
101
102
char* floatToString( char* buf, size_t bufSize, float value, bool halfprecision, bool explicitZero )
103
0
{
104
0
    Cv32suf val;
105
0
    unsigned ieee754;
106
0
    val.f = value;
107
0
    ieee754 = val.u;
108
109
0
    if( (ieee754 & 0x7f800000) != 0x7f800000 )
110
0
    {
111
0
        int ivalue = cvRound(value);
112
0
        if( ivalue == value )
113
0
        {
114
0
            if( explicitZero )
115
0
                snprintf( buf, bufSize, "%d.0", ivalue );
116
0
            else
117
0
                snprintf( buf, bufSize, "%d.", ivalue );
118
0
        }
119
0
        else
120
0
        {
121
0
            char* ptr = buf;
122
0
            if (halfprecision)
123
0
                snprintf(buf, bufSize, "%.4e", value);
124
0
            else
125
0
                snprintf(buf, bufSize, "%.8e", value);
126
0
            if( *ptr == '+' || *ptr == '-' )
127
0
                ptr++;
128
0
            for( ; cv_isdigit(*ptr); ptr++ )
129
0
                ;
130
0
            if( *ptr == ',' )
131
0
                *ptr = '.';
132
0
        }
133
0
    }
134
0
    else
135
0
    {
136
0
        if( (ieee754 & 0x7fffffff) != 0x7f800000 )
137
0
            strcpy( buf, ".Nan" );
138
0
        else
139
0
            strcpy( buf, (int)ieee754 < 0 ? "-.Inf" : ".Inf" );
140
0
    }
141
142
0
    return buf;
143
0
}
144
145
static const char symbols[9] = "ucwsifdh";
146
147
static char typeSymbol(int depth)
148
0
{
149
0
    CV_StaticAssert(CV_64F == 6, "");
150
0
    CV_CheckDepth(depth, depth >=0 && depth <= CV_16F, "");
151
0
    return symbols[depth];
152
0
}
153
154
static int symbolToType(char c)
155
0
{
156
0
    if (c == 'r')
157
0
        return CV_SEQ_ELTYPE_PTR;
158
0
    const char* pos = strchr( symbols, c );
159
0
    if( !pos )
160
0
        CV_Error( cv::Error::StsBadArg, "Invalid data type specification" );
161
0
    return static_cast<int>(pos - symbols);
162
0
}
163
164
char* encodeFormat(int elem_type, char* dt, size_t dt_len)
165
0
{
166
0
    int cn = (elem_type == CV_SEQ_ELTYPE_PTR/*CV_USRTYPE1*/) ? 1 : CV_MAT_CN(elem_type);
167
0
    char symbol = (elem_type == CV_SEQ_ELTYPE_PTR/*CV_USRTYPE1*/) ? 'r' : typeSymbol(CV_MAT_DEPTH(elem_type));
168
0
    snprintf(dt, dt_len, "%d%c", cn, symbol);
169
0
    return dt + (cn == 1 ? 1 : 0);
170
0
}
171
172
// Deprecated due to size of dt buffer being unknowable.
173
char* encodeFormat(int elem_type, char* dt)
174
0
{
175
0
    constexpr size_t max = 20+1+1; // UINT64_MAX + one char + nul termination.
176
0
    return encodeFormat(elem_type, dt, max);
177
0
}
178
179
int decodeFormat( const char* dt, int* fmt_pairs, int max_len )
180
0
{
181
0
    int fmt_pair_count = 0;
182
0
    int i = 0, k = 0, len = dt ? (int)strlen(dt) : 0;
183
184
0
    if( !dt || !len )
185
0
        return 0;
186
187
0
    CV_Assert( fmt_pairs != 0 && max_len > 0 );
188
0
    fmt_pairs[0] = 0;
189
0
    max_len *= 2;
190
191
0
    for( ; k < len; k++ )
192
0
    {
193
0
        char c = dt[k];
194
195
0
        if( cv_isdigit(c) )
196
0
        {
197
0
            int count = c - '0';
198
0
            if( cv_isdigit(dt[k+1]) )
199
0
            {
200
0
                char* endptr = 0;
201
0
                count = (int)strtol( dt+k, &endptr, 10 );
202
0
                k = (int)(endptr - dt) - 1;
203
0
            }
204
205
0
            if( count <= 0 )
206
0
                CV_Error( cv::Error::StsBadArg, "Invalid data type specification" );
207
208
0
            fmt_pairs[i] = count;
209
0
        }
210
0
        else
211
0
        {
212
0
            int depth = symbolToType(c);
213
0
            if( fmt_pairs[i] == 0 )
214
0
                fmt_pairs[i] = 1;
215
0
            fmt_pairs[i+1] = depth;
216
0
            if( i > 0 && fmt_pairs[i+1] == fmt_pairs[i-1] )
217
0
                fmt_pairs[i-2] += fmt_pairs[i];
218
0
            else
219
0
            {
220
0
                i += 2;
221
0
                if( i >= max_len )
222
0
                    CV_Error( cv::Error::StsBadArg, "Too long data type specification" );
223
0
            }
224
0
            fmt_pairs[i] = 0;
225
0
        }
226
0
    }
227
228
0
    fmt_pair_count = i/2;
229
0
    return fmt_pair_count;
230
0
}
231
232
int calcElemSize( const char* dt, int initial_size )
233
0
{
234
0
    int size = 0;
235
0
    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
236
0
    int comp_size;
237
238
0
    fmt_pair_count = decodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
239
0
    fmt_pair_count *= 2;
240
0
    for( i = 0, size = initial_size; i < fmt_pair_count; i += 2 )
241
0
    {
242
0
        comp_size = CV_ELEM_SIZE(fmt_pairs[i+1]);
243
0
        size = cvAlign( size, comp_size );
244
0
        size += comp_size * fmt_pairs[i];
245
0
    }
246
0
    if( initial_size == 0 )
247
0
    {
248
0
        comp_size = CV_ELEM_SIZE(fmt_pairs[1]);
249
0
        size = cvAlign( size, comp_size );
250
0
    }
251
0
    return size;
252
0
}
253
254
255
int calcStructSize( const char* dt, int initial_size )
256
0
{
257
0
    int size = calcElemSize( dt, initial_size );
258
0
    size_t elem_max_size = 0;
259
0
    for ( const char * type = dt; *type != '\0'; type++ )
260
0
    {
261
0
        char v = *type;
262
0
        if (v >= '0' && v <= '9')
263
0
            continue;  // skip vector size
264
0
        switch (v)
265
0
        {
266
0
        case 'u': { elem_max_size = std::max( elem_max_size, sizeof(uchar ) ); break; }
267
0
        case 'c': { elem_max_size = std::max( elem_max_size, sizeof(schar ) ); break; }
268
0
        case 'w': { elem_max_size = std::max( elem_max_size, sizeof(ushort) ); break; }
269
0
        case 's': { elem_max_size = std::max( elem_max_size, sizeof(short ) ); break; }
270
0
        case 'i': { elem_max_size = std::max( elem_max_size, sizeof(int   ) ); break; }
271
0
        case 'f': { elem_max_size = std::max( elem_max_size, sizeof(float ) ); break; }
272
0
        case 'd': { elem_max_size = std::max( elem_max_size, sizeof(double) ); break; }
273
0
        case 'h': { elem_max_size = std::max(elem_max_size, sizeof(float16_t)); break; }
274
0
        default:
275
0
            CV_Error_(Error::StsNotImplemented, ("Unknown type identifier: '%c' in '%s'", (char)(*type), dt));
276
0
        }
277
0
    }
278
0
    size = cvAlign( size, static_cast<int>(elem_max_size) );
279
0
    return size;
280
0
}
281
282
int decodeSimpleFormat( const char* dt )
283
0
{
284
0
    int elem_type = -1;
285
0
    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
286
287
0
    fmt_pair_count = decodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
288
0
    if( fmt_pair_count != 1 || fmt_pairs[0] >= CV_CN_MAX)
289
0
        CV_Error( cv::Error::StsError, "Too complex format for the matrix" );
290
291
0
    elem_type = CV_MAKETYPE( fmt_pairs[1], fmt_pairs[0] );
292
293
0
    return elem_type;
294
0
}
295
296
}
297
298
#if defined __i386__ || defined(_M_IX86) || defined __x86_64__ || defined(_M_X64) || \
299
    (defined (__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__)
300
#define CV_LITTLE_ENDIAN_MEM_ACCESS 1
301
#else
302
#define CV_LITTLE_ENDIAN_MEM_ACCESS 0
303
#endif
304
305
static inline int readInt(const uchar* p)
306
0
{
307
    // On little endian CPUs, both branches produce the same result. On big endian, only the else branch does.
308
0
#if CV_LITTLE_ENDIAN_MEM_ACCESS
309
0
    int val;
310
0
    memcpy(&val, p, sizeof(val));
311
0
    return val;
312
#else
313
    int val = (int)(p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
314
    return val;
315
#endif
316
0
}
317
318
static inline double readReal(const uchar* p)
319
0
{
320
    // On little endian CPUs, both branches produce the same result. On big endian, only the else branch does.
321
0
#if CV_LITTLE_ENDIAN_MEM_ACCESS
322
0
    double val;
323
0
    memcpy(&val, p, sizeof(val));
324
0
    return val;
325
#else
326
    unsigned val0 = (unsigned)(p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
327
    unsigned val1 = (unsigned)(p[4] | (p[5] << 8) | (p[6] << 16) | (p[7] << 24));
328
    Cv64suf val;
329
    val.u = val0 | ((uint64)val1 << 32);
330
    return val.f;
331
#endif
332
0
}
333
334
static inline void writeInt(uchar* p, int ival)
335
0
{
336
    // On little endian CPUs, both branches produce the same result. On big endian, only the else branch does.
337
0
#if CV_LITTLE_ENDIAN_MEM_ACCESS
338
0
    memcpy(p, &ival, sizeof(ival));
339
#else
340
    p[0] = (uchar)ival;
341
    p[1] = (uchar)(ival >> 8);
342
    p[2] = (uchar)(ival >> 16);
343
    p[3] = (uchar)(ival >> 24);
344
#endif
345
0
}
346
347
static inline void writeReal(uchar* p, double fval)
348
0
{
349
    // On little endian CPUs, both branches produce the same result. On big endian, only the else branch does.
350
0
#if CV_LITTLE_ENDIAN_MEM_ACCESS
351
0
    memcpy(p, &fval, sizeof(fval));
352
#else
353
    Cv64suf v;
354
    v.f = fval;
355
    p[0] = (uchar)v.u;
356
    p[1] = (uchar)(v.u >> 8);
357
    p[2] = (uchar)(v.u >> 16);
358
    p[3] = (uchar)(v.u >> 24);
359
    p[4] = (uchar)(v.u >> 32);
360
    p[5] = (uchar)(v.u >> 40);
361
    p[6] = (uchar)(v.u >> 48);
362
    p[7] = (uchar)(v.u >> 56);
363
#endif
364
0
}
365
366
367
368
3.40k
void FileStorage::Impl::init() {
369
3.40k
    flags = 0;
370
3.40k
    buffer.clear();
371
3.40k
    bufofs = 0;
372
3.40k
    state = UNDEFINED;
373
3.40k
    is_using_base64 = false;
374
3.40k
    state_of_writing_base64 = FileStorage_API::Base64State::Uncertain;
375
3.40k
    is_write_struct_delayed = false;
376
3.40k
    delayed_struct_key = nullptr;
377
3.40k
    delayed_struct_flags = 0;
378
3.40k
    delayed_type_name = nullptr;
379
3.40k
    base64_writer = nullptr;
380
3.40k
    is_opened = false;
381
3.40k
    dummy_eof = false;
382
3.40k
    write_mode = false;
383
3.40k
    mem_mode = false;
384
3.40k
    space = 0;
385
3.40k
    wrap_margin = 71;
386
3.40k
    fmt = 0;
387
3.40k
    file = 0;
388
3.40k
    gzfile = 0;
389
3.40k
    empty_stream = true;
390
391
3.40k
    strbufv.clear();
392
3.40k
    strbuf = 0;
393
3.40k
    strbufsize = strbufpos = 0;
394
3.40k
    roots.clear();
395
396
3.40k
    fs_data.clear();
397
3.40k
    fs_data_ptrs.clear();
398
3.40k
    fs_data_blksz.clear();
399
3.40k
    freeSpaceOfs = 0;
400
401
3.40k
    str_hash.clear();
402
3.40k
    str_hash_data.clear();
403
3.40k
    str_hash_data.resize(1);
404
3.40k
    str_hash_data[0] = '\0';
405
406
3.40k
    filename.clear();
407
3.40k
    lineno = 0;
408
3.40k
}
409
410
995
FileStorage::Impl::Impl(FileStorage *_fs) {
411
995
    fs_ext = _fs;
412
995
    init();
413
995
}
414
415
995
FileStorage::Impl::~Impl() {
416
995
    release();
417
995
}
418
419
2.40k
void FileStorage::Impl::release(String *out) {
420
2.40k
    if (is_opened) {
421
0
        if (out)
422
0
            out->clear();
423
0
        if (write_mode) {
424
0
            while (write_stack.size() > 1) {
425
0
                endWriteStruct();
426
0
            }
427
0
            flush();
428
0
            if (fmt == FileStorage::FORMAT_XML)
429
0
                puts("</opencv_storage>\n");
430
0
            else if (fmt == FileStorage::FORMAT_JSON)
431
0
                puts("}\n");
432
0
        }
433
0
        if (mem_mode && out) {
434
0
            *out = cv::String(outbuf.begin(), outbuf.end());
435
0
        }
436
0
    }
437
2.40k
    closeFile();
438
2.40k
    init();
439
2.40k
}
440
441
994
void FileStorage::Impl::analyze_file_name(const std::string &file_name, std::vector<std::string> &params) {
442
994
    params.clear();
443
994
    static const char not_file_name = '\n';
444
994
    static const char parameter_begin = '?';
445
994
    static const char parameter_separator = '&';
446
447
994
    if (file_name.find(not_file_name, (size_t) 0) != std::string::npos)
448
54
        return;
449
450
940
    size_t beg = file_name.find_last_of(parameter_begin);
451
940
    params.push_back(file_name.substr((size_t) 0, beg));
452
453
940
    if (beg != std::string::npos) {
454
553
        size_t end = file_name.size();
455
553
        beg++;
456
553
        for (size_t param_beg = beg, param_end = beg;
457
7.78M
             param_end < end;
458
7.78M
             param_beg = param_end + 1) {
459
7.78M
            param_end = file_name.find_first_of(parameter_separator, param_beg);
460
7.78M
            if ((param_end == std::string::npos || param_end != param_beg) && param_beg + 1 < end) {
461
7.78M
                params.push_back(file_name.substr(param_beg, param_end - param_beg));
462
7.78M
            }
463
7.78M
        }
464
553
    }
465
940
}
466
467
994
bool FileStorage::Impl::open(const char *filename_or_buf, int _flags, const char *encoding) {
468
994
    bool ok = true;
469
994
    release();
470
471
994
    bool append = (_flags & 3) == FileStorage::APPEND;
472
994
    mem_mode = (_flags & FileStorage::MEMORY) != 0;
473
474
994
    write_mode = (_flags & 3) != 0;
475
994
    bool write_base64 = (write_mode || append) && (_flags & FileStorage::BASE64) != 0;
476
477
994
    bool isGZ = false;
478
994
    size_t fnamelen = 0;
479
480
994
    std::vector<std::string> params;
481
    //if ( !mem_mode )
482
994
    {
483
994
        analyze_file_name(filename_or_buf, params);
484
994
        if (!params.empty())
485
940
            filename = params[0];
486
487
994
        if (!write_base64 && params.size() >= 2 &&
488
994
            std::find(params.begin() + 1, params.end(), std::string("base64")) != params.end())
489
4
            write_base64 = (write_mode || append);
490
994
    }
491
492
994
    if (filename.size() == 0 && !mem_mode && !write_mode)
493
392
        CV_Error(cv::Error::StsNullPtr, "NULL or empty filename");
494
495
602
    if (mem_mode && append)
496
0
        CV_Error(cv::Error::StsBadFlag, "FileStorage::APPEND and FileStorage::MEMORY are not currently compatible");
497
498
602
    flags = _flags;
499
500
602
    if (!mem_mode) {
501
602
        char *dot_pos = strrchr((char *) filename.c_str(), '.');
502
602
        char compression = '\0';
503
504
602
        if (dot_pos && dot_pos[1] == 'g' && dot_pos[2] == 'z' &&
505
602
            (dot_pos[3] == '\0' || (cv_isdigit(dot_pos[3]) && dot_pos[4] == '\0'))) {
506
28
            if (append) {
507
0
                CV_Error(cv::Error::StsNotImplemented, "Appending data to compressed file is not implemented");
508
0
            }
509
28
            isGZ = true;
510
28
            compression = dot_pos[3];
511
28
            if (compression)
512
26
                dot_pos[3] = '\0', fnamelen--;
513
28
        }
514
515
602
        if (!isGZ) {
516
574
            file = fopen(filename.c_str(), !write_mode ? "rt" : !append ? "wt" : "a+t");
517
574
            if (!file)
518
548
            {
519
548
                CV_LOG_ERROR(NULL, "Can't open file: '" << filename << "' in " << (!write_mode ? "read" : !append ? "write" : "append") << " mode");
520
548
                return false;
521
548
            }
522
574
        } else {
523
28
#if USE_ZLIB
524
28
            char mode[] = {write_mode ? 'w' : 'r', 'b', compression ? compression : '3', '\0'};
525
28
            gzfile = gzopen(filename.c_str(), mode);
526
28
            if (!gzfile)
527
28
            {
528
28
                CV_LOG_ERROR(NULL, "Can't open archive: '" << filename << "' mode=" << mode);
529
28
                return false;
530
28
            }
531
#else
532
            CV_Error(cv::Error::StsNotImplemented, "There is no compressed file storage support in this configuration");
533
#endif
534
28
        }
535
602
    }
536
537
    // FIXIT release() must do that, use CV_Assert() here instead
538
26
    roots.clear();
539
26
    fs_data.clear();
540
541
26
    wrap_margin = 71;
542
26
    fmt = FileStorage::FORMAT_AUTO;
543
544
26
    if (write_mode) {
545
0
        fmt = flags & FileStorage::FORMAT_MASK;
546
547
0
        if (mem_mode)
548
0
            outbuf.clear();
549
550
0
        if (fmt == FileStorage::FORMAT_AUTO && !filename.empty()) {
551
0
            const char *dot_pos = NULL;
552
0
            const char *dot_pos2 = NULL;
553
            // like strrchr() implementation, but save two last positions simultaneously
554
0
            for (const char *pos = &filename[0]; pos[0] != 0; pos++) {
555
0
                if (pos[0] == '.') {
556
0
                    dot_pos2 = dot_pos;
557
0
                    dot_pos = pos;
558
0
                }
559
0
            }
560
0
            if (fs::strcasecmp(dot_pos, ".gz") == 0 && dot_pos2 != NULL) {
561
0
                dot_pos = dot_pos2;
562
0
            }
563
0
            fmt = (fs::strcasecmp(dot_pos, ".xml") == 0 || fs::strcasecmp(dot_pos, ".xml.gz") == 0)
564
0
                  ? FileStorage::FORMAT_XML
565
0
                  : (fs::strcasecmp(dot_pos, ".json") == 0 || fs::strcasecmp(dot_pos, ".json.gz") == 0)
566
0
                    ? FileStorage::FORMAT_JSON
567
0
                    : FileStorage::FORMAT_YAML;
568
0
        } else if (fmt == FileStorage::FORMAT_AUTO) {
569
0
            fmt = FileStorage::FORMAT_XML;
570
0
        }
571
572
        // we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (&apos; and &quot;)
573
        // and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB))
574
0
        int buf_size = CV_FS_MAX_LEN * (fmt == FileStorage::FORMAT_XML ? 6 : 4) + 1024;
575
576
0
        if (append) {
577
0
            fseek(file, 0, SEEK_END);
578
0
            if (ftell(file) == 0)
579
0
                append = false;
580
0
        }
581
582
0
        write_stack.clear();
583
0
        empty_stream = true;
584
0
        write_stack.push_back(FStructData("", FileNode::MAP | FileNode::EMPTY, 0));
585
0
        buffer.reserve(buf_size + 1024);
586
0
        buffer.resize(buf_size);
587
0
        bufofs = 0;
588
0
        is_using_base64 = write_base64;
589
0
        state_of_writing_base64 = FileStorage_API::Base64State::Uncertain;
590
591
0
        if (fmt == FileStorage::FORMAT_XML) {
592
0
            size_t file_size = file ? (size_t) ftell(file) : (size_t) 0;
593
0
            if (!append || file_size == 0) {
594
0
                if (encoding && *encoding != '\0') {
595
0
                    if (fs::strcasecmp(encoding, "UTF-16") == 0) {
596
0
                        release();
597
0
                        CV_Error(cv::Error::StsBadArg, "UTF-16 XML encoding is not supported! Use 8-bit encoding\n");
598
0
                    }
599
600
0
                    CV_Assert(strlen(encoding) < 1000);
601
0
                    char buf[1100];
602
0
                    snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding);
603
0
                    puts(buf);
604
0
                } else
605
0
                    puts("<?xml version=\"1.0\"?>\n");
606
0
                puts("<opencv_storage>\n");
607
0
            } else {
608
0
                int xml_buf_size = 1 << 10;
609
0
                char substr[] = "</opencv_storage>";
610
0
                int last_occurrence = -1;
611
0
                xml_buf_size = MIN(xml_buf_size, int(file_size));
612
0
                fseek(file, -xml_buf_size, SEEK_END);
613
                // find the last occurrence of </opencv_storage>
614
0
                for (;;) {
615
0
                    int line_offset = (int) ftell(file);
616
0
                    const char *ptr0 = this->gets(xml_buf_size);
617
0
                    const char *ptr = NULL;
618
0
                    if (!ptr0)
619
0
                        break;
620
0
                    ptr = ptr0;
621
0
                    for (;;) {
622
0
                        ptr = strstr(ptr, substr);
623
0
                        if (!ptr)
624
0
                            break;
625
0
                        last_occurrence = line_offset + (int) (ptr - ptr0);
626
0
                        ptr += strlen(substr);
627
0
                    }
628
0
                }
629
0
                if (last_occurrence < 0) {
630
0
                    release();
631
0
                    CV_Error(cv::Error::StsError, "Could not find </opencv_storage> in the end of file.\n");
632
0
                }
633
0
                closeFile();
634
0
                file = fopen(filename.c_str(), "r+t");
635
0
                CV_Assert(file != 0);
636
0
                fseek(file, last_occurrence, SEEK_SET);
637
                // replace the last "</opencv_storage>" with " <!-- resumed -->", which has the same length
638
0
                puts(" <!-- resumed -->");
639
0
                fseek(file, 0, SEEK_END);
640
0
                puts("\n");
641
0
            }
642
643
0
            emitter_do_not_use_direct_dereference = createXMLEmitter(this);
644
0
        } else if (fmt == FileStorage::FORMAT_YAML) {
645
0
            if (!append)
646
0
                puts("%YAML:1.0\n---\n");
647
0
            else
648
0
                puts("...\n---\n");
649
650
0
            emitter_do_not_use_direct_dereference = createYAMLEmitter(this);
651
0
        } else {
652
0
            CV_Assert(fmt == FileStorage::FORMAT_JSON);
653
0
            if (!append)
654
0
                puts("{\n");
655
0
            else {
656
0
                bool valid = false;
657
0
                long roffset = 0;
658
0
                for (;
659
0
                        fseek(file, roffset, SEEK_END) == 0;
660
0
                        roffset -= 1) {
661
0
                    const char end_mark = '}';
662
0
                    if (fgetc(file) == end_mark) {
663
0
                        fseek(file, roffset, SEEK_END);
664
0
                        valid = true;
665
0
                        break;
666
0
                    }
667
0
                }
668
669
0
                if (valid) {
670
0
                    closeFile();
671
0
                    file = fopen(filename.c_str(), "r+t");
672
0
                    CV_Assert(file != 0);
673
0
                    fseek(file, roffset, SEEK_END);
674
0
                    fputs(",", file);
675
0
                } else {
676
0
                    CV_Error(cv::Error::StsError, "Could not find '}' in the end of file.\n");
677
0
                }
678
0
            }
679
0
            write_stack.back().indent = 4;
680
0
            emitter_do_not_use_direct_dereference = createJSONEmitter(this);
681
0
        }
682
0
        is_opened = true;
683
26
    } else {
684
26
        const size_t buf_size0 = 40;
685
26
        buffer.resize(buf_size0);
686
26
        if (mem_mode) {
687
0
            strbuf = (char *) filename_or_buf;
688
0
            strbufsize = strlen(strbuf);
689
0
        }
690
691
26
        const char *yaml_signature = "%YAML";
692
26
        const char *json_signature = "{";
693
26
        const char *xml_signature = "<?xml";
694
26
        char *buf = this->gets(16);
695
26
        CV_Assert(buf);
696
6
        char *bufPtr = cv_skip_BOM(buf);
697
6
        size_t bufOffset = bufPtr - buf;
698
699
6
        if (strncmp(bufPtr, yaml_signature, strlen(yaml_signature)) == 0)
700
0
            fmt = FileStorage::FORMAT_YAML;
701
6
        else if (strncmp(bufPtr, json_signature, strlen(json_signature)) == 0)
702
0
            fmt = FileStorage::FORMAT_JSON;
703
6
        else if (strncmp(bufPtr, xml_signature, strlen(xml_signature)) == 0)
704
0
            fmt = FileStorage::FORMAT_XML;
705
6
        else if (strbufsize == bufOffset)
706
6
            CV_Error(cv::Error::StsBadArg, "Input file is invalid");
707
0
        else
708
0
            CV_Error(cv::Error::StsBadArg, "Unsupported file storage format");
709
710
0
        rewind();
711
0
        strbufpos = bufOffset;
712
0
        bufofs = 0;
713
714
0
        try {
715
0
            char *ptr = bufferStart();
716
0
            ptr[0] = ptr[1] = ptr[2] = '\0';
717
0
            FileNode root_nodes(fs_ext, 0, 0);
718
719
0
            uchar *rptr = reserveNodeSpace(root_nodes, 9);
720
0
            *rptr = FileNode::SEQ;
721
0
            writeInt(rptr + 1, 4);
722
0
            writeInt(rptr + 5, 0);
723
724
0
            roots.clear();
725
726
0
            switch (fmt) {
727
0
                case FileStorage::FORMAT_XML:
728
0
                    parser_do_not_use_direct_dereference = createXMLParser(this);
729
0
                    break;
730
0
                case FileStorage::FORMAT_YAML:
731
0
                    parser_do_not_use_direct_dereference = createYAMLParser(this);
732
0
                    break;
733
0
                case FileStorage::FORMAT_JSON:
734
0
                    parser_do_not_use_direct_dereference = createJSONParser(this);
735
0
                    break;
736
0
                default:
737
0
                    parser_do_not_use_direct_dereference = Ptr<FileStorageParser>();
738
0
            }
739
740
0
            if (!parser_do_not_use_direct_dereference.empty()) {
741
0
                ok = getParser().parse(ptr);
742
0
                if (ok) {
743
0
                    finalizeCollection(root_nodes);
744
745
0
                    CV_Assert(!fs_data_ptrs.empty());
746
0
                    FileNode roots_node(fs_ext, 0, 0);
747
0
                    size_t i, nroots = roots_node.size();
748
0
                    FileNodeIterator it = roots_node.begin();
749
750
0
                    for (i = 0; i < nroots; i++, ++it)
751
0
                        roots.push_back(*it);
752
0
                }
753
0
            }
754
0
        }
755
0
        catch (...)
756
0
        {
757
            // FIXIT log error message
758
0
            is_opened = true;
759
0
            release();
760
0
            throw;
761
0
        }
762
763
        // release resources that we do not need anymore
764
0
        closeFile();
765
0
        is_opened = true;
766
0
        std::vector<char> tmpbuf;
767
0
        std::swap(buffer, tmpbuf);
768
0
        bufofs = 0;
769
0
    }
770
0
    return ok;
771
26
}
772
773
0
void FileStorage::Impl::puts(const char *str) {
774
0
    CV_Assert(write_mode);
775
0
    if (mem_mode)
776
0
        std::copy(str, str + strlen(str), std::back_inserter(outbuf));
777
0
    else if (file)
778
0
        fputs(str, file);
779
0
#if USE_ZLIB
780
0
    else if (gzfile)
781
0
        gzputs(gzfile, str);
782
0
#endif
783
0
    else
784
0
        CV_Error(cv::Error::StsError, "The storage is not opened");
785
0
}
786
787
37
char *FileStorage::Impl::getsFromFile(char *buf, int count) {
788
37
    if (file)
789
37
        return fgets(buf, count, file);
790
0
#if USE_ZLIB
791
0
    if (gzfile)
792
0
        return gzgets(gzfile, buf, count);
793
0
#endif
794
0
    CV_Error(cv::Error::StsError, "The storage is not opened");
795
0
}
796
797
26
char *FileStorage::Impl::gets(size_t maxCount) {
798
26
    if (strbuf) {
799
0
        size_t i = strbufpos, len = strbufsize;
800
0
        const char *instr = strbuf;
801
0
        for (; i < len; i++) {
802
0
            char c = instr[i];
803
0
            if (c == '\0' || c == '\n') {
804
0
                if (c == '\n')
805
0
                    i++;
806
0
                break;
807
0
            }
808
0
        }
809
0
        size_t count = i - strbufpos;
810
0
        if (maxCount == 0 || maxCount > count)
811
0
            maxCount = count;
812
0
        buffer.resize(std::max(buffer.size(), maxCount + 8));
813
0
        memcpy(&buffer[0], instr + strbufpos, maxCount);
814
0
        buffer[maxCount] = '\0';
815
0
        strbufpos = i;
816
0
        return maxCount > 0 ? &buffer[0] : 0;
817
0
    }
818
819
26
    const size_t MAX_BLOCK_SIZE = INT_MAX / 2; // hopefully, that will be enough
820
26
    if (maxCount == 0)
821
0
        maxCount = MAX_BLOCK_SIZE;
822
26
    else
823
26
        CV_Assert(maxCount < MAX_BLOCK_SIZE);
824
26
    size_t ofs = 0;
825
826
37
    for (;;) {
827
37
        int count = (int) std::min(buffer.size() - ofs - 16, maxCount);
828
37
        char *ptr = getsFromFile(&buffer[ofs], count + 1);
829
37
        if (!ptr)
830
20
            break;
831
17
        int delta = (int) strlen(ptr);
832
17
        ofs += delta;
833
17
        maxCount -= delta;
834
17
        if (delta == 0 || ptr[delta - 1] == '\n' || maxCount == 0)
835
6
            break;
836
11
        if (delta == count)
837
0
            buffer.resize((size_t) (buffer.size() * 1.5));
838
11
    }
839
26
    return ofs > 0 ? &buffer[0] : 0;
840
26
}
841
842
0
char *FileStorage::Impl::gets() {
843
0
    char *ptr = this->gets(0);
844
0
    if (!ptr) {
845
0
        ptr = bufferStart();  // FIXIT Why do we need this hack? What is about other parsers JSON/YAML?
846
0
        *ptr = '\0';
847
0
        setEof();
848
0
        return 0;
849
0
    } else {
850
0
        size_t l = strlen(ptr);
851
0
        if (l > 0 && ptr[l - 1] != '\n' && ptr[l - 1] != '\r' && !eof()) {
852
0
            ptr[l] = '\n';
853
0
            ptr[l + 1] = '\0';
854
0
        }
855
0
    }
856
0
    lineno++;
857
0
    return ptr;
858
0
}
859
860
0
bool FileStorage::Impl::eof() {
861
0
    if (dummy_eof)
862
0
        return true;
863
0
    if (strbuf)
864
0
        return strbufpos >= strbufsize;
865
0
    if (file)
866
0
        return feof(file) != 0;
867
0
#if USE_ZLIB
868
0
    if (gzfile)
869
0
        return gzeof(gzfile) != 0;
870
0
#endif
871
0
    return false;
872
0
}
873
874
0
void FileStorage::Impl::setEof() {
875
0
    dummy_eof = true;
876
0
}
877
878
2.40k
void FileStorage::Impl::closeFile() {
879
2.40k
    if (file)
880
26
        fclose(file);
881
2.38k
#if USE_ZLIB
882
2.38k
    else if (gzfile)
883
0
        gzclose(gzfile);
884
2.40k
#endif
885
2.40k
    file = 0;
886
2.40k
    gzfile = 0;
887
2.40k
    strbuf = 0;
888
2.40k
    strbufpos = 0;
889
2.40k
    is_opened = false;
890
2.40k
}
891
892
0
void FileStorage::Impl::rewind() {
893
0
    if (file)
894
0
        ::rewind(file);
895
0
#if USE_ZLIB
896
0
    else if (gzfile)
897
0
        gzrewind(gzfile);
898
0
#endif
899
0
    strbufpos = 0;
900
0
}
901
902
0
char *FileStorage::Impl::resizeWriteBuffer(char *ptr, int len) {
903
0
    const char *buffer_end = &buffer[0] + buffer.size();
904
0
    if (ptr + len < buffer_end)
905
0
        return ptr;
906
907
0
    const char *buffer_start = &buffer[0];
908
0
    int written_len = (int) (ptr - buffer_start);
909
910
0
    CV_Assert(written_len <= (int) buffer.size());
911
0
    int new_size = (int) ((buffer_end - buffer_start) * 3 / 2);
912
0
    new_size = MAX(written_len + len, new_size);
913
0
    buffer.reserve(new_size + 256);
914
0
    buffer.resize(new_size);
915
0
    bufofs = written_len;
916
0
    return &buffer[0] + bufofs;
917
0
}
918
919
0
char *FileStorage::Impl::flush() {
920
0
    char *buffer_start = &buffer[0];
921
0
    char *ptr = buffer_start + bufofs;
922
923
0
    if (ptr > buffer_start + space) {
924
0
        ptr[0] = '\n';
925
0
        ptr[1] = '\0';
926
0
        puts(buffer_start);
927
0
        bufofs = 0;
928
0
    }
929
930
0
    int indent = write_stack.back().indent;
931
932
0
    if (space != indent) {
933
0
        memset(buffer_start, ' ', indent);
934
0
        space = indent;
935
0
    }
936
0
    bufofs = space;
937
0
    ptr = buffer_start + bufofs;
938
939
0
    return ptr;
940
0
}
941
942
0
void FileStorage::Impl::endWriteStruct() {
943
0
    CV_Assert(write_mode);
944
945
0
    check_if_write_struct_is_delayed(false);
946
0
    if (state_of_writing_base64 != FileStorage_API::Uncertain)
947
0
        switch_to_Base64_state(FileStorage_API::Uncertain);
948
949
0
    CV_Assert(!write_stack.empty());
950
951
0
    FStructData &current_struct = write_stack.back();
952
0
    if (fmt == FileStorage::FORMAT_JSON && !FileNode::isFlow(current_struct.flags) && write_stack.size() > 1)
953
0
        current_struct.indent = write_stack[write_stack.size() - 2].indent;
954
955
0
    getEmitter().endWriteStruct(current_struct);
956
957
0
    write_stack.pop_back();
958
0
    if (!write_stack.empty())
959
0
        write_stack.back().flags &= ~FileNode::EMPTY;
960
0
}
961
962
void FileStorage::Impl::startWriteStruct_helper(const char *key, int struct_flags,
963
0
                                                const char *type_name) {
964
0
    CV_Assert(write_mode);
965
966
0
    struct_flags = (struct_flags & (FileNode::TYPE_MASK | FileNode::FLOW)) | FileNode::EMPTY;
967
0
    if (!FileNode::isCollection(struct_flags))
968
0
        CV_Error(cv::Error::StsBadArg,
969
0
                 "Some collection type: FileNode::SEQ or FileNode::MAP must be specified");
970
971
0
    if (type_name && type_name[0] == '\0')
972
0
        type_name = 0;
973
974
0
    FStructData s = getEmitter().startWriteStruct(write_stack.back(), key, struct_flags, type_name);
975
976
0
    write_stack.push_back(s);
977
0
    size_t write_stack_size = write_stack.size();
978
0
    if (write_stack_size > 1)
979
0
        write_stack[write_stack_size - 2].flags &= ~FileNode::EMPTY;
980
981
0
    if (fmt != FileStorage::FORMAT_JSON && !FileNode::isFlow(s.flags))
982
0
        flush();
983
984
0
    if (fmt == FileStorage::FORMAT_JSON && type_name && type_name[0] && FileNode::isMap(struct_flags)) {
985
0
        getEmitter().write("type_id", type_name, false);
986
0
    }
987
0
}
988
989
void FileStorage::Impl::startWriteStruct(const char *key, int struct_flags,
990
0
                                         const char *type_name) {
991
0
    check_if_write_struct_is_delayed(false);
992
0
    if (state_of_writing_base64 == FileStorage_API::NotUse)
993
0
        switch_to_Base64_state(FileStorage_API::Uncertain);
994
995
0
    if (state_of_writing_base64 == FileStorage_API::Uncertain && FileNode::isSeq(struct_flags)
996
0
        && is_using_base64 && type_name == 0) {
997
        /* Uncertain whether output Base64 data */
998
0
        make_write_struct_delayed(key, struct_flags, type_name);
999
0
    } else if (type_name && memcmp(type_name, "binary", 6) == 0) {
1000
        /* Must output Base64 data */
1001
0
        if ((FileNode::TYPE_MASK & struct_flags) != FileNode::SEQ)
1002
0
            CV_Error(cv::Error::StsBadArg, "must set 'struct_flags |= CV_NODE_SEQ' if using Base64.");
1003
0
        else if (state_of_writing_base64 != FileStorage_API::Uncertain)
1004
0
            CV_Error(cv::Error::StsError, "function \'cvStartWriteStruct\' calls cannot be nested if using Base64.");
1005
1006
0
        startWriteStruct_helper(key, struct_flags, "binary");
1007
1008
0
        if (state_of_writing_base64 != FileStorage_API::Uncertain)
1009
0
            switch_to_Base64_state(FileStorage_API::Uncertain);
1010
0
        switch_to_Base64_state(FileStorage_API::InUse);
1011
0
    } else {
1012
        /* Won't output Base64 data */
1013
0
        if (state_of_writing_base64 == FileStorage_API::InUse)
1014
0
            CV_Error(cv::Error::StsError, "At the end of the output Base64, `cvEndWriteStruct` is needed.");
1015
1016
0
        startWriteStruct_helper(key, struct_flags, type_name);
1017
1018
0
        if (state_of_writing_base64 != FileStorage_API::Uncertain)
1019
0
            switch_to_Base64_state(FileStorage_API::Uncertain);
1020
0
        switch_to_Base64_state(FileStorage_API::NotUse);
1021
0
    }
1022
0
}
1023
1024
0
void FileStorage::Impl::writeComment(const char *comment, bool eol_comment) {
1025
0
    CV_Assert(write_mode);
1026
0
    getEmitter().writeComment(comment, eol_comment);
1027
0
}
1028
1029
0
void FileStorage::Impl::startNextStream() {
1030
0
    CV_Assert(write_mode);
1031
0
    if (!empty_stream) {
1032
0
        while (!write_stack.empty())
1033
0
            endWriteStruct();
1034
0
        flush();
1035
0
        getEmitter().startNextStream();
1036
0
        empty_stream = true;
1037
0
        write_stack.push_back(FStructData("", FileNode::EMPTY, 0));
1038
0
        bufofs = 0;
1039
0
    }
1040
0
}
1041
1042
0
void FileStorage::Impl::write(const String &key, int value) {
1043
0
    CV_Assert(write_mode);
1044
0
    getEmitter().write(key.c_str(), value);
1045
0
}
1046
1047
0
void FileStorage::Impl::write(const String &key, double value) {
1048
0
    CV_Assert(write_mode);
1049
0
    getEmitter().write(key.c_str(), value);
1050
0
}
1051
1052
0
void FileStorage::Impl::write(const String &key, const String &value) {
1053
0
    CV_Assert(write_mode);
1054
0
    getEmitter().write(key.c_str(), value.c_str(), false);
1055
0
}
1056
1057
0
void FileStorage::Impl::writeRawData(const std::string &dt, const void *_data, size_t len) {
1058
0
    CV_Assert(write_mode);
1059
1060
0
    if (is_using_base64 || state_of_writing_base64 == FileStorage_API::Base64State::InUse) {
1061
0
        writeRawDataBase64(_data, len, dt.c_str());
1062
0
        return;
1063
0
    } else if (state_of_writing_base64 == FileStorage_API::Base64State::Uncertain) {
1064
0
        switch_to_Base64_state(FileStorage_API::Base64State::NotUse);
1065
0
    }
1066
1067
0
    size_t elemSize = fs::calcStructSize(dt.c_str(), 0);
1068
0
    CV_Assert(elemSize);
1069
0
    CV_Assert(len % elemSize == 0);
1070
0
    len /= elemSize;
1071
1072
0
    bool explicitZero = fmt == FileStorage::FORMAT_JSON;
1073
0
    const uchar *data0 = (const uchar *) _data;
1074
0
    int fmt_pairs[CV_FS_MAX_FMT_PAIRS * 2], k, fmt_pair_count;
1075
0
    char buf[256] = "";
1076
1077
0
    fmt_pair_count = fs::decodeFormat(dt.c_str(), fmt_pairs, CV_FS_MAX_FMT_PAIRS);
1078
1079
0
    if (!len)
1080
0
        return;
1081
1082
0
    if (!data0)
1083
0
        CV_Error(cv::Error::StsNullPtr, "Null data pointer");
1084
1085
0
    if (fmt_pair_count == 1) {
1086
0
        fmt_pairs[0] *= (int) len;
1087
0
        len = 1;
1088
0
    }
1089
1090
0
    for (; len--; data0 += elemSize) {
1091
0
        int offset = 0;
1092
0
        for (k = 0; k < fmt_pair_count; k++) {
1093
0
            int i, count = fmt_pairs[k * 2];
1094
0
            int elem_type = fmt_pairs[k * 2 + 1];
1095
0
            int elem_size = CV_ELEM_SIZE(elem_type);
1096
0
            const char *ptr;
1097
1098
0
            offset = cvAlign(offset, elem_size);
1099
0
            const uchar *data = data0 + offset;
1100
1101
0
            for (i = 0; i < count; i++) {
1102
0
                switch (elem_type) {
1103
0
                    case CV_8U:
1104
0
                        ptr = fs::itoa(*(uchar *) data, buf, 10);
1105
0
                        data++;
1106
0
                        break;
1107
0
                    case CV_8S:
1108
0
                        ptr = fs::itoa(*(char *) data, buf, 10);
1109
0
                        data++;
1110
0
                        break;
1111
0
                    case CV_16U:
1112
0
                        ptr = fs::itoa(*(ushort *) data, buf, 10);
1113
0
                        data += sizeof(ushort);
1114
0
                        break;
1115
0
                    case CV_16S:
1116
0
                        ptr = fs::itoa(*(short *) data, buf, 10);
1117
0
                        data += sizeof(short);
1118
0
                        break;
1119
0
                    case CV_32S:
1120
0
                        ptr = fs::itoa(*(int *) data, buf, 10);
1121
0
                        data += sizeof(int);
1122
0
                        break;
1123
0
                    case CV_32F:
1124
0
                        ptr = fs::floatToString(buf, sizeof(buf), *(float *) data, false, explicitZero);
1125
0
                        data += sizeof(float);
1126
0
                        break;
1127
0
                    case CV_64F:
1128
0
                        ptr = fs::doubleToString(buf, sizeof(buf), *(double *) data, explicitZero);
1129
0
                        data += sizeof(double);
1130
0
                        break;
1131
0
                    case CV_16F: /* reference */
1132
0
                        ptr = fs::floatToString(buf, sizeof(buf), (float) *(float16_t *) data, true, explicitZero);
1133
0
                        data += sizeof(float16_t);
1134
0
                        break;
1135
0
                    default:
1136
0
                        CV_Error(cv::Error::StsUnsupportedFormat, "Unsupported type");
1137
0
                        return;
1138
0
                }
1139
1140
0
                getEmitter().writeScalar(0, ptr);
1141
0
            }
1142
1143
0
            offset = (int) (data - data0);
1144
0
        }
1145
0
    }
1146
0
}
1147
1148
0
void FileStorage::Impl::workaround() {
1149
0
    check_if_write_struct_is_delayed(false);
1150
1151
0
    if (state_of_writing_base64 != FileStorage_API::Base64State::Uncertain)
1152
0
        switch_to_Base64_state(FileStorage_API::Base64State::Uncertain);
1153
0
}
1154
1155
0
void FileStorage::Impl::switch_to_Base64_state(FileStorage_API::Base64State new_state) {
1156
0
    const char *err_unkonwn_state = "Unexpected error, unable to determine the Base64 state.";
1157
0
    const char *err_unable_to_switch = "Unexpected error, unable to switch to this state.";
1158
1159
    /* like a finite state machine */
1160
0
    switch (state_of_writing_base64) {
1161
0
        case FileStorage_API::Base64State::Uncertain:
1162
0
            switch (new_state) {
1163
0
                case FileStorage_API::Base64State::InUse:
1164
0
                {
1165
0
                    CV_DbgAssert(base64_writer == 0);
1166
0
                    bool can_indent = (fmt != cv::FileStorage::Mode::FORMAT_JSON);
1167
0
                    base64_writer = new base64::Base64Writer(*this, can_indent);
1168
0
                    if (!can_indent) {
1169
0
                        char *ptr = bufferPtr();
1170
0
                        *ptr++ = '\0';
1171
0
                        puts(bufferStart());
1172
0
                        setBufferPtr(bufferStart());
1173
0
                        memset(bufferStart(), 0, static_cast<int>(space));
1174
0
                        puts("\"$base64$");
1175
0
                    }
1176
0
                    break;
1177
0
                }
1178
0
                case FileStorage_API::Base64State::Uncertain:
1179
0
                    break;
1180
0
                case FileStorage_API::Base64State::NotUse:
1181
0
                    break;
1182
0
                default:
1183
0
                    CV_Error(cv::Error::StsError, err_unkonwn_state);
1184
0
                    break;
1185
0
            }
1186
0
            break;
1187
0
        case FileStorage_API::Base64State::InUse:
1188
0
            switch (new_state) {
1189
0
                case FileStorage_API::Base64State::InUse:
1190
0
                case FileStorage_API::Base64State::NotUse:
1191
0
                    CV_Error(cv::Error::StsError, err_unable_to_switch);
1192
0
                    break;
1193
0
                case FileStorage_API::Base64State::Uncertain:
1194
0
                    delete base64_writer;
1195
0
                    base64_writer = 0;
1196
0
                    if ( fmt == cv::FileStorage::FORMAT_JSON )
1197
0
                    {
1198
0
                        puts("\"");
1199
0
                        setBufferPtr(bufferStart());
1200
0
                        flush();
1201
0
                        memset(bufferStart(), 0, static_cast<int>(space) );
1202
0
                        setBufferPtr(bufferStart());
1203
0
                    }
1204
0
                    break;
1205
0
                default:
1206
0
                    CV_Error(cv::Error::StsError, err_unkonwn_state);
1207
0
                    break;
1208
0
            }
1209
0
            break;
1210
0
        case FileStorage_API::Base64State::NotUse:
1211
0
            switch (new_state) {
1212
0
                case FileStorage_API::Base64State::InUse:
1213
0
                case FileStorage_API::Base64State::NotUse:
1214
0
                    CV_Error(cv::Error::StsError, err_unable_to_switch);
1215
0
                    break;
1216
0
                case FileStorage_API::Base64State::Uncertain:
1217
0
                    break;
1218
0
                default:
1219
0
                    CV_Error(cv::Error::StsError, err_unkonwn_state);
1220
0
                    break;
1221
0
            }
1222
0
            break;
1223
0
        default:
1224
0
            CV_Error(cv::Error::StsError, err_unkonwn_state);
1225
0
            break;
1226
0
    }
1227
1228
0
    state_of_writing_base64 = new_state;
1229
0
}
1230
1231
0
void FileStorage::Impl::make_write_struct_delayed(const char *key, int struct_flags, const char *type_name) {
1232
0
    CV_Assert(is_write_struct_delayed == false);
1233
0
    CV_DbgAssert(delayed_struct_key == nullptr);
1234
0
    CV_DbgAssert(delayed_struct_flags == 0);
1235
0
    CV_DbgAssert(delayed_type_name == nullptr);
1236
1237
0
    delayed_struct_flags = struct_flags;
1238
1239
0
    if (key != nullptr) {
1240
0
        delayed_struct_key = new char[strlen(key) + 1U];
1241
0
        strcpy(delayed_struct_key, key);
1242
0
    }
1243
1244
0
    if (type_name != nullptr) {
1245
0
        delayed_type_name = new char[strlen(type_name) + 1U];
1246
0
        strcpy(delayed_type_name, type_name);
1247
0
    }
1248
1249
0
    is_write_struct_delayed = true;
1250
0
}
1251
1252
0
void FileStorage::Impl::check_if_write_struct_is_delayed(bool change_type_to_base64) {
1253
0
    if (is_write_struct_delayed) {
1254
        /* save data to prevent recursive call errors */
1255
0
        std::string struct_key;
1256
0
        std::string type_name;
1257
0
        int struct_flags = delayed_struct_flags;
1258
1259
0
        if (delayed_struct_key != nullptr && *delayed_struct_key != '\0') {
1260
0
            struct_key.assign(delayed_struct_key);
1261
0
        }
1262
0
        if (delayed_type_name != nullptr && *delayed_type_name != '\0') {
1263
0
            type_name.assign(delayed_type_name);
1264
0
        }
1265
1266
        /* reset */
1267
0
        delete[] delayed_struct_key;
1268
0
        delete[] delayed_type_name;
1269
0
        delayed_struct_key = nullptr;
1270
0
        delayed_struct_flags = 0;
1271
0
        delayed_type_name = nullptr;
1272
1273
0
        is_write_struct_delayed = false;
1274
1275
        /* call */
1276
0
        if (change_type_to_base64) {
1277
0
            startWriteStruct_helper(struct_key.c_str(), struct_flags, "binary");
1278
0
            if (state_of_writing_base64 != FileStorage_API::Uncertain)
1279
0
                switch_to_Base64_state(FileStorage_API::Uncertain);
1280
0
            switch_to_Base64_state(FileStorage_API::InUse);
1281
0
        } else {
1282
0
            startWriteStruct_helper(struct_key.c_str(), struct_flags, type_name.c_str());
1283
0
            if (state_of_writing_base64 != FileStorage_API::Uncertain)
1284
0
                switch_to_Base64_state(FileStorage_API::Uncertain);
1285
0
            switch_to_Base64_state(FileStorage_API::NotUse);
1286
0
        }
1287
0
    }
1288
0
}
1289
1290
0
void FileStorage::Impl::writeRawDataBase64(const void *_data, size_t len, const char *dt) {
1291
0
    CV_Assert(write_mode);
1292
1293
0
    check_if_write_struct_is_delayed(true);
1294
1295
0
    if (state_of_writing_base64 == FileStorage_API::Base64State::Uncertain) {
1296
0
        switch_to_Base64_state(FileStorage_API::Base64State::InUse);
1297
0
    } else if (state_of_writing_base64 != FileStorage_API::Base64State::InUse) {
1298
0
        CV_Error(cv::Error::StsError, "Base64 should not be used at present.");
1299
0
    }
1300
1301
0
    base64_writer->write(_data, len, dt);
1302
0
}
1303
1304
0
FileNode FileStorage::Impl::getFirstTopLevelNode() const {
1305
0
    return roots.empty() ? FileNode() : roots[0];
1306
0
}
1307
1308
0
FileNode FileStorage::Impl::root(int streamIdx) const {
1309
0
    return streamIdx >= 0 && streamIdx < (int) roots.size() ? roots[streamIdx] : FileNode();
1310
0
}
1311
1312
0
FileNode FileStorage::Impl::operator[](const String &nodename) const {
1313
0
    return this->operator[](nodename.c_str());
1314
0
}
1315
1316
0
FileNode FileStorage::Impl::operator[](const char * /*nodename*/) const {
1317
0
    return FileNode();
1318
0
}
1319
1320
0
int FileStorage::Impl::getFormat() const { return fmt; }
1321
1322
0
char *FileStorage::Impl::bufferPtr() const { return (char *) (&buffer[0] + bufofs); }
1323
1324
0
char *FileStorage::Impl::bufferStart() const { return (char *) &buffer[0]; }
1325
1326
0
char *FileStorage::Impl::bufferEnd() const { return (char *) (&buffer[0] + buffer.size()); }
1327
1328
0
void FileStorage::Impl::setBufferPtr(char *ptr) {
1329
0
    char *bufferstart = bufferStart();
1330
0
    CV_Assert(ptr >= bufferstart && ptr <= bufferEnd());
1331
0
    bufofs = ptr - bufferstart;
1332
0
}
1333
1334
0
int FileStorage::Impl::wrapMargin() const { return wrap_margin; }
1335
1336
0
FStructData &FileStorage::Impl::getCurrentStruct() {
1337
0
    CV_Assert(!write_stack.empty());
1338
0
    return write_stack.back();
1339
0
}
1340
1341
0
void FileStorage::Impl::setNonEmpty() {
1342
0
    empty_stream = false;
1343
0
}
1344
1345
0
void FileStorage::Impl::processSpecialDouble(char *buf, double *value, char **endptr) {
1346
0
    FileStorage_API *fs = this;
1347
0
    char c = buf[0];
1348
0
    int inf_hi = 0x7ff00000;
1349
1350
0
    if (c == '-' || c == '+') {
1351
0
        inf_hi = c == '-' ? 0xfff00000 : 0x7ff00000;
1352
0
        c = *++buf;
1353
0
    }
1354
1355
0
    if (c != '.')
1356
0
        CV_PARSE_ERROR_CPP("Bad format of floating-point constant");
1357
1358
0
    Cv64suf v;
1359
0
    v.f = 0.;
1360
0
    if (toupper(buf[1]) == 'I' && toupper(buf[2]) == 'N' && toupper(buf[3]) == 'F')
1361
0
        v.u = (uint64) inf_hi << 32;
1362
0
    else if (toupper(buf[1]) == 'N' && toupper(buf[2]) == 'A' && toupper(buf[3]) == 'N')
1363
0
        v.u = (uint64) -1;
1364
0
    else
1365
0
        CV_PARSE_ERROR_CPP("Bad format of floating-point constant");
1366
0
    *value = v.f;
1367
0
    *endptr = buf + 4;
1368
0
}
1369
1370
0
double FileStorage::Impl::strtod(char *ptr, char **endptr) {
1371
0
    double fval = ::strtod(ptr, endptr);
1372
0
    if (**endptr == '.') {
1373
0
        char *dot_pos = *endptr;
1374
0
        *dot_pos = ',';
1375
0
        double fval2 = ::strtod(ptr, endptr);
1376
0
        *dot_pos = '.';
1377
0
        if (*endptr > dot_pos)
1378
0
            fval = fval2;
1379
0
        else
1380
0
            *endptr = dot_pos;
1381
0
    }
1382
1383
0
    if (*endptr == ptr || cv_isalpha(**endptr))
1384
0
        processSpecialDouble(ptr, &fval, endptr);
1385
1386
0
    return fval;
1387
0
}
1388
1389
0
void FileStorage::Impl::convertToCollection(int type, FileNode &node) {
1390
0
    CV_Assert(type == FileNode::SEQ || type == FileNode::MAP);
1391
1392
0
    int node_type = node.type();
1393
0
    if (node_type == type)
1394
0
        return;
1395
1396
0
    bool named = node.isNamed();
1397
0
    uchar *ptr = node.ptr() + 1 + (named ? 4 : 0);
1398
1399
0
    int ival = 0;
1400
0
    double fval = 0;
1401
0
    std::string sval;
1402
0
    bool add_first_scalar = false;
1403
1404
0
    if (node_type != FileNode::NONE) {
1405
        // scalar nodes can only be converted to sequences, e.g. in XML:
1406
        // <a>5[parser_position]... => create 5 with name "a"
1407
        // <a>5 6[parser_position]... => 5 is converted to [5] and then 6 is added to it
1408
        //
1409
        // otherwise we don't know where to get the element names from
1410
0
        CV_Assert(type == FileNode::SEQ);
1411
0
        if (node_type == FileNode::INT) {
1412
0
            ival = readInt(ptr);
1413
0
            add_first_scalar = true;
1414
0
        } else if (node_type == FileNode::REAL) {
1415
0
            fval = readReal(ptr);
1416
0
            add_first_scalar = true;
1417
0
        } else if (node_type == FileNode::STRING) {
1418
0
            sval = std::string(node);
1419
0
            add_first_scalar = true;
1420
0
        } else
1421
0
            CV_Error_(Error::StsError, ("The node of type %d cannot be converted to collection", node_type));
1422
0
    }
1423
1424
0
    ptr = reserveNodeSpace(node, 1 + (named ? 4 : 0) + 4 + 4);
1425
0
    *ptr++ = (uchar) (type | (named ? FileNode::NAMED : 0));
1426
    // name has been copied automatically
1427
0
    if (named)
1428
0
        ptr += 4;
1429
    // set raw_size(collection)==4, nelems(collection)==1
1430
0
    writeInt(ptr, 4);
1431
0
    writeInt(ptr + 4, 0);
1432
1433
0
    if (add_first_scalar)
1434
0
        addNode(node, std::string(), node_type,
1435
0
                node_type == FileNode::INT ? (const void *) &ival :
1436
0
                node_type == FileNode::REAL ? (const void *) &fval :
1437
0
                node_type == FileNode::STRING ? (const void *) sval.c_str() : 0,
1438
0
                -1);
1439
0
}
1440
1441
// a) allocates new FileNode (for that just set blockIdx to the last block and ofs to freeSpaceOfs) or
1442
// b) reallocates just created new node (blockIdx and ofs must be taken from FileNode).
1443
//    If there is no enough space in the current block (it should be the last block added so far),
1444
//    the last block is shrunk so that it ends immediately before the reallocated node. Then,
1445
//    a new block of sufficient size is allocated and the FileNode is placed in the beginning of it.
1446
// The case (a) can be used to allocate the very first node by setting blockIdx == ofs == 0.
1447
// In the case (b) the existing tag and the name are copied automatically.
1448
0
uchar *FileStorage::Impl::reserveNodeSpace(FileNode &node, size_t sz) {
1449
0
    bool shrinkBlock = false;
1450
0
    size_t shrinkBlockIdx = 0, shrinkSize = 0;
1451
1452
0
    uchar *ptr = 0, *blockEnd = 0;
1453
1454
0
    if (!fs_data_ptrs.empty()) {
1455
0
        size_t blockIdx = node.blockIdx;
1456
0
        size_t ofs = node.ofs;
1457
0
        CV_Assert(blockIdx == fs_data_ptrs.size() - 1);
1458
0
        CV_Assert(ofs <= fs_data_blksz[blockIdx]);
1459
0
        CV_Assert(freeSpaceOfs <= fs_data_blksz[blockIdx]);
1460
        //CV_Assert( freeSpaceOfs <= ofs + sz );
1461
1462
0
        ptr = fs_data_ptrs[blockIdx] + ofs;
1463
0
        blockEnd = fs_data_ptrs[blockIdx] + fs_data_blksz[blockIdx];
1464
1465
0
        CV_Assert(ptr >= fs_data_ptrs[blockIdx] && ptr <= blockEnd);
1466
0
        if (ptr + sz <= blockEnd) {
1467
0
            freeSpaceOfs = ofs + sz;
1468
0
            return ptr;
1469
0
        }
1470
1471
0
        if (ofs ==
1472
0
            0)  // FileNode is a first component of this block. Resize current block instead of allocation of new one.
1473
0
        {
1474
0
            fs_data[blockIdx]->resize(sz);
1475
0
            ptr = &fs_data[blockIdx]->at(0);
1476
0
            fs_data_ptrs[blockIdx] = ptr;
1477
0
            fs_data_blksz[blockIdx] = sz;
1478
0
            freeSpaceOfs = sz;
1479
0
            return ptr;
1480
0
        }
1481
1482
0
        shrinkBlock = true;
1483
0
        shrinkBlockIdx = blockIdx;
1484
0
        shrinkSize = ofs;
1485
0
    }
1486
1487
0
    size_t blockSize = std::max((size_t) CV_FS_MAX_LEN * 4 - 256, sz) + 256;
1488
0
    Ptr<std::vector<uchar> > pv = makePtr<std::vector<uchar> >(blockSize);
1489
0
    fs_data.push_back(pv);
1490
0
    uchar *new_ptr = &pv->at(0);
1491
0
    fs_data_ptrs.push_back(new_ptr);
1492
0
    fs_data_blksz.push_back(blockSize);
1493
0
    node.blockIdx = fs_data_ptrs.size() - 1;
1494
0
    node.ofs = 0;
1495
0
    freeSpaceOfs = sz;
1496
1497
0
    if (ptr && ptr + 5 <= blockEnd) {
1498
0
        new_ptr[0] = ptr[0];
1499
0
        if (ptr[0] & FileNode::NAMED) {
1500
0
            new_ptr[1] = ptr[1];
1501
0
            new_ptr[2] = ptr[2];
1502
0
            new_ptr[3] = ptr[3];
1503
0
            new_ptr[4] = ptr[4];
1504
0
        }
1505
0
    }
1506
1507
0
    if (shrinkBlock) {
1508
0
        fs_data[shrinkBlockIdx]->resize(shrinkSize);
1509
0
        fs_data_blksz[shrinkBlockIdx] = shrinkSize;
1510
0
    }
1511
1512
0
    return new_ptr;
1513
0
}
1514
1515
0
unsigned FileStorage::Impl::getStringOfs(const std::string &key) const {
1516
0
    str_hash_t::const_iterator it = str_hash.find(key);
1517
0
    return it != str_hash.end() ? it->second : 0;
1518
0
}
1519
1520
FileNode FileStorage::Impl::addNode(FileNode &collection, const std::string &key,
1521
0
                                    int elem_type, const void *value, int len) {
1522
0
    FileStorage_API *fs = this;
1523
0
    bool noname = key.empty() || (fmt == FileStorage::FORMAT_XML && strcmp(key.c_str(), "_") == 0);
1524
0
    convertToCollection(noname ? FileNode::SEQ : FileNode::MAP, collection);
1525
1526
0
    bool isseq = collection.empty() ? false : collection.isSeq();
1527
0
    if (noname != isseq)
1528
0
        CV_PARSE_ERROR_CPP(noname ? "Map element should have a name" :
1529
0
                           "Sequence element should not have name (use <_></_>)");
1530
0
    unsigned strofs = 0;
1531
0
    if (!noname) {
1532
0
        strofs = getStringOfs(key);
1533
0
        if (!strofs) {
1534
0
            strofs = (unsigned) str_hash_data.size();
1535
0
            size_t keysize = key.size() + 1;
1536
0
            str_hash_data.resize(strofs + keysize);
1537
0
            memcpy(&str_hash_data[0] + strofs, &key[0], keysize);
1538
0
            str_hash.insert(std::make_pair(key, strofs));
1539
0
        }
1540
0
    }
1541
1542
0
    uchar *cp = collection.ptr();
1543
1544
0
    size_t blockIdx = fs_data_ptrs.size() - 1;
1545
0
    size_t ofs = freeSpaceOfs;
1546
0
    FileNode node(fs_ext, blockIdx, ofs);
1547
1548
0
    size_t sz0 = 1 + (noname ? 0 : 4) + 8;
1549
0
    uchar *ptr = reserveNodeSpace(node, sz0);
1550
1551
0
    *ptr++ = (uchar) (elem_type | (noname ? 0 : FileNode::NAMED));
1552
0
    if (elem_type == FileNode::NONE)
1553
0
        freeSpaceOfs -= 8;
1554
1555
0
    if (!noname) {
1556
0
        writeInt(ptr, (int) strofs);
1557
0
        ptr += 4;
1558
0
    }
1559
1560
0
    if (elem_type == FileNode::SEQ || elem_type == FileNode::MAP) {
1561
0
        writeInt(ptr, 4);
1562
0
        writeInt(ptr, 0);
1563
0
    }
1564
1565
0
    if (value)
1566
0
        node.setValue(elem_type, value, len);
1567
1568
0
    if (collection.isNamed())
1569
0
        cp += 4;
1570
0
    int nelems = readInt(cp + 5);
1571
0
    writeInt(cp + 5, nelems + 1);
1572
1573
0
    return node;
1574
0
}
1575
1576
0
void FileStorage::Impl::finalizeCollection(FileNode &collection) {
1577
0
    if (!collection.isSeq() && !collection.isMap())
1578
0
        return;
1579
0
    uchar *ptr0 = collection.ptr(), *ptr = ptr0 + 1;
1580
0
    if (*ptr0 & FileNode::NAMED)
1581
0
        ptr += 4;
1582
0
    size_t blockIdx = collection.blockIdx;
1583
0
    size_t ofs = collection.ofs + (size_t) (ptr + 8 - ptr0);
1584
0
    size_t rawSize = 4;
1585
0
    unsigned sz = (unsigned) readInt(ptr + 4);
1586
0
    if (sz > 0) {
1587
0
        size_t lastBlockIdx = fs_data_ptrs.size() - 1;
1588
1589
0
        for (; blockIdx < lastBlockIdx; blockIdx++) {
1590
0
            rawSize += fs_data_blksz[blockIdx] - ofs;
1591
0
            ofs = 0;
1592
0
        }
1593
0
    }
1594
0
    rawSize += freeSpaceOfs - ofs;
1595
0
    writeInt(ptr, (int) rawSize);
1596
0
}
1597
1598
0
void FileStorage::Impl::normalizeNodeOfs(size_t &blockIdx, size_t &ofs) const {
1599
0
    while (ofs >= fs_data_blksz[blockIdx]) {
1600
0
        if (blockIdx == fs_data_blksz.size() - 1) {
1601
0
            CV_Assert(ofs == fs_data_blksz[blockIdx]);
1602
0
            break;
1603
0
        }
1604
0
        ofs -= fs_data_blksz[blockIdx];
1605
0
        blockIdx++;
1606
0
    }
1607
0
}
1608
1609
0
FileStorage::Impl::Base64State FileStorage::Impl::get_state_of_writing_base64() {
1610
0
    return state_of_writing_base64;
1611
0
}
1612
1613
0
int FileStorage::Impl::get_space() {
1614
0
    return space;
1615
0
}
1616
1617
1618
995
FileStorage::Impl::Base64Decoder::Base64Decoder() {
1619
995
    ofs = 0;
1620
995
    ptr = 0;
1621
995
    indent = 0;
1622
995
    totalchars = 0;
1623
995
    eos = true;
1624
995
}
1625
1626
0
void FileStorage::Impl::Base64Decoder::init(const Ptr<FileStorageParser> &_parser, char *_ptr, int _indent) {
1627
0
    parser_do_not_use_direct_dereference = _parser;
1628
0
    ptr = _ptr;
1629
0
    indent = _indent;
1630
0
    encoded.clear();
1631
0
    decoded.clear();
1632
0
    ofs = 0;
1633
0
    totalchars = 0;
1634
0
    eos = false;
1635
0
}
1636
1637
0
bool FileStorage::Impl::Base64Decoder::readMore(int needed) {
1638
0
    static const uchar base64tab[] =
1639
0
            {
1640
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1641
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1642
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63,
1643
0
                    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0,
1644
0
                    0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1645
0
                    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0,
1646
0
                    0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1647
0
                    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0,
1648
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1649
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1650
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1651
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1652
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1653
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1654
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1655
0
                    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1656
0
            };
1657
1658
0
    if (eos)
1659
0
        return false;
1660
1661
0
    size_t sz = decoded.size();
1662
0
    CV_Assert(ofs <= sz);
1663
0
    sz -= ofs;
1664
0
    for (size_t i = 0; i < sz; i++)
1665
0
        decoded[i] = decoded[ofs + i];
1666
1667
0
    decoded.resize(sz);
1668
0
    ofs = 0;
1669
1670
0
    CV_Assert(ptr);
1671
0
    char *beg = 0, *end = 0;
1672
0
    bool ok = getParser().getBase64Row(ptr, indent, beg, end);
1673
0
    ptr = end;
1674
0
    std::copy(beg, end, std::back_inserter(encoded));
1675
0
    totalchars += end - beg;
1676
1677
0
    if (!ok || beg == end) {
1678
        // in the end of base64 sequence pad it with '=' characters so that
1679
        // its total length is multiple of
1680
0
        eos = true;
1681
0
        size_t tc = totalchars;
1682
0
        for (; tc % 4 != 0; tc++)
1683
0
            encoded.push_back('=');
1684
0
    }
1685
1686
0
    int i = 0, j, n = (int) encoded.size();
1687
0
    if (n > 0) {
1688
0
        const uchar *tab = base64tab;
1689
0
        char *src = &encoded[0];
1690
1691
0
        for (; i <= n - 4; i += 4) {
1692
            // dddddd cccccc bbbbbb aaaaaa => ddddddcc ccccbbbb bbaaaaaa
1693
0
            uchar d = tab[(int) (uchar) src[i]], c = tab[(int) (uchar) src[i + 1]];
1694
0
            uchar b = tab[(int) (uchar) src[i + 2]], a = tab[(int) (uchar) src[i + 3]];
1695
1696
0
            decoded.push_back((uchar) ((d << 2) | (c >> 4)));
1697
0
            decoded.push_back((uchar) ((c << 4) | (b >> 2)));
1698
0
            decoded.push_back((uchar) ((b << 6) | a));
1699
0
        }
1700
0
    }
1701
1702
0
    if (i > 0 && encoded[i - 1] == '=') {
1703
0
        if (i > 1 && encoded[i - 2] == '=' && !decoded.empty())
1704
0
            decoded.pop_back();
1705
0
        if (!decoded.empty())
1706
0
            decoded.pop_back();
1707
0
    }
1708
1709
0
    n -= i;
1710
0
    for (j = 0; j < n; j++)
1711
0
        encoded[j] = encoded[i + j];
1712
0
    encoded.resize(n);
1713
1714
0
    return (int) decoded.size() >= needed;
1715
0
}
1716
1717
0
uchar FileStorage::Impl::Base64Decoder::getUInt8() {
1718
0
    size_t sz = decoded.size();
1719
0
    if (ofs >= sz && !readMore(1))
1720
0
        return (uchar) 0;
1721
0
    return decoded[ofs++];
1722
0
}
1723
1724
0
ushort FileStorage::Impl::Base64Decoder::getUInt16() {
1725
0
    size_t sz = decoded.size();
1726
0
    if (ofs + 2 > sz && !readMore(2))
1727
0
        return (ushort) 0;
1728
0
    ushort val = (decoded[ofs] + (decoded[ofs + 1] << 8));
1729
0
    ofs += 2;
1730
0
    return val;
1731
0
}
1732
1733
0
int FileStorage::Impl::Base64Decoder::getInt32() {
1734
0
    size_t sz = decoded.size();
1735
0
    if (ofs + 4 > sz && !readMore(4))
1736
0
        return 0;
1737
0
    int ival = readInt(&decoded[ofs]);
1738
0
    ofs += 4;
1739
0
    return ival;
1740
0
}
1741
1742
0
double FileStorage::Impl::Base64Decoder::getFloat64() {
1743
0
    size_t sz = decoded.size();
1744
0
    if (ofs + 8 > sz && !readMore(8))
1745
0
        return 0;
1746
0
    double fval = readReal(&decoded[ofs]);
1747
0
    ofs += 8;
1748
0
    return fval;
1749
0
}
1750
1751
0
bool FileStorage::Impl::Base64Decoder::endOfStream() const { return eos; }
1752
1753
0
char *FileStorage::Impl::Base64Decoder::getPtr() const { return ptr; }
1754
1755
1756
0
char *FileStorage::Impl::parseBase64(char *ptr, int indent, FileNode &collection) {
1757
0
    const int BASE64_HDR_SIZE = 24;
1758
0
    char dt[BASE64_HDR_SIZE + 1] = {0};
1759
0
    base64decoder.init(parser_do_not_use_direct_dereference, ptr, indent);
1760
1761
0
    int i, k;
1762
1763
0
    for (i = 0; i < BASE64_HDR_SIZE; i++)
1764
0
        dt[i] = (char) base64decoder.getUInt8();
1765
0
    for (i = 0; i < BASE64_HDR_SIZE; i++)
1766
0
        if (isspace(dt[i]))
1767
0
            break;
1768
0
    dt[i] = '\0';
1769
1770
0
    CV_Assert(!base64decoder.endOfStream());
1771
1772
0
    int fmt_pairs[CV_FS_MAX_FMT_PAIRS * 2];
1773
0
    int fmt_pair_count = fs::decodeFormat(dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS);
1774
0
    int ival = 0;
1775
0
    double fval = 0;
1776
1777
0
    for (;;) {
1778
0
        for (k = 0; k < fmt_pair_count; k++) {
1779
0
            int elem_type = fmt_pairs[k * 2 + 1];
1780
0
            int count = fmt_pairs[k * 2];
1781
1782
0
            for (i = 0; i < count; i++) {
1783
0
                int node_type = FileNode::INT;
1784
0
                switch (elem_type) {
1785
0
                    case CV_8U:
1786
0
                        ival = base64decoder.getUInt8();
1787
0
                        break;
1788
0
                    case CV_8S:
1789
0
                        ival = (char) base64decoder.getUInt8();
1790
0
                        break;
1791
0
                    case CV_16U:
1792
0
                        ival = base64decoder.getUInt16();
1793
0
                        break;
1794
0
                    case CV_16S:
1795
0
                        ival = (short) base64decoder.getUInt16();
1796
0
                        break;
1797
0
                    case CV_32S:
1798
0
                        ival = base64decoder.getInt32();
1799
0
                        break;
1800
0
                    case CV_32F: {
1801
0
                        Cv32suf v;
1802
0
                        v.i = base64decoder.getInt32();
1803
0
                        fval = v.f;
1804
0
                        node_type = FileNode::REAL;
1805
0
                    }
1806
0
                        break;
1807
0
                    case CV_64F:
1808
0
                        fval = base64decoder.getFloat64();
1809
0
                        node_type = FileNode::REAL;
1810
0
                        break;
1811
0
                    case CV_16F:
1812
0
                        fval = (float) float16_t::fromBits(base64decoder.getUInt16());
1813
0
                        node_type = FileNode::REAL;
1814
0
                        break;
1815
0
                    default:
1816
0
                        CV_Error(Error::StsUnsupportedFormat, "Unsupported type");
1817
0
                }
1818
1819
0
                if (base64decoder.endOfStream())
1820
0
                    break;
1821
0
                addNode(collection, std::string(), node_type,
1822
0
                        node_type == FileNode::INT ? (void *) &ival : (void *) &fval, -1);
1823
0
            }
1824
0
        }
1825
0
        if (base64decoder.endOfStream())
1826
0
            break;
1827
0
    }
1828
1829
0
    finalizeCollection(collection);
1830
0
    return base64decoder.getPtr();
1831
0
}
1832
1833
void FileStorage::Impl::parseError(const char *func_name, const std::string &err_msg, const char *source_file,
1834
0
                                   int source_line) {
1835
0
    std::string msg = format("%s(%d): %s", filename.c_str(), lineno, err_msg.c_str());
1836
0
    error(Error::StsParseError, func_name, msg.c_str(), source_file, source_line);
1837
0
}
1838
1839
0
const uchar *FileStorage::Impl::getNodePtr(size_t blockIdx, size_t ofs) const {
1840
0
    CV_Assert(blockIdx < fs_data_ptrs.size());
1841
0
    CV_Assert(ofs < fs_data_blksz[blockIdx]);
1842
1843
0
    return fs_data_ptrs[blockIdx] + ofs;
1844
0
}
1845
1846
0
std::string FileStorage::Impl::getName(size_t nameofs) const {
1847
0
    CV_Assert(nameofs < str_hash_data.size());
1848
0
    return std::string(&str_hash_data[nameofs]);
1849
0
}
1850
1851
0
FileStorage *FileStorage::Impl::getFS() { return fs_ext; }
1852
1853
1854
FileStorage::FileStorage()
1855
    : state(0)
1856
995
{
1857
995
    p = makePtr<FileStorage::Impl>(this);
1858
995
}
1859
1860
FileStorage::FileStorage(const String& filename, int flags, const String& encoding)
1861
    : state(0)
1862
0
{
1863
0
    p = makePtr<FileStorage::Impl>(this);
1864
0
    bool ok = p->open(filename.c_str(), flags, encoding.c_str());
1865
0
    if(ok)
1866
0
        state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
1867
0
}
1868
1869
void FileStorage::startWriteStruct(const String& name, int struct_flags, const String& typeName)
1870
0
{
1871
0
    p->startWriteStruct(name.size() ? name.c_str() : 0, struct_flags, typeName.size() ? typeName.c_str() : 0);
1872
0
    elname = String();
1873
0
    if ((struct_flags & FileNode::TYPE_MASK) == FileNode::SEQ)
1874
0
        state = FileStorage::VALUE_EXPECTED;
1875
0
    else
1876
0
        state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
1877
0
}
1878
1879
void FileStorage::endWriteStruct()
1880
0
{
1881
0
    p->endWriteStruct();
1882
0
    state = p->write_stack.empty() || FileNode::isMap(p->write_stack.back().flags) ?
1883
0
        FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP :
1884
0
        FileStorage::VALUE_EXPECTED;
1885
0
    elname = String();
1886
0
}
1887
1888
FileStorage::~FileStorage()
1889
995
{
1890
995
}
1891
1892
bool FileStorage::open(const String& filename, int flags, const String& encoding)
1893
994
{
1894
994
    try
1895
994
    {
1896
994
        bool ok = p->open(filename.c_str(), flags, encoding.c_str());
1897
994
        if(ok)
1898
0
            state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
1899
994
        return ok;
1900
994
    }
1901
994
    catch (...)
1902
994
    {
1903
418
        release();
1904
418
        throw;  // re-throw
1905
418
    }
1906
994
}
1907
1908
0
bool FileStorage::isOpened() const { return p->is_opened; }
1909
1910
void FileStorage::release()
1911
418
{
1912
418
    p->release();
1913
418
}
1914
1915
FileNode FileStorage::root(int i) const
1916
0
{
1917
0
    if( p.empty() || p->roots.empty() || i < 0 || i >= (int)p->roots.size() )
1918
0
        return FileNode();
1919
1920
0
    return p->roots[i];
1921
0
}
1922
1923
FileNode FileStorage::getFirstTopLevelNode() const
1924
0
{
1925
0
    FileNode r = root();
1926
0
    FileNodeIterator it = r.begin();
1927
0
    return it != r.end() ? *it : FileNode();
1928
0
}
1929
1930
std::string FileStorage::getDefaultObjectName(const std::string& _filename)
1931
0
{
1932
0
    static const char* stubname = "unnamed";
1933
0
    const char* filename = _filename.c_str();
1934
0
    const char* ptr2 = filename + _filename.size();
1935
0
    const char* ptr = ptr2 - 1;
1936
0
    cv::AutoBuffer<char> name_buf(_filename.size()+1);
1937
1938
0
    while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
1939
0
    {
1940
0
        if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) )
1941
0
            ptr2 = ptr;
1942
0
        ptr--;
1943
0
    }
1944
0
    ptr++;
1945
0
    if( ptr == ptr2 )
1946
0
        CV_Error( cv::Error::StsBadArg, "Invalid filename" );
1947
1948
0
    char* name = name_buf.data();
1949
1950
    // name must start with letter or '_'
1951
0
    if( !cv_isalpha(*ptr) && *ptr!= '_' ){
1952
0
        *name++ = '_';
1953
0
    }
1954
1955
0
    while( ptr < ptr2 )
1956
0
    {
1957
0
        char c = *ptr++;
1958
0
        if( !cv_isalnum(c) && c != '-' && c != '_' )
1959
0
            c = '_';
1960
0
        *name++ = c;
1961
0
    }
1962
0
    *name = '\0';
1963
0
    name = name_buf.data();
1964
0
    if( strcmp( name, "_" ) == 0 )
1965
0
        strcpy( name, stubname );
1966
0
    return name;
1967
0
}
1968
1969
1970
int FileStorage::getFormat() const
1971
0
{
1972
0
    return p->fmt;
1973
0
}
1974
1975
FileNode FileStorage::operator [](const char* key) const
1976
0
{
1977
0
    return this->operator[](std::string(key));
1978
0
}
1979
1980
FileNode FileStorage::operator [](const std::string& key) const
1981
0
{
1982
0
    FileNode res;
1983
0
    for (size_t i = 0; i < p->roots.size(); i++)
1984
0
    {
1985
0
        res = p->roots[i][key];
1986
0
        if (!res.empty())
1987
0
            break;
1988
0
    }
1989
0
    return res;
1990
0
}
1991
1992
String FileStorage::releaseAndGetString()
1993
0
{
1994
0
    String buf;
1995
0
    p->release(&buf);
1996
0
    return buf;
1997
0
}
1998
1999
void FileStorage::writeRaw( const String& fmt, const void* vec, size_t len )
2000
0
{
2001
0
    p->writeRawData(fmt, (const uchar*)vec, len);
2002
0
}
2003
2004
void FileStorage::writeComment( const String& comment, bool eol_comment )
2005
0
{
2006
0
    p->writeComment(comment.c_str(), eol_comment);
2007
0
}
2008
2009
void writeScalar( FileStorage& fs, int value )
2010
0
{
2011
0
    fs.p->write(String(), value);
2012
0
}
2013
2014
void writeScalar( FileStorage& fs, float value )
2015
0
{
2016
0
    fs.p->write(String(), (double)value);
2017
0
}
2018
2019
void writeScalar( FileStorage& fs, double value )
2020
0
{
2021
0
    fs.p->write(String(), value);
2022
0
}
2023
2024
void writeScalar( FileStorage& fs, const String& value )
2025
0
{
2026
0
    fs.p->write(String(), value);
2027
0
}
2028
2029
void write( FileStorage& fs, const String& name, int value )
2030
0
{
2031
0
    fs.p->write(name, value);
2032
0
}
2033
2034
void write( FileStorage& fs, const String& name, float value )
2035
0
{
2036
0
    fs.p->write(name, (double)value);
2037
0
}
2038
2039
void write( FileStorage& fs, const String& name, double value )
2040
0
{
2041
0
    fs.p->write(name, value);
2042
0
}
2043
2044
void write( FileStorage& fs, const String& name, const String& value )
2045
0
{
2046
0
    fs.p->write(name, value);
2047
0
}
2048
2049
0
void FileStorage::write(const String& name, int val) { p->write(name, val); }
2050
0
void FileStorage::write(const String& name, double val) { p->write(name, val); }
2051
0
void FileStorage::write(const String& name, const String& val) { p->write(name, val); }
2052
0
void FileStorage::write(const String& name, const Mat& val) { cv::write(*this, name, val); }
2053
0
void FileStorage::write(const String& name, const std::vector<String>& val) { cv::write(*this, name, val); }
2054
2055
FileStorage& operator << (FileStorage& fs, const String& str)
2056
0
{
2057
0
    enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED,
2058
0
        VALUE_EXPECTED = FileStorage::VALUE_EXPECTED,
2059
0
        INSIDE_MAP = FileStorage::INSIDE_MAP };
2060
0
    const char* _str = str.c_str();
2061
0
    if( !fs.isOpened() || !_str )
2062
0
        return fs;
2063
0
    Ptr<FileStorage::Impl>& fs_impl = fs.p;
2064
0
    char c = *_str;
2065
2066
0
    if( c == '}' || c == ']' )
2067
0
    {
2068
0
        if( fs_impl->write_stack.empty() )
2069
0
            CV_Error_( cv::Error::StsError, ("Extra closing '%c'", *_str) );
2070
2071
0
        fs_impl->workaround();
2072
2073
0
        int struct_flags = fs_impl->write_stack.back().flags;
2074
0
        char expected_bracket = FileNode::isMap(struct_flags) ? '}' : ']';
2075
0
        if( c != expected_bracket )
2076
0
            CV_Error_( cv::Error::StsError, ("The closing '%c' does not match the opening '%c'", c, expected_bracket));
2077
0
        fs_impl->endWriteStruct();
2078
0
        CV_Assert(!fs_impl->write_stack.empty());
2079
0
        struct_flags = fs_impl->write_stack.back().flags;
2080
0
        fs.state = FileNode::isMap(struct_flags) ? INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED;
2081
0
        fs.elname = String();
2082
0
    }
2083
0
    else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
2084
0
    {
2085
0
        if (!cv_isalpha(c) && c != '_')
2086
0
            CV_Error_( cv::Error::StsError, ("Incorrect element name %s; should start with a letter or '_'", _str) );
2087
0
        fs.elname = str;
2088
0
        fs.state = VALUE_EXPECTED + INSIDE_MAP;
2089
0
    }
2090
0
    else if( (fs.state & 3) == VALUE_EXPECTED )
2091
0
    {
2092
0
        if( c == '{' || c == '[' )
2093
0
        {
2094
0
            int struct_flags = c == '{' ? FileNode::MAP : FileNode::SEQ;
2095
0
            fs.state = struct_flags == FileNode::MAP ? INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED;
2096
0
            _str++;
2097
0
            if( *_str == ':' )
2098
0
            {
2099
0
                _str++;
2100
0
                if( !*_str )
2101
0
                    struct_flags |= FileNode::FLOW;
2102
0
            }
2103
0
            fs_impl->startWriteStruct(!fs.elname.empty() ? fs.elname.c_str() : 0, struct_flags, *_str ? _str : 0 );
2104
0
            fs.elname = String();
2105
0
        }
2106
0
        else
2107
0
        {
2108
0
            write( fs, fs.elname, (c == '\\' && (_str[1] == '{' || _str[1] == '}' ||
2109
0
                                _str[1] == '[' || _str[1] == ']')) ? String(_str+1) : str );
2110
0
            if( fs.state == INSIDE_MAP + VALUE_EXPECTED )
2111
0
                fs.state = INSIDE_MAP + NAME_EXPECTED;
2112
0
        }
2113
0
    }
2114
0
    else
2115
0
        CV_Error( cv::Error::StsError, "Invalid fs.state" );
2116
0
    return fs;
2117
0
}
2118
2119
2120
FileNode::FileNode()
2121
    : fs(NULL)
2122
0
{
2123
0
    blockIdx = ofs = 0;
2124
0
}
2125
2126
FileNode::FileNode(FileStorage::Impl* _fs, size_t _blockIdx, size_t _ofs)
2127
    : fs(_fs)
2128
0
{
2129
0
    blockIdx = _blockIdx;
2130
0
    ofs = _ofs;
2131
0
}
2132
2133
FileNode::FileNode(const FileStorage* _fs, size_t _blockIdx, size_t _ofs)
2134
    : FileNode(_fs->p.get(), _blockIdx, _ofs)
2135
0
{
2136
    // nothing
2137
0
}
2138
2139
FileNode::FileNode(const FileNode& node)
2140
0
{
2141
0
    fs = node.fs;
2142
0
    blockIdx = node.blockIdx;
2143
0
    ofs = node.ofs;
2144
0
}
2145
2146
FileNode& FileNode::operator=(const FileNode& node)
2147
0
{
2148
0
    fs = node.fs;
2149
0
    blockIdx = node.blockIdx;
2150
0
    ofs = node.ofs;
2151
0
    return *this;
2152
0
}
2153
2154
FileNode FileNode::operator[](const std::string& nodename) const
2155
0
{
2156
0
    if(!fs)
2157
0
        return FileNode();
2158
2159
0
    CV_Assert( isMap() );
2160
2161
0
    unsigned key = fs->getStringOfs(nodename);
2162
0
    size_t i, sz = size();
2163
0
    FileNodeIterator it = begin();
2164
2165
0
    for( i = 0; i < sz; i++, ++it )
2166
0
    {
2167
0
        FileNode n = *it;
2168
0
        const uchar* p = n.ptr();
2169
0
        unsigned key2 = (unsigned)readInt(p + 1);
2170
0
        CV_Assert( key2 < fs->str_hash_data.size() );
2171
0
        if( key == key2 )
2172
0
            return n;
2173
0
    }
2174
0
    return FileNode();
2175
0
}
2176
2177
FileNode FileNode::operator[](const char* nodename) const
2178
0
{
2179
0
    return this->operator[](std::string(nodename));
2180
0
}
2181
2182
FileNode FileNode::operator[](int i) const
2183
0
{
2184
0
    if(!fs)
2185
0
        return FileNode();
2186
2187
0
    CV_Assert( isSeq() );
2188
2189
0
    int sz = (int)size();
2190
0
    CV_Assert( 0 <= i && i < sz );
2191
2192
0
    FileNodeIterator it = begin();
2193
0
    it += i;
2194
2195
0
    return *it;
2196
0
}
2197
2198
std::vector<String> FileNode::keys() const
2199
0
{
2200
0
    CV_Assert(isMap());
2201
2202
0
    std::vector<String> res;
2203
0
    res.reserve(size());
2204
0
    for (FileNodeIterator it = begin(); it != end(); ++it)
2205
0
    {
2206
0
        res.push_back((*it).name());
2207
0
    }
2208
0
    return res;
2209
0
}
2210
2211
int FileNode::type() const
2212
0
{
2213
0
    const uchar* p = ptr();
2214
0
    if(!p)
2215
0
        return NONE;
2216
0
    return (*p & TYPE_MASK);
2217
0
}
2218
2219
0
bool FileNode::isMap(int flags) { return (flags & TYPE_MASK) == MAP; }
2220
0
bool FileNode::isSeq(int flags) { return (flags & TYPE_MASK) == SEQ; }
2221
0
bool FileNode::isCollection(int flags) { return isMap(flags) || isSeq(flags); }
2222
0
bool FileNode::isFlow(int flags) { return (flags & FLOW) != 0; }
2223
0
bool FileNode::isEmptyCollection(int flags) { return (flags & EMPTY) != 0; }
2224
2225
0
bool FileNode::empty() const   { return fs == 0; }
2226
0
bool FileNode::isNone() const  { return type() == NONE; }
2227
0
bool FileNode::isSeq() const   { return type() == SEQ; }
2228
0
bool FileNode::isMap() const   { return type() == MAP; }
2229
0
bool FileNode::isInt() const   { return type() == INT;  }
2230
0
bool FileNode::isReal() const  { return type() == REAL; }
2231
0
bool FileNode::isString() const { return type() == STRING;  }
2232
bool FileNode::isNamed() const
2233
0
{
2234
0
    const uchar* p = ptr();
2235
0
    if(!p)
2236
0
        return false;
2237
0
    return (*p & NAMED) != 0;
2238
0
}
2239
2240
std::string FileNode::name() const
2241
0
{
2242
0
    const uchar* p = ptr();
2243
0
    if(!p)
2244
0
        return std::string();
2245
0
    size_t nameofs = p[1] | (p[2]<<8) | (p[3]<<16) | (p[4]<<24);
2246
0
    return fs->getName(nameofs);
2247
0
}
2248
2249
FileNode::operator int() const
2250
0
{
2251
0
    const uchar* p = ptr();
2252
0
    if(!p)
2253
0
        return 0;
2254
0
    int tag = *p;
2255
0
    int type = (tag & TYPE_MASK);
2256
0
    p += (tag & NAMED) ? 5 : 1;
2257
2258
0
    if( type == INT )
2259
0
    {
2260
0
        return readInt(p);
2261
0
    }
2262
0
    else if( type == REAL )
2263
0
    {
2264
0
        return cvRound(readReal(p));
2265
0
    }
2266
0
    else
2267
0
        return 0x7fffffff;
2268
0
}
2269
2270
FileNode::operator float() const
2271
0
{
2272
0
    const uchar* p = ptr();
2273
0
    if(!p)
2274
0
        return 0.f;
2275
0
    int tag = *p;
2276
0
    int type = (tag & TYPE_MASK);
2277
0
    p += (tag & NAMED) ? 5 : 1;
2278
2279
0
    if( type == INT )
2280
0
    {
2281
0
        return (float)readInt(p);
2282
0
    }
2283
0
    else if( type == REAL )
2284
0
    {
2285
0
        return (float)readReal(p);
2286
0
    }
2287
0
    else
2288
0
        return FLT_MAX;
2289
0
}
2290
2291
FileNode::operator double() const
2292
0
{
2293
0
    const uchar* p = ptr();
2294
0
    if(!p)
2295
0
        return 0.f;
2296
0
    int tag = *p;
2297
0
    int type = (tag & TYPE_MASK);
2298
0
    p += (tag & NAMED) ? 5 : 1;
2299
2300
0
    if( type == INT )
2301
0
    {
2302
0
        return (double)readInt(p);
2303
0
    }
2304
0
    else if( type == REAL )
2305
0
    {
2306
0
        return readReal(p);
2307
0
    }
2308
0
    else
2309
0
        return DBL_MAX;
2310
0
}
2311
2312
0
double FileNode::real() const  { return double(*this); }
2313
std::string FileNode::string() const
2314
0
{
2315
0
    const uchar* p = ptr();
2316
0
    if( !p || (*p & TYPE_MASK) != STRING )
2317
0
        return std::string();
2318
0
    p += (*p & NAMED) ? 5 : 1;
2319
0
    size_t sz = (size_t)(unsigned)readInt(p);
2320
0
    return std::string((const char*)(p + 4), sz - 1);
2321
0
}
2322
0
Mat FileNode::mat() const { Mat value; read(*this, value, Mat()); return value; }
2323
2324
0
FileNodeIterator FileNode::begin() const { return FileNodeIterator(*this, false); }
2325
0
FileNodeIterator FileNode::end() const   { return FileNodeIterator(*this, true); }
2326
2327
void FileNode::readRaw( const std::string& fmt, void* vec, size_t len ) const
2328
0
{
2329
0
    FileNodeIterator it = begin();
2330
0
    it.readRaw( fmt, vec, len );
2331
0
}
2332
2333
size_t FileNode::size() const
2334
0
{
2335
0
    const uchar* p = ptr();
2336
0
    if( !p )
2337
0
        return 0;
2338
0
    int tag = *p;
2339
0
    int tp = tag & TYPE_MASK;
2340
0
    if( tp == MAP || tp == SEQ )
2341
0
    {
2342
0
        if( tag & NAMED )
2343
0
            p += 4;
2344
0
        return (size_t)(unsigned)readInt(p + 5);
2345
0
    }
2346
0
    return tp != NONE;
2347
0
}
2348
2349
size_t FileNode::rawSize() const
2350
0
{
2351
0
    const uchar* p0 = ptr(), *p = p0;
2352
0
    if( !p )
2353
0
        return 0;
2354
0
    int tag = *p++;
2355
0
    int tp = tag & TYPE_MASK;
2356
0
    if( tag & NAMED )
2357
0
        p += 4;
2358
0
    size_t sz0 = (size_t)(p - p0);
2359
0
    if( tp == INT )
2360
0
        return sz0 + 4;
2361
0
    if( tp == REAL )
2362
0
        return sz0 + 8;
2363
0
    if( tp == NONE )
2364
0
        return sz0;
2365
0
    CV_Assert( tp == STRING || tp == SEQ || tp == MAP );
2366
0
    return sz0 + 4 + readInt(p);
2367
0
}
2368
2369
uchar* FileNode::ptr()
2370
0
{
2371
0
    return !fs ? 0 : (uchar*)fs->getNodePtr(blockIdx, ofs);
2372
0
}
2373
2374
const uchar* FileNode::ptr() const
2375
0
{
2376
0
    return !fs ? 0 : fs->getNodePtr(blockIdx, ofs);
2377
0
}
2378
2379
void FileNode::setValue( int type, const void* value, int len )
2380
0
{
2381
0
    uchar *p = ptr();
2382
0
    CV_Assert(p != 0);
2383
2384
0
    int tag = *p;
2385
0
    int current_type = tag & TYPE_MASK;
2386
0
    CV_Assert( current_type == NONE || current_type == type );
2387
2388
0
    int sz = 1;
2389
2390
0
    if( tag & NAMED )
2391
0
        sz += 4;
2392
2393
0
    if( type == INT )
2394
0
        sz += 4;
2395
0
    else if( type == REAL )
2396
0
        sz += 8;
2397
0
    else if( type == STRING )
2398
0
    {
2399
0
        if( len < 0 )
2400
0
            len = (int)strlen((const char*)value);
2401
0
        sz += 4 + len + 1; // besides the string content,
2402
                           // take the size (4 bytes) and the final '\0' into account
2403
0
    }
2404
0
    else
2405
0
        CV_Error(Error::StsNotImplemented, "Only scalar types can be dynamically assigned to a file node");
2406
2407
0
    p = fs->reserveNodeSpace(*this, sz);
2408
0
    *p++ = (uchar)(type | (tag & NAMED));
2409
0
    if( tag & NAMED )
2410
0
        p += 4;
2411
2412
0
    if( type == INT )
2413
0
    {
2414
0
        int ival = *(const int*)value;
2415
0
        writeInt(p, ival);
2416
0
    }
2417
0
    else if( type == REAL )
2418
0
    {
2419
0
        double dbval = *(const double*)value;
2420
0
        writeReal(p, dbval);
2421
0
    }
2422
0
    else if( type == STRING )
2423
0
    {
2424
0
        const char* str = (const char*)value;
2425
0
        writeInt(p, len + 1);
2426
0
        memcpy(p + 4, str, len);
2427
0
        p[4 + len] = (uchar)'\0';
2428
0
    }
2429
0
}
2430
2431
FileNodeIterator::FileNodeIterator()
2432
0
{
2433
0
    fs = 0;
2434
0
    blockIdx = 0;
2435
0
    ofs = 0;
2436
0
    blockSize = 0;
2437
0
    nodeNElems = 0;
2438
0
    idx = 0;
2439
0
}
2440
2441
FileNodeIterator::FileNodeIterator( const FileNode& node, bool seekEnd )
2442
0
{
2443
0
    fs = node.fs;
2444
0
    idx = 0;
2445
0
    if( !fs )
2446
0
        blockIdx = ofs = blockSize = nodeNElems = 0;
2447
0
    else
2448
0
    {
2449
0
        blockIdx = node.blockIdx;
2450
0
        ofs = node.ofs;
2451
2452
0
        bool collection = node.isSeq() || node.isMap();
2453
0
        if( node.isNone() )
2454
0
        {
2455
0
            nodeNElems = 0;
2456
0
        }
2457
0
        else if( !collection )
2458
0
        {
2459
0
            nodeNElems = 1;
2460
0
            if( seekEnd )
2461
0
            {
2462
0
                idx = 1;
2463
0
                ofs += node.rawSize();
2464
0
            }
2465
0
        }
2466
0
        else
2467
0
        {
2468
0
            nodeNElems = node.size();
2469
0
            const uchar* p0 = node.ptr(), *p = p0 + 1;
2470
0
            if(*p0 & FileNode::NAMED )
2471
0
                p += 4;
2472
0
            if( !seekEnd )
2473
0
                ofs += (p - p0) + 8;
2474
0
            else
2475
0
            {
2476
0
                size_t rawsz = (size_t)(unsigned)readInt(p);
2477
0
                ofs += (p - p0) + 4 + rawsz;
2478
0
                idx = nodeNElems;
2479
0
            }
2480
0
        }
2481
0
        fs->normalizeNodeOfs(blockIdx, ofs);
2482
0
        blockSize = fs->fs_data_blksz[blockIdx];
2483
0
    }
2484
0
}
2485
2486
FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
2487
0
{
2488
0
    fs = it.fs;
2489
0
    blockIdx = it.blockIdx;
2490
0
    ofs = it.ofs;
2491
0
    blockSize = it.blockSize;
2492
0
    nodeNElems = it.nodeNElems;
2493
0
    idx = it.idx;
2494
0
}
2495
2496
FileNodeIterator& FileNodeIterator::operator=(const FileNodeIterator& it)
2497
0
{
2498
0
    fs = it.fs;
2499
0
    blockIdx = it.blockIdx;
2500
0
    ofs = it.ofs;
2501
0
    blockSize = it.blockSize;
2502
0
    nodeNElems = it.nodeNElems;
2503
0
    idx = it.idx;
2504
0
    return *this;
2505
0
}
2506
2507
FileNode FileNodeIterator::operator *() const
2508
0
{
2509
0
    return FileNode(idx < nodeNElems ? fs : NULL, blockIdx, ofs);
2510
0
}
2511
2512
FileNodeIterator& FileNodeIterator::operator ++ ()
2513
0
{
2514
0
    if( idx == nodeNElems || !fs )
2515
0
        return *this;
2516
0
    idx++;
2517
0
    FileNode n(fs, blockIdx, ofs);
2518
0
    ofs += n.rawSize();
2519
0
    if( ofs >= blockSize )
2520
0
    {
2521
0
        fs->normalizeNodeOfs(blockIdx, ofs);
2522
0
        blockSize = fs->fs_data_blksz[blockIdx];
2523
0
    }
2524
0
    return *this;
2525
0
}
2526
2527
FileNodeIterator FileNodeIterator::operator ++ (int)
2528
0
{
2529
0
    FileNodeIterator it = *this;
2530
0
    ++(*this);
2531
0
    return it;
2532
0
}
2533
2534
FileNodeIterator& FileNodeIterator::operator += (int _ofs)
2535
0
{
2536
0
    CV_Assert( _ofs >= 0 );
2537
0
    for( ; _ofs > 0; _ofs-- )
2538
0
        this->operator ++();
2539
0
    return *this;
2540
0
}
2541
2542
FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, void* _data0, size_t maxsz)
2543
0
{
2544
0
    if( fs && idx < nodeNElems )
2545
0
    {
2546
0
        uchar* data0 = (uchar*)_data0;
2547
0
        int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2];
2548
0
        int fmt_pair_count = fs::decodeFormat( fmt.c_str(), fmt_pairs, CV_FS_MAX_FMT_PAIRS );
2549
0
        size_t esz = fs::calcStructSize( fmt.c_str(), 0 );
2550
2551
0
        CV_Assert( maxsz % esz == 0 );
2552
0
        maxsz /= esz;
2553
2554
0
        for( ; maxsz > 0; maxsz--, data0 += esz )
2555
0
        {
2556
0
            size_t offset = 0;
2557
0
            for( int k = 0; k < fmt_pair_count; k++ )
2558
0
            {
2559
0
                int elem_type = fmt_pairs[k*2+1];
2560
0
                int elem_size = CV_ELEM_SIZE(elem_type);
2561
2562
0
                int count = fmt_pairs[k*2];
2563
0
                offset = alignSize( offset, elem_size );
2564
0
                uchar* data = data0 + offset;
2565
2566
0
                for( int i = 0; i < count; i++, ++(*this) )
2567
0
                {
2568
0
                    FileNode node = *(*this);
2569
0
                    if( node.isInt() )
2570
0
                    {
2571
0
                        int ival = (int)node;
2572
0
                        switch( elem_type )
2573
0
                        {
2574
0
                        case CV_8U:
2575
0
                            *(uchar*)data = saturate_cast<uchar>(ival);
2576
0
                            data++;
2577
0
                            break;
2578
0
                        case CV_8S:
2579
0
                            *(char*)data = saturate_cast<schar>(ival);
2580
0
                            data++;
2581
0
                            break;
2582
0
                        case CV_16U:
2583
0
                            *(ushort*)data = saturate_cast<ushort>(ival);
2584
0
                            data += sizeof(ushort);
2585
0
                            break;
2586
0
                        case CV_16S:
2587
0
                            *(short*)data = saturate_cast<short>(ival);
2588
0
                            data += sizeof(short);
2589
0
                            break;
2590
0
                        case CV_32S:
2591
0
                            *(int*)data = ival;
2592
0
                            data += sizeof(int);
2593
0
                            break;
2594
0
                        case CV_32F:
2595
0
                            *(float*)data = (float)ival;
2596
0
                            data += sizeof(float);
2597
0
                            break;
2598
0
                        case CV_64F:
2599
0
                            *(double*)data = (double)ival;
2600
0
                            data += sizeof(double);
2601
0
                            break;
2602
0
                        case CV_16F:
2603
0
                            *(float16_t*)data = float16_t((float)ival);
2604
0
                            data += sizeof(float16_t);
2605
0
                            break;
2606
0
                        default:
2607
0
                            CV_Error( Error::StsUnsupportedFormat, "Unsupported type" );
2608
0
                        }
2609
0
                    }
2610
0
                    else if( node.isReal() )
2611
0
                    {
2612
0
                        double fval = (double)node;
2613
2614
0
                        switch( elem_type )
2615
0
                        {
2616
0
                        case CV_8U:
2617
0
                            *(uchar*)data = saturate_cast<uchar>(fval);
2618
0
                            data++;
2619
0
                            break;
2620
0
                        case CV_8S:
2621
0
                            *(char*)data = saturate_cast<schar>(fval);
2622
0
                            data++;
2623
0
                            break;
2624
0
                        case CV_16U:
2625
0
                            *(ushort*)data = saturate_cast<ushort>(fval);
2626
0
                            data += sizeof(ushort);
2627
0
                            break;
2628
0
                        case CV_16S:
2629
0
                            *(short*)data = saturate_cast<short>(fval);
2630
0
                            data += sizeof(short);
2631
0
                            break;
2632
0
                        case CV_32S:
2633
0
                            *(int*)data = saturate_cast<int>(fval);
2634
0
                            data += sizeof(int);
2635
0
                            break;
2636
0
                        case CV_32F:
2637
0
                            *(float*)data = (float)fval;
2638
0
                            data += sizeof(float);
2639
0
                            break;
2640
0
                        case CV_64F:
2641
0
                            *(double*)data = fval;
2642
0
                            data += sizeof(double);
2643
0
                            break;
2644
0
                        case CV_16F:
2645
0
                            *(float16_t*)data = float16_t((float)fval);
2646
0
                            data += sizeof(float16_t);
2647
0
                            break;
2648
0
                        default:
2649
0
                            CV_Error( Error::StsUnsupportedFormat, "Unsupported type" );
2650
0
                        }
2651
0
                    }
2652
0
                    else
2653
0
                        CV_Error( Error::StsError, "readRawData can only be used to read plain sequences of numbers" );
2654
0
                }
2655
0
                offset = (int)(data - data0);
2656
0
            }
2657
0
        }
2658
0
    }
2659
2660
0
    return *this;
2661
0
}
2662
2663
bool FileNodeIterator::equalTo(const FileNodeIterator& it) const
2664
0
{
2665
0
    return fs == it.fs && blockIdx == it.blockIdx && ofs == it.ofs &&
2666
0
           idx == it.idx && nodeNElems == it.nodeNElems;
2667
0
}
2668
2669
size_t FileNodeIterator::remaining() const
2670
0
{
2671
0
    return nodeNElems - idx;
2672
0
}
2673
2674
bool operator == ( const FileNodeIterator& it1, const FileNodeIterator& it2 )
2675
0
{
2676
0
    return it1.equalTo(it2);
2677
0
}
2678
2679
bool operator != ( const FileNodeIterator& it1, const FileNodeIterator& it2 )
2680
0
{
2681
0
    return !it1.equalTo(it2);
2682
0
}
2683
2684
void read(const FileNode& node, int& val, int default_val)
2685
0
{
2686
0
    val = default_val;
2687
0
    if( !node.empty() )
2688
0
    {
2689
0
        val = (int)node;
2690
0
    }
2691
0
}
2692
2693
void read(const FileNode& node, double& val, double default_val)
2694
0
{
2695
0
    val = default_val;
2696
0
    if( !node.empty() )
2697
0
    {
2698
0
        val = (double)node;
2699
0
    }
2700
0
}
2701
2702
void read(const FileNode& node, float& val, float default_val)
2703
0
{
2704
0
    val = default_val;
2705
0
    if( !node.empty() )
2706
0
    {
2707
0
        val = (float)node;
2708
0
    }
2709
0
}
2710
2711
void read(const FileNode& node, std::string& val, const std::string& default_val)
2712
0
{
2713
0
    val = default_val;
2714
0
    if( !node.empty() )
2715
0
    {
2716
0
        val = (std::string)node;
2717
0
    }
2718
0
}
2719
2720
995
FileStorage_API::~FileStorage_API() {}
2721
2722
namespace internal
2723
{
2724
2725
WriteStructContext::WriteStructContext(FileStorage& _fs, const std::string& name,
2726
                                       int flags, const std::string& typeName)
2727
0
{
2728
0
    fs = &_fs;
2729
0
    fs->startWriteStruct(name, flags, typeName);
2730
0
}
2731
2732
WriteStructContext::~WriteStructContext()
2733
0
{
2734
0
    fs->endWriteStruct();
2735
0
}
2736
2737
}
2738
2739
}