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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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