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

source code of opencv/modules/core/src/persistence.cpp