1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42 
43 #include "precomp.hpp"
44 
45 #include <ctype.h>
46 #include <deque>
47 #include <iterator>
48 
49 #define USE_ZLIB 1
50 
51 #ifdef __APPLE__
52 #  include "TargetConditionals.h"
53 #  if (defined TARGET_OS_IPHONE && TARGET_OS_IPHONE) || (defined TARGET_IPHONE_SIMULATOR && TARGET_IPHONE_SIMULATOR)
54 #    undef USE_ZLIB
55 #    define USE_ZLIB 0
56      typedef void* gzFile;
57 #  endif
58 #endif
59 
60 #if USE_ZLIB
61 #  ifndef _LFS64_LARGEFILE
62 #    define _LFS64_LARGEFILE 0
63 #  endif
64 #  ifndef _FILE_OFFSET_BITS
65 #    define _FILE_OFFSET_BITS 0
66 #  endif
67 #  include <zlib.h>
68 #endif
69 
70 /****************************************************************************************\
71 *                            Common macros and type definitions                          *
72 \****************************************************************************************/
73 
74 #define cv_isprint(c)     ((uchar)(c) >= (uchar)' ')
75 #define cv_isprint_or_tab(c)  ((uchar)(c) >= (uchar)' ' || (c) == '\t')
76 
cv_isalnum(char c)77 static inline bool cv_isalnum(char c)
78 {
79     return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
80 }
81 
cv_isalpha(char c)82 static inline bool cv_isalpha(char c)
83 {
84     return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
85 }
86 
cv_isdigit(char c)87 static inline bool cv_isdigit(char c)
88 {
89     return '0' <= c && c <= '9';
90 }
91 
cv_isspace(char c)92 static inline bool cv_isspace(char c)
93 {
94     return (9 <= c && c <= 13) || c == ' ';
95 }
96 
icv_itoa(int _val,char * buffer,int)97 static char* icv_itoa( int _val, char* buffer, int /*radix*/ )
98 {
99     const int radix = 10;
100     char* ptr=buffer + 23 /* enough even for 64-bit integers */;
101     unsigned val = abs(_val);
102 
103     *ptr = '\0';
104     do
105     {
106         unsigned r = val / radix;
107         *--ptr = (char)(val - (r*radix) + '0');
108         val = r;
109     }
110     while( val != 0 );
111 
112     if( _val < 0 )
113         *--ptr = '-';
114 
115     return ptr;
116 }
117 
getDefaultObjectName(const cv::String & _filename)118 cv::String cv::FileStorage::getDefaultObjectName(const cv::String& _filename)
119 {
120     static const char* stubname = "unnamed";
121     const char* filename = _filename.c_str();
122     const char* ptr2 = filename + _filename.size();
123     const char* ptr = ptr2 - 1;
124     cv::AutoBuffer<char> name_buf(_filename.size()+1);
125 
126     while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
127     {
128         if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) )
129             ptr2 = ptr;
130         ptr--;
131     }
132     ptr++;
133     if( ptr == ptr2 )
134         CV_Error( CV_StsBadArg, "Invalid filename" );
135 
136     char* name = name_buf;
137 
138     // name must start with letter or '_'
139     if( !cv_isalpha(*ptr) && *ptr!= '_' ){
140         *name++ = '_';
141     }
142 
143     while( ptr < ptr2 )
144     {
145         char c = *ptr++;
146         if( !cv_isalnum(c) && c != '-' && c != '_' )
147             c = '_';
148         *name++ = c;
149     }
150     *name = '\0';
151     name = name_buf;
152     if( strcmp( name, "_" ) == 0 )
153         strcpy( name, stubname );
154     return String(name);
155 }
156 
157 typedef struct CvGenericHash
158 {
159     CV_SET_FIELDS()
160     int tab_size;
161     void** table;
162 }
163 CvGenericHash;
164 
165 typedef CvGenericHash CvStringHash;
166 
167 typedef struct CvFileMapNode
168 {
169     CvFileNode value;
170     const CvStringHashNode* key;
171     struct CvFileMapNode* next;
172 }
173 CvFileMapNode;
174 
175 typedef struct CvXMLStackRecord
176 {
177     CvMemStoragePos pos;
178     CvString struct_tag;
179     int struct_indent;
180     int struct_flags;
181 }
182 CvXMLStackRecord;
183 
184 #define CV_XML_OPENING_TAG 1
185 #define CV_XML_CLOSING_TAG 2
186 #define CV_XML_EMPTY_TAG 3
187 #define CV_XML_HEADER_TAG 4
188 #define CV_XML_DIRECTIVE_TAG 5
189 
190 //typedef void (*CvParse)( struct CvFileStorage* fs );
191 typedef void (*CvStartWriteStruct)( struct CvFileStorage* fs, const char* key,
192                                     int struct_flags, const char* type_name );
193 typedef void (*CvEndWriteStruct)( struct CvFileStorage* fs );
194 typedef void (*CvWriteInt)( struct CvFileStorage* fs, const char* key, int value );
195 typedef void (*CvWriteReal)( struct CvFileStorage* fs, const char* key, double value );
196 typedef void (*CvWriteString)( struct CvFileStorage* fs, const char* key,
197                                const char* value, int quote );
198 typedef void (*CvWriteComment)( struct CvFileStorage* fs, const char* comment, int eol_comment );
199 typedef void (*CvStartNextStream)( struct CvFileStorage* fs );
200 
201 typedef struct CvFileStorage
202 {
203     int flags;
204     int fmt;
205     int write_mode;
206     int is_first;
207     CvMemStorage* memstorage;
208     CvMemStorage* dststorage;
209     CvMemStorage* strstorage;
210     CvStringHash* str_hash;
211     CvSeq* roots;
212     CvSeq* write_stack;
213     int struct_indent;
214     int struct_flags;
215     CvString struct_tag;
216     int space;
217     char* filename;
218     FILE* file;
219     gzFile gzfile;
220     char* buffer;
221     char* buffer_start;
222     char* buffer_end;
223     int wrap_margin;
224     int lineno;
225     int dummy_eof;
226     const char* errmsg;
227     char errmsgbuf[128];
228 
229     CvStartWriteStruct start_write_struct;
230     CvEndWriteStruct end_write_struct;
231     CvWriteInt write_int;
232     CvWriteReal write_real;
233     CvWriteString write_string;
234     CvWriteComment write_comment;
235     CvStartNextStream start_next_stream;
236 
237     const char* strbuf;
238     size_t strbufsize, strbufpos;
239     std::deque<char>* outbuf;
240 
241     bool is_opened;
242 }
243 CvFileStorage;
244 
icvPuts(CvFileStorage * fs,const char * str)245 static void icvPuts( CvFileStorage* fs, const char* str )
246 {
247     if( fs->outbuf )
248         std::copy(str, str + strlen(str), std::back_inserter(*fs->outbuf));
249     else if( fs->file )
250         fputs( str, fs->file );
251 #if USE_ZLIB
252     else if( fs->gzfile )
253         gzputs( fs->gzfile, str );
254 #endif
255     else
256         CV_Error( CV_StsError, "The storage is not opened" );
257 }
258 
icvGets(CvFileStorage * fs,char * str,int maxCount)259 static char* icvGets( CvFileStorage* fs, char* str, int maxCount )
260 {
261     if( fs->strbuf )
262     {
263         size_t i = fs->strbufpos, len = fs->strbufsize;
264         int j = 0;
265         const char* instr = fs->strbuf;
266         while( i < len && j < maxCount-1 )
267         {
268             char c = instr[i++];
269             if( c == '\0' )
270                 break;
271             str[j++] = c;
272             if( c == '\n' )
273                 break;
274         }
275         str[j++] = '\0';
276         fs->strbufpos = i;
277         return j > 1 ? str : 0;
278     }
279     if( fs->file )
280         return fgets( str, maxCount, fs->file );
281 #if USE_ZLIB
282     if( fs->gzfile )
283         return gzgets( fs->gzfile, str, maxCount );
284 #endif
285     CV_Error( CV_StsError, "The storage is not opened" );
286     return 0;
287 }
288 
icvEof(CvFileStorage * fs)289 static int icvEof( CvFileStorage* fs )
290 {
291     if( fs->strbuf )
292         return fs->strbufpos >= fs->strbufsize;
293     if( fs->file )
294         return feof(fs->file);
295 #if USE_ZLIB
296     if( fs->gzfile )
297         return gzeof(fs->gzfile);
298 #endif
299     return false;
300 }
301 
icvCloseFile(CvFileStorage * fs)302 static void icvCloseFile( CvFileStorage* fs )
303 {
304     if( fs->file )
305         fclose( fs->file );
306 #if USE_ZLIB
307     else if( fs->gzfile )
308         gzclose( fs->gzfile );
309 #endif
310     fs->file = 0;
311     fs->gzfile = 0;
312     fs->strbuf = 0;
313     fs->strbufpos = 0;
314     fs->is_opened = false;
315 }
316 
icvRewind(CvFileStorage * fs)317 static void icvRewind( CvFileStorage* fs )
318 {
319     if( fs->file )
320         rewind(fs->file);
321 #if USE_ZLIB
322     else if( fs->gzfile )
323         gzrewind(fs->gzfile);
324 #endif
325     fs->strbufpos = 0;
326 }
327 
328 #define CV_YML_INDENT  3
329 #define CV_XML_INDENT  2
330 #define CV_YML_INDENT_FLOW  1
331 #define CV_FS_MAX_LEN 4096
332 
333 #define CV_FILE_STORAGE ('Y' + ('A' << 8) + ('M' << 16) + ('L' << 24))
334 #define CV_IS_FILE_STORAGE(fs) ((fs) != 0 && (fs)->flags == CV_FILE_STORAGE)
335 
336 #define CV_CHECK_FILE_STORAGE(fs)                       \
337 {                                                       \
338     if( !CV_IS_FILE_STORAGE(fs) )                       \
339         CV_Error( (fs) ? CV_StsBadArg : CV_StsNullPtr,  \
340                   "Invalid pointer to file storage" );  \
341 }
342 
343 #define CV_CHECK_OUTPUT_FILE_STORAGE(fs)                \
344 {                                                       \
345     CV_CHECK_FILE_STORAGE(fs);                          \
346     if( !fs->write_mode )                               \
347         CV_Error( CV_StsError, "The file storage is opened for reading" ); \
348 }
349 
350 CV_IMPL const char*
cvAttrValue(const CvAttrList * attr,const char * attr_name)351 cvAttrValue( const CvAttrList* attr, const char* attr_name )
352 {
353     while( attr && attr->attr )
354     {
355         int i;
356         for( i = 0; attr->attr[i*2] != 0; i++ )
357         {
358             if( strcmp( attr_name, attr->attr[i*2] ) == 0 )
359                 return attr->attr[i*2+1];
360         }
361         attr = attr->next;
362     }
363 
364     return 0;
365 }
366 
367 
368 static CvGenericHash*
cvCreateMap(int flags,int header_size,int elem_size,CvMemStorage * storage,int start_tab_size)369 cvCreateMap( int flags, int header_size, int elem_size,
370              CvMemStorage* storage, int start_tab_size )
371 {
372     if( header_size < (int)sizeof(CvGenericHash) )
373         CV_Error( CV_StsBadSize, "Too small map header_size" );
374 
375     if( start_tab_size <= 0 )
376         start_tab_size = 16;
377 
378     CvGenericHash* map = (CvGenericHash*)cvCreateSet( flags, header_size, elem_size, storage );
379 
380     map->tab_size = start_tab_size;
381     start_tab_size *= sizeof(map->table[0]);
382     map->table = (void**)cvMemStorageAlloc( storage, start_tab_size );
383     memset( map->table, 0, start_tab_size );
384 
385     return map;
386 }
387 
388 #define CV_PARSE_ERROR( errmsg )                                    \
389     icvParseError( fs, CV_Func, (errmsg), __FILE__, __LINE__ )
390 
391 static void
icvParseError(CvFileStorage * fs,const char * func_name,const char * err_msg,const char * source_file,int source_line)392 icvParseError( CvFileStorage* fs, const char* func_name,
393                const char* err_msg, const char* source_file, int source_line )
394 {
395     char buf[1<<10];
396     sprintf( buf, "%s(%d): %s", fs->filename, fs->lineno, err_msg );
397     cvError( CV_StsParseError, func_name, buf, source_file, source_line );
398 }
399 
400 
401 static void
icvFSCreateCollection(CvFileStorage * fs,int tag,CvFileNode * collection)402 icvFSCreateCollection( CvFileStorage* fs, int tag, CvFileNode* collection )
403 {
404     if( CV_NODE_IS_MAP(tag) )
405     {
406         if( collection->tag != CV_NODE_NONE )
407         {
408             assert( fs->fmt == CV_STORAGE_FORMAT_XML );
409             CV_PARSE_ERROR( "Sequence element should not have name (use <_></_>)" );
410         }
411 
412         collection->data.map = cvCreateMap( 0, sizeof(CvFileNodeHash),
413                             sizeof(CvFileMapNode), fs->memstorage, 16 );
414     }
415     else
416     {
417         CvSeq* seq;
418         seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvFileNode), fs->memstorage );
419 
420         // if <collection> contains some scalar element, add it to the newly created collection
421         if( CV_NODE_TYPE(collection->tag) != CV_NODE_NONE )
422             cvSeqPush( seq, collection );
423 
424         collection->data.seq = seq;
425     }
426 
427     collection->tag = tag;
428     cvSetSeqBlockSize( collection->data.seq, 8 );
429 }
430 
431 
432 /*static void
433 icvFSReleaseCollection( CvSeq* seq )
434 {
435     if( seq )
436     {
437         int is_map = CV_IS_SET(seq);
438         CvSeqReader reader;
439         int i, total = seq->total;
440         cvStartReadSeq( seq, &reader, 0 );
441 
442         for( i = 0; i < total; i++ )
443         {
444             CvFileNode* node = (CvFileNode*)reader.ptr;
445 
446             if( (!is_map || CV_IS_SET_ELEM( node )) && CV_NODE_IS_COLLECTION(node->tag) )
447             {
448                 if( CV_NODE_IS_USER(node->tag) && node->info && node->data.obj.decoded )
449                     cvRelease( (void**)&node->data.obj.decoded );
450                 if( !CV_NODE_SEQ_IS_SIMPLE( node->data.seq ))
451                     icvFSReleaseCollection( node->data.seq );
452             }
453             CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
454         }
455     }
456 }*/
457 
458 
459 static char*
icvFSDoResize(CvFileStorage * fs,char * ptr,int len)460 icvFSDoResize( CvFileStorage* fs, char* ptr, int len )
461 {
462     char* new_ptr = 0;
463     int written_len = (int)(ptr - fs->buffer_start);
464     int new_size = (int)((fs->buffer_end - fs->buffer_start)*3/2);
465     new_size = MAX( written_len + len, new_size );
466     new_ptr = (char*)cvAlloc( new_size + 256 );
467     fs->buffer = new_ptr + (fs->buffer - fs->buffer_start);
468     if( written_len > 0 )
469         memcpy( new_ptr, fs->buffer_start, written_len );
470     fs->buffer_start = new_ptr;
471     fs->buffer_end = fs->buffer_start + new_size;
472     new_ptr += written_len;
473     return new_ptr;
474 }
475 
476 
icvFSResizeWriteBuffer(CvFileStorage * fs,char * ptr,int len)477 inline char* icvFSResizeWriteBuffer( CvFileStorage* fs, char* ptr, int len )
478 {
479     return ptr + len < fs->buffer_end ? ptr : icvFSDoResize( fs, ptr, len );
480 }
481 
482 
483 static char*
icvFSFlush(CvFileStorage * fs)484 icvFSFlush( CvFileStorage* fs )
485 {
486     char* ptr = fs->buffer;
487     int indent;
488 
489     if( ptr > fs->buffer_start + fs->space )
490     {
491         ptr[0] = '\n';
492         ptr[1] = '\0';
493         icvPuts( fs, fs->buffer_start );
494         fs->buffer = fs->buffer_start;
495     }
496 
497     indent = fs->struct_indent;
498 
499     if( fs->space != indent )
500     {
501         if( fs->space < indent )
502             memset( fs->buffer_start + fs->space, ' ', indent - fs->space );
503         fs->space = indent;
504     }
505 
506     ptr = fs->buffer = fs->buffer_start + fs->space;
507 
508     return ptr;
509 }
510 
511 
512 static void
icvClose(CvFileStorage * fs,cv::String * out)513 icvClose( CvFileStorage* fs, cv::String* out )
514 {
515     if( out )
516         out->clear();
517 
518     if( !fs )
519         CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" );
520 
521     if( fs->is_opened )
522     {
523         if( fs->write_mode && (fs->file || fs->gzfile || fs->outbuf) )
524         {
525             if( fs->write_stack )
526             {
527                 while( fs->write_stack->total > 0 )
528                     cvEndWriteStruct(fs);
529             }
530             icvFSFlush(fs);
531             if( fs->fmt == CV_STORAGE_FORMAT_XML )
532                 icvPuts( fs, "</opencv_storage>\n" );
533         }
534 
535         icvCloseFile(fs);
536     }
537 
538     if( fs->outbuf && out )
539     {
540         *out = cv::String(fs->outbuf->begin(), fs->outbuf->end());
541     }
542 }
543 
544 
545 /* closes file storage and deallocates buffers */
546 CV_IMPL  void
cvReleaseFileStorage(CvFileStorage ** p_fs)547 cvReleaseFileStorage( CvFileStorage** p_fs )
548 {
549     if( !p_fs )
550         CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" );
551 
552     if( *p_fs )
553     {
554         CvFileStorage* fs = *p_fs;
555         *p_fs = 0;
556 
557         icvClose(fs, 0);
558 
559         cvReleaseMemStorage( &fs->strstorage );
560         cvFree( &fs->buffer_start );
561         cvReleaseMemStorage( &fs->memstorage );
562 
563         if( fs->outbuf )
564             delete fs->outbuf;
565 
566         memset( fs, 0, sizeof(*fs) );
567         cvFree( &fs );
568     }
569 }
570 
571 
572 #define CV_HASHVAL_SCALE 33
573 
574 CV_IMPL CvStringHashNode*
cvGetHashedKey(CvFileStorage * fs,const char * str,int len,int create_missing)575 cvGetHashedKey( CvFileStorage* fs, const char* str, int len, int create_missing )
576 {
577     CvStringHashNode* node = 0;
578     unsigned hashval = 0;
579     int i, tab_size;
580 
581     if( !fs )
582         return 0;
583 
584     CvStringHash* map = fs->str_hash;
585 
586     if( len < 0 )
587     {
588         for( i = 0; str[i] != '\0'; i++ )
589             hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
590         len = i;
591     }
592     else for( i = 0; i < len; i++ )
593         hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
594 
595     hashval &= INT_MAX;
596     tab_size = map->tab_size;
597     if( (tab_size & (tab_size - 1)) == 0 )
598         i = (int)(hashval & (tab_size - 1));
599     else
600         i = (int)(hashval % tab_size);
601 
602     for( node = (CvStringHashNode*)(map->table[i]); node != 0; node = node->next )
603     {
604         if( node->hashval == hashval &&
605             node->str.len == len &&
606             memcmp( node->str.ptr, str, len ) == 0 )
607             break;
608     }
609 
610     if( !node && create_missing )
611     {
612         node = (CvStringHashNode*)cvSetNew( (CvSet*)map );
613         node->hashval = hashval;
614         node->str = cvMemStorageAllocString( map->storage, str, len );
615         node->next = (CvStringHashNode*)(map->table[i]);
616         map->table[i] = node;
617     }
618 
619     return node;
620 }
621 
622 
623 CV_IMPL CvFileNode*
cvGetFileNode(CvFileStorage * fs,CvFileNode * _map_node,const CvStringHashNode * key,int create_missing)624 cvGetFileNode( CvFileStorage* fs, CvFileNode* _map_node,
625                const CvStringHashNode* key,
626                int create_missing )
627 {
628     CvFileNode* value = 0;
629     int k = 0, attempts = 1;
630 
631     if( !fs )
632         return 0;
633 
634     CV_CHECK_FILE_STORAGE(fs);
635 
636     if( !key )
637         CV_Error( CV_StsNullPtr, "Null key element" );
638 
639     if( _map_node )
640     {
641         if( !fs->roots )
642             return 0;
643         attempts = fs->roots->total;
644     }
645 
646     for( k = 0; k < attempts; k++ )
647     {
648         int i, tab_size;
649         CvFileNode* map_node = _map_node;
650         CvFileMapNode* another;
651         CvFileNodeHash* map;
652 
653         if( !map_node )
654             map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
655 
656         if( !CV_NODE_IS_MAP(map_node->tag) )
657         {
658             if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
659                 CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
660                 CV_Error( CV_StsError, "The node is neither a map nor an empty collection" );
661             return 0;
662         }
663 
664         map = map_node->data.map;
665         tab_size = map->tab_size;
666 
667         if( (tab_size & (tab_size - 1)) == 0 )
668             i = (int)(key->hashval & (tab_size - 1));
669         else
670             i = (int)(key->hashval % tab_size);
671 
672         for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
673             if( another->key == key )
674             {
675                 if( !create_missing )
676                 {
677                     value = &another->value;
678                     return value;
679                 }
680                 CV_PARSE_ERROR( "Duplicated key" );
681             }
682 
683         if( k == attempts - 1 && create_missing )
684         {
685             CvFileMapNode* node = (CvFileMapNode*)cvSetNew( (CvSet*)map );
686             node->key = key;
687 
688             node->next = (CvFileMapNode*)(map->table[i]);
689             map->table[i] = node;
690             value = (CvFileNode*)node;
691         }
692     }
693 
694     return value;
695 }
696 
697 
698 CV_IMPL CvFileNode*
cvGetFileNodeByName(const CvFileStorage * fs,const CvFileNode * _map_node,const char * str)699 cvGetFileNodeByName( const CvFileStorage* fs, const CvFileNode* _map_node, const char* str )
700 {
701     CvFileNode* value = 0;
702     int i, len, tab_size;
703     unsigned hashval = 0;
704     int k = 0, attempts = 1;
705 
706     if( !fs )
707         return 0;
708 
709     CV_CHECK_FILE_STORAGE(fs);
710 
711     if( !str )
712         CV_Error( CV_StsNullPtr, "Null element name" );
713 
714     for( i = 0; str[i] != '\0'; i++ )
715         hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
716     hashval &= INT_MAX;
717     len = i;
718 
719     if( !_map_node )
720     {
721         if( !fs->roots )
722             return 0;
723         attempts = fs->roots->total;
724     }
725 
726     for( k = 0; k < attempts; k++ )
727     {
728         CvFileNodeHash* map;
729         const CvFileNode* map_node = _map_node;
730         CvFileMapNode* another;
731 
732         if( !map_node )
733             map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
734 
735         if( !CV_NODE_IS_MAP(map_node->tag) )
736         {
737             if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
738                 CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
739                 CV_Error( CV_StsError, "The node is neither a map nor an empty collection" );
740             return 0;
741         }
742 
743         map = map_node->data.map;
744         tab_size = map->tab_size;
745 
746         if( (tab_size & (tab_size - 1)) == 0 )
747             i = (int)(hashval & (tab_size - 1));
748         else
749             i = (int)(hashval % tab_size);
750 
751         for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
752         {
753             const CvStringHashNode* key = another->key;
754 
755             if( key->hashval == hashval &&
756                 key->str.len == len &&
757                 memcmp( key->str.ptr, str, len ) == 0 )
758             {
759                 value = &another->value;
760                 return value;
761             }
762         }
763     }
764 
765     return value;
766 }
767 
768 
769 CV_IMPL CvFileNode*
cvGetRootFileNode(const CvFileStorage * fs,int stream_index)770 cvGetRootFileNode( const CvFileStorage* fs, int stream_index )
771 {
772     CV_CHECK_FILE_STORAGE(fs);
773 
774     if( !fs->roots || (unsigned)stream_index >= (unsigned)fs->roots->total )
775         return 0;
776 
777     return (CvFileNode*)cvGetSeqElem( fs->roots, stream_index );
778 }
779 
780 
781 /* returns the sequence element by its index */
782 /*CV_IMPL CvFileNode*
783 cvGetFileNodeFromSeq( CvFileStorage* fs,
784                       CvFileNode* seq_node, int index )
785 {
786     CvFileNode* value = 0;
787     CvSeq* seq;
788 
789     if( !seq_node )
790         seq = fs->roots;
791     else if( !CV_NODE_IS_SEQ(seq_node->tag) )
792     {
793         if( CV_NODE_IS_MAP(seq_node->tag) )
794             CV_Error( CV_StsError, "The node is map. Use cvGetFileNodeFromMap()." );
795         if( CV_NODE_TYPE(seq_node->tag) == CV_NODE_NONE )
796             CV_Error( CV_StsError, "The node is an empty object (None)." );
797         if( index != 0 && index != -1 )
798             CV_Error( CV_StsOutOfRange, "" );
799         value = seq_node;
800         EXIT;
801     }
802     else
803         seq = seq_node->data.seq;
804 
805     if( !seq )
806         CV_Error( CV_StsNullPtr, "The file storage is empty" );
807 
808     value = (CvFileNode*)cvGetSeqElem( seq, index, 0 );
809 
810 
811 
812     return value;
813 }*/
814 
815 
816 static char*
icvDoubleToString(char * buf,double value)817 icvDoubleToString( char* buf, double value )
818 {
819     Cv64suf val;
820     unsigned ieee754_hi;
821 
822     val.f = value;
823     ieee754_hi = (unsigned)(val.u >> 32);
824 
825     if( (ieee754_hi & 0x7ff00000) != 0x7ff00000 )
826     {
827         int ivalue = cvRound(value);
828         if( ivalue == value )
829             sprintf( buf, "%d.", ivalue );
830         else
831         {
832             static const char* fmt = "%.16e";
833             char* ptr = buf;
834             sprintf( buf, fmt, value );
835             if( *ptr == '+' || *ptr == '-' )
836                 ptr++;
837             for( ; cv_isdigit(*ptr); ptr++ )
838                 ;
839             if( *ptr == ',' )
840                 *ptr = '.';
841         }
842     }
843     else
844     {
845         unsigned ieee754_lo = (unsigned)val.u;
846         if( (ieee754_hi & 0x7fffffff) + (ieee754_lo != 0) > 0x7ff00000 )
847             strcpy( buf, ".Nan" );
848         else
849             strcpy( buf, (int)ieee754_hi < 0 ? "-.Inf" : ".Inf" );
850     }
851 
852     return buf;
853 }
854 
855 
856 static char*
icvFloatToString(char * buf,float value)857 icvFloatToString( char* buf, float value )
858 {
859     Cv32suf val;
860     unsigned ieee754;
861     val.f = value;
862     ieee754 = val.u;
863 
864     if( (ieee754 & 0x7f800000) != 0x7f800000 )
865     {
866         int ivalue = cvRound(value);
867         if( ivalue == value )
868             sprintf( buf, "%d.", ivalue );
869         else
870         {
871             static const char* fmt = "%.8e";
872             char* ptr = buf;
873             sprintf( buf, fmt, value );
874             if( *ptr == '+' || *ptr == '-' )
875                 ptr++;
876             for( ; cv_isdigit(*ptr); ptr++ )
877                 ;
878             if( *ptr == ',' )
879                 *ptr = '.';
880         }
881     }
882     else
883     {
884         if( (ieee754 & 0x7fffffff) != 0x7f800000 )
885             strcpy( buf, ".Nan" );
886         else
887             strcpy( buf, (int)ieee754 < 0 ? "-.Inf" : ".Inf" );
888     }
889 
890     return buf;
891 }
892 
893 
894 static void
icvProcessSpecialDouble(CvFileStorage * fs,char * buf,double * value,char ** endptr)895 icvProcessSpecialDouble( CvFileStorage* fs, char* buf, double* value, char** endptr )
896 {
897     char c = buf[0];
898     int inf_hi = 0x7ff00000;
899 
900     if( c == '-' || c == '+' )
901     {
902         inf_hi = c == '-' ? 0xfff00000 : 0x7ff00000;
903         c = *++buf;
904     }
905 
906     if( c != '.' )
907         CV_PARSE_ERROR( "Bad format of floating-point constant" );
908 
909     union{double d; uint64 i;} v;
910     v.d = 0.;
911     if( toupper(buf[1]) == 'I' && toupper(buf[2]) == 'N' && toupper(buf[3]) == 'F' )
912         v.i = (uint64)inf_hi << 32;
913     else if( toupper(buf[1]) == 'N' && toupper(buf[2]) == 'A' && toupper(buf[3]) == 'N' )
914         v.i = (uint64)-1;
915     else
916         CV_PARSE_ERROR( "Bad format of floating-point constant" );
917     *value = v.d;
918 
919     *endptr = buf + 4;
920 }
921 
922 
icv_strtod(CvFileStorage * fs,char * ptr,char ** endptr)923 static double icv_strtod( CvFileStorage* fs, char* ptr, char** endptr )
924 {
925     double fval = strtod( ptr, endptr );
926     if( **endptr == '.' )
927     {
928         char* dot_pos = *endptr;
929         *dot_pos = ',';
930         double fval2 = strtod( ptr, endptr );
931         *dot_pos = '.';
932         if( *endptr > dot_pos )
933             fval = fval2;
934         else
935             *endptr = dot_pos;
936     }
937 
938     if( *endptr == ptr || cv_isalpha(**endptr) )
939         icvProcessSpecialDouble( fs, ptr, &fval, endptr );
940 
941     return fval;
942 }
943 
944 
945 /****************************************************************************************\
946 *                                       YAML Parser                                      *
947 \****************************************************************************************/
948 
949 static char*
icvYMLSkipSpaces(CvFileStorage * fs,char * ptr,int min_indent,int max_comment_indent)950 icvYMLSkipSpaces( CvFileStorage* fs, char* ptr, int min_indent, int max_comment_indent )
951 {
952     for(;;)
953     {
954         while( *ptr == ' ' )
955             ptr++;
956         if( *ptr == '#' )
957         {
958             if( ptr - fs->buffer_start > max_comment_indent )
959                 return ptr;
960             *ptr = '\0';
961         }
962         else if( cv_isprint(*ptr) )
963         {
964             if( ptr - fs->buffer_start < min_indent )
965                 CV_PARSE_ERROR( "Incorrect indentation" );
966             break;
967         }
968         else if( *ptr == '\0' || *ptr == '\n' || *ptr == '\r' )
969         {
970             int max_size = (int)(fs->buffer_end - fs->buffer_start);
971             ptr = icvGets( fs, fs->buffer_start, max_size );
972             if( !ptr )
973             {
974                 // emulate end of stream
975                 ptr = fs->buffer_start;
976                 ptr[0] = ptr[1] = ptr[2] = '.';
977                 ptr[3] = '\0';
978                 fs->dummy_eof = 1;
979                 break;
980             }
981             else
982             {
983                 int l = (int)strlen(ptr);
984                 if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) )
985                     CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
986             }
987 
988             fs->lineno++;
989         }
990         else
991             CV_PARSE_ERROR( *ptr == '\t' ? "Tabs are prohibited in YAML!" : "Invalid character" );
992     }
993 
994     return ptr;
995 }
996 
997 
998 static char*
icvYMLParseKey(CvFileStorage * fs,char * ptr,CvFileNode * map_node,CvFileNode ** value_placeholder)999 icvYMLParseKey( CvFileStorage* fs, char* ptr,
1000                 CvFileNode* map_node, CvFileNode** value_placeholder )
1001 {
1002     char c;
1003     char *endptr = ptr - 1, *saveptr;
1004     CvStringHashNode* str_hash_node;
1005 
1006     if( *ptr == '-' )
1007         CV_PARSE_ERROR( "Key may not start with \'-\'" );
1008 
1009     do c = *++endptr;
1010     while( cv_isprint(c) && c != ':' );
1011 
1012     if( c != ':' )
1013         CV_PARSE_ERROR( "Missing \':\'" );
1014 
1015     saveptr = endptr + 1;
1016     do c = *--endptr;
1017     while( c == ' ' );
1018 
1019     ++endptr;
1020     if( endptr == ptr )
1021         CV_PARSE_ERROR( "An empty key" );
1022 
1023     str_hash_node = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 );
1024     *value_placeholder = cvGetFileNode( fs, map_node, str_hash_node, 1 );
1025     ptr = saveptr;
1026 
1027     return ptr;
1028 }
1029 
1030 
1031 static char*
icvYMLParseValue(CvFileStorage * fs,char * ptr,CvFileNode * node,int parent_flags,int min_indent)1032 icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
1033                   int parent_flags, int min_indent )
1034 {
1035     char buf[CV_FS_MAX_LEN + 1024];
1036     char* endptr = 0;
1037     char c = ptr[0], d = ptr[1];
1038     int is_parent_flow = CV_NODE_IS_FLOW(parent_flags);
1039     int value_type = CV_NODE_NONE;
1040     int len;
1041 
1042     memset( node, 0, sizeof(*node) );
1043 
1044     if( c == '!' ) // handle explicit type specification
1045     {
1046         if( d == '!' || d == '^' )
1047         {
1048             ptr++;
1049             value_type |= CV_NODE_USER;
1050         }
1051 
1052         endptr = ptr++;
1053         do d = *++endptr;
1054         while( cv_isprint(d) && d != ' ' );
1055         len = (int)(endptr - ptr);
1056         if( len == 0 )
1057             CV_PARSE_ERROR( "Empty type name" );
1058         d = *endptr;
1059         *endptr = '\0';
1060 
1061         if( len == 3 && !CV_NODE_IS_USER(value_type) )
1062         {
1063             if( memcmp( ptr, "str", 3 ) == 0 )
1064                 value_type = CV_NODE_STRING;
1065             else if( memcmp( ptr, "int", 3 ) == 0 )
1066                 value_type = CV_NODE_INT;
1067             else if( memcmp( ptr, "seq", 3 ) == 0 )
1068                 value_type = CV_NODE_SEQ;
1069             else if( memcmp( ptr, "map", 3 ) == 0 )
1070                 value_type = CV_NODE_MAP;
1071         }
1072         else if( len == 5 && !CV_NODE_IS_USER(value_type) )
1073         {
1074             if( memcmp( ptr, "float", 5 ) == 0 )
1075                 value_type = CV_NODE_REAL;
1076         }
1077         else if( CV_NODE_IS_USER(value_type) )
1078         {
1079             node->info = cvFindType( ptr );
1080             if( !node->info )
1081                 node->tag &= ~CV_NODE_USER;
1082         }
1083 
1084         *endptr = d;
1085         ptr = icvYMLSkipSpaces( fs, endptr, min_indent, INT_MAX );
1086 
1087         c = *ptr;
1088 
1089         if( !CV_NODE_IS_USER(value_type) )
1090         {
1091             if( value_type == CV_NODE_STRING && c != '\'' && c != '\"' )
1092                 goto force_string;
1093             if( value_type == CV_NODE_INT )
1094                 goto force_int;
1095             if( value_type == CV_NODE_REAL )
1096                 goto force_real;
1097         }
1098     }
1099 
1100     if( cv_isdigit(c) ||
1101         ((c == '-' || c == '+') && (cv_isdigit(d) || d == '.')) ||
1102         (c == '.' && cv_isalnum(d))) // a number
1103     {
1104         double fval;
1105         int ival;
1106         endptr = ptr + (c == '-' || c == '+');
1107         while( cv_isdigit(*endptr) )
1108             endptr++;
1109         if( *endptr == '.' || *endptr == 'e' )
1110         {
1111 force_real:
1112             fval = icv_strtod( fs, ptr, &endptr );
1113             /*if( endptr == ptr || cv_isalpha(*endptr) )
1114                 icvProcessSpecialDouble( fs, endptr, &fval, &endptr ));*/
1115 
1116             node->tag = CV_NODE_REAL;
1117             node->data.f = fval;
1118         }
1119         else
1120         {
1121 force_int:
1122             ival = (int)strtol( ptr, &endptr, 0 );
1123             node->tag = CV_NODE_INT;
1124             node->data.i = ival;
1125         }
1126 
1127         if( !endptr || endptr == ptr )
1128             CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
1129 
1130         ptr = endptr;
1131     }
1132     else if( c == '\'' || c == '\"' ) // an explicit string
1133     {
1134         node->tag = CV_NODE_STRING;
1135         if( c == '\'' )
1136             for( len = 0; len < CV_FS_MAX_LEN; )
1137             {
1138                 c = *++ptr;
1139                 if( cv_isalnum(c) || (c != '\'' && cv_isprint(c)))
1140                     buf[len++] = c;
1141                 else if( c == '\'' )
1142                 {
1143                     c = *++ptr;
1144                     if( c != '\'' )
1145                         break;
1146                     buf[len++] = c;
1147                 }
1148                 else
1149                     CV_PARSE_ERROR( "Invalid character" );
1150             }
1151         else
1152             for( len = 0; len < CV_FS_MAX_LEN; )
1153             {
1154                 c = *++ptr;
1155                 if( cv_isalnum(c) || (c != '\\' && c != '\"' && cv_isprint(c)))
1156                     buf[len++] = c;
1157                 else if( c == '\"' )
1158                 {
1159                     ++ptr;
1160                     break;
1161                 }
1162                 else if( c == '\\' )
1163                 {
1164                     d = *++ptr;
1165                     if( d == '\'' )
1166                         buf[len++] = d;
1167                     else if( d == '\"' || d == '\\' || d == '\'' )
1168                         buf[len++] = d;
1169                     else if( d == 'n' )
1170                         buf[len++] = '\n';
1171                     else if( d == 'r' )
1172                         buf[len++] = '\r';
1173                     else if( d == 't' )
1174                         buf[len++] = '\t';
1175                     else if( d == 'x' || (cv_isdigit(d) && d < '8') )
1176                     {
1177                         int val, is_hex = d == 'x';
1178                         c = ptr[3];
1179                         ptr[3] = '\0';
1180                         val = (int)strtol( ptr + is_hex, &endptr, is_hex ? 8 : 16 );
1181                         ptr[3] = c;
1182                         if( endptr == ptr + is_hex )
1183                             buf[len++] = 'x';
1184                         else
1185                         {
1186                             buf[len++] = (char)val;
1187                             ptr = endptr;
1188                         }
1189                     }
1190                 }
1191                 else
1192                     CV_PARSE_ERROR( "Invalid character" );
1193             }
1194 
1195         if( len >= CV_FS_MAX_LEN )
1196             CV_PARSE_ERROR( "Too long string literal" );
1197 
1198         node->data.str = cvMemStorageAllocString( fs->memstorage, buf, len );
1199     }
1200     else if( c == '[' || c == '{' ) // collection as a flow
1201     {
1202         int new_min_indent = min_indent + !is_parent_flow;
1203         int struct_flags = CV_NODE_FLOW + (c == '{' ? CV_NODE_MAP : CV_NODE_SEQ);
1204         int is_simple = 1;
1205 
1206         icvFSCreateCollection( fs, CV_NODE_TYPE(struct_flags) +
1207                                         (node->info ? CV_NODE_USER : 0), node );
1208 
1209         d = c == '[' ? ']' : '}';
1210 
1211         for( ++ptr ;;)
1212         {
1213             CvFileNode* elem = 0;
1214 
1215             ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX );
1216             if( *ptr == '}' || *ptr == ']' )
1217             {
1218                 if( *ptr != d )
1219                     CV_PARSE_ERROR( "The wrong closing bracket" );
1220                 ptr++;
1221                 break;
1222             }
1223 
1224             if( node->data.seq->total != 0 )
1225             {
1226                 if( *ptr != ',' )
1227                     CV_PARSE_ERROR( "Missing , between the elements" );
1228                 ptr = icvYMLSkipSpaces( fs, ptr + 1, new_min_indent, INT_MAX );
1229             }
1230 
1231             if( CV_NODE_IS_MAP(struct_flags) )
1232             {
1233                 ptr = icvYMLParseKey( fs, ptr, node, &elem );
1234                 ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX );
1235             }
1236             else
1237             {
1238                 if( *ptr == ']' )
1239                     break;
1240                 elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
1241             }
1242             ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, new_min_indent );
1243             if( CV_NODE_IS_MAP(struct_flags) )
1244                 elem->tag |= CV_NODE_NAMED;
1245             is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
1246         }
1247         node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
1248     }
1249     else
1250     {
1251         int indent, struct_flags, is_simple;
1252 
1253         if( is_parent_flow || c != '-' )
1254         {
1255             // implicit (one-line) string or nested block-style collection
1256             if( !is_parent_flow )
1257             {
1258                 if( c == '?' )
1259                     CV_PARSE_ERROR( "Complex keys are not supported" );
1260                 if( c == '|' || c == '>' )
1261                     CV_PARSE_ERROR( "Multi-line text literals are not supported" );
1262             }
1263 
1264 force_string:
1265             endptr = ptr - 1;
1266 
1267             do c = *++endptr;
1268             while( cv_isprint(c) &&
1269                    (!is_parent_flow || (c != ',' && c != '}' && c != ']')) &&
1270                    (is_parent_flow || c != ':' || value_type == CV_NODE_STRING));
1271 
1272             if( endptr == ptr )
1273                 CV_PARSE_ERROR( "Invalid character" );
1274 
1275             if( is_parent_flow || c != ':' )
1276             {
1277                 char* str_end = endptr;
1278                 node->tag = CV_NODE_STRING;
1279                 // strip spaces in the end of string
1280                 do c = *--str_end;
1281                 while( str_end > ptr && c == ' ' );
1282                 str_end++;
1283                 node->data.str = cvMemStorageAllocString( fs->memstorage, ptr, (int)(str_end - ptr) );
1284                 ptr = endptr;
1285                 return ptr;
1286             }
1287             struct_flags = CV_NODE_MAP;
1288         }
1289         else
1290             struct_flags = CV_NODE_SEQ;
1291 
1292         icvFSCreateCollection( fs, struct_flags +
1293                     (node->info ? CV_NODE_USER : 0), node );
1294 
1295         indent = (int)(ptr - fs->buffer_start);
1296         is_simple = 1;
1297 
1298         for(;;)
1299         {
1300             CvFileNode* elem = 0;
1301 
1302             if( CV_NODE_IS_MAP(struct_flags) )
1303             {
1304                 ptr = icvYMLParseKey( fs, ptr, node, &elem );
1305             }
1306             else
1307             {
1308                 c = *ptr++;
1309                 if( c != '-' )
1310                     CV_PARSE_ERROR( "Block sequence elements must be preceded with \'-\'" );
1311 
1312                 elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
1313             }
1314 
1315             ptr = icvYMLSkipSpaces( fs, ptr, indent + 1, INT_MAX );
1316             ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, indent + 1 );
1317             if( CV_NODE_IS_MAP(struct_flags) )
1318                 elem->tag |= CV_NODE_NAMED;
1319             is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
1320 
1321             ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
1322             if( ptr - fs->buffer_start != indent )
1323             {
1324                 if( ptr - fs->buffer_start < indent )
1325                     break;
1326                 else
1327                     CV_PARSE_ERROR( "Incorrect indentation" );
1328             }
1329             if( memcmp( ptr, "...", 3 ) == 0 )
1330                 break;
1331         }
1332 
1333         node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
1334     }
1335 
1336     return ptr;
1337 }
1338 
1339 
1340 static void
icvYMLParse(CvFileStorage * fs)1341 icvYMLParse( CvFileStorage* fs )
1342 {
1343     char* ptr = fs->buffer_start;
1344     int is_first = 1;
1345 
1346     for(;;)
1347     {
1348         // 0. skip leading comments and directives  and ...
1349         // 1. reach the first item
1350         for(;;)
1351         {
1352             ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
1353             if( !ptr )
1354                 return;
1355 
1356             if( *ptr == '%' )
1357             {
1358                 if( memcmp( ptr, "%YAML:", 6 ) == 0 &&
1359                     memcmp( ptr, "%YAML:1.", 8 ) != 0 )
1360                     CV_PARSE_ERROR( "Unsupported YAML version (it must be 1.x)" );
1361                 *ptr = '\0';
1362             }
1363             else if( *ptr == '-' )
1364             {
1365                 if( memcmp(ptr, "---", 3) == 0 )
1366                 {
1367                     ptr += 3;
1368                     break;
1369                 }
1370                 else if( is_first )
1371                     break;
1372             }
1373             else if( cv_isalnum(*ptr) || *ptr=='_')
1374             {
1375                 if( !is_first )
1376                     CV_PARSE_ERROR( "The YAML streams must start with '---', except the first one" );
1377                 break;
1378             }
1379             else if( fs->dummy_eof )
1380                 break;
1381             else
1382                 CV_PARSE_ERROR( "Invalid or unsupported syntax" );
1383         }
1384 
1385         ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
1386         if( memcmp( ptr, "...", 3 ) != 0 )
1387         {
1388             // 2. parse the collection
1389             CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
1390 
1391             ptr = icvYMLParseValue( fs, ptr, root_node, CV_NODE_NONE, 0 );
1392             if( !CV_NODE_IS_COLLECTION(root_node->tag) )
1393                 CV_PARSE_ERROR( "Only collections as YAML streams are supported by this parser" );
1394 
1395             // 3. parse until the end of file or next collection
1396             ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
1397             if( !ptr )
1398                 return;
1399         }
1400 
1401         if( fs->dummy_eof )
1402             break;
1403         ptr += 3;
1404         is_first = 0;
1405     }
1406 }
1407 
1408 
1409 /****************************************************************************************\
1410 *                                       YAML Emitter                                     *
1411 \****************************************************************************************/
1412 
1413 static void
icvYMLWrite(CvFileStorage * fs,const char * key,const char * data)1414 icvYMLWrite( CvFileStorage* fs, const char* key, const char* data )
1415 {
1416     int i, keylen = 0;
1417     int datalen = 0;
1418     int struct_flags;
1419     char* ptr;
1420 
1421     struct_flags = fs->struct_flags;
1422 
1423     if( key && key[0] == '\0' )
1424         key = 0;
1425 
1426     if( CV_NODE_IS_COLLECTION(struct_flags) )
1427     {
1428         if( (CV_NODE_IS_MAP(struct_flags) ^ (key != 0)) )
1429             CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
1430                                     "or add element with key to sequence" );
1431     }
1432     else
1433     {
1434         fs->is_first = 0;
1435         struct_flags = CV_NODE_EMPTY | (key ? CV_NODE_MAP : CV_NODE_SEQ);
1436     }
1437 
1438     if( key )
1439     {
1440         keylen = (int)strlen(key);
1441         if( keylen == 0 )
1442             CV_Error( CV_StsBadArg, "The key is an empty" );
1443 
1444         if( keylen > CV_FS_MAX_LEN )
1445             CV_Error( CV_StsBadArg, "The key is too long" );
1446     }
1447 
1448     if( data )
1449         datalen = (int)strlen(data);
1450 
1451     if( CV_NODE_IS_FLOW(struct_flags) )
1452     {
1453         int new_offset;
1454         ptr = fs->buffer;
1455         if( !CV_NODE_IS_EMPTY(struct_flags) )
1456             *ptr++ = ',';
1457         new_offset = (int)(ptr - fs->buffer_start) + keylen + datalen;
1458         if( new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10 )
1459         {
1460             fs->buffer = ptr;
1461             ptr = icvFSFlush(fs);
1462         }
1463         else
1464             *ptr++ = ' ';
1465     }
1466     else
1467     {
1468         ptr = icvFSFlush(fs);
1469         if( !CV_NODE_IS_MAP(struct_flags) )
1470         {
1471             *ptr++ = '-';
1472             if( data )
1473                 *ptr++ = ' ';
1474         }
1475     }
1476 
1477     if( key )
1478     {
1479         if( !cv_isalpha(key[0]) && key[0] != '_' )
1480             CV_Error( CV_StsBadArg, "Key must start with a letter or _" );
1481 
1482         ptr = icvFSResizeWriteBuffer( fs, ptr, keylen );
1483 
1484         for( i = 0; i < keylen; i++ )
1485         {
1486             char c = key[i];
1487 
1488             ptr[i] = c;
1489             if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
1490                 CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
1491         }
1492 
1493         ptr += keylen;
1494         *ptr++ = ':';
1495         if( !CV_NODE_IS_FLOW(struct_flags) && data )
1496             *ptr++ = ' ';
1497     }
1498 
1499     if( data )
1500     {
1501         ptr = icvFSResizeWriteBuffer( fs, ptr, datalen );
1502         memcpy( ptr, data, datalen );
1503         ptr += datalen;
1504     }
1505 
1506     fs->buffer = ptr;
1507     fs->struct_flags = struct_flags & ~CV_NODE_EMPTY;
1508 }
1509 
1510 
1511 static void
1512 icvYMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
1513                         const char* type_name CV_DEFAULT(0))
1514 {
1515     int parent_flags;
1516     char buf[CV_FS_MAX_LEN + 1024];
1517     const char* data = 0;
1518 
1519     struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
1520     if( !CV_NODE_IS_COLLECTION(struct_flags))
1521         CV_Error( CV_StsBadArg,
1522         "Some collection type - CV_NODE_SEQ or CV_NODE_MAP, must be specified" );
1523 
1524     if( CV_NODE_IS_FLOW(struct_flags) )
1525     {
1526         char c = CV_NODE_IS_MAP(struct_flags) ? '{' : '[';
1527         struct_flags |= CV_NODE_FLOW;
1528 
1529         if( type_name )
1530             sprintf( buf, "!!%s %c", type_name, c );
1531         else
1532         {
1533             buf[0] = c;
1534             buf[1] = '\0';
1535         }
1536         data = buf;
1537     }
1538     else if( type_name )
1539     {
1540         sprintf( buf, "!!%s", type_name );
1541         data = buf;
1542     }
1543 
1544     icvYMLWrite( fs, key, data );
1545 
1546     parent_flags = fs->struct_flags;
1547     cvSeqPush( fs->write_stack, &parent_flags );
1548     fs->struct_flags = struct_flags;
1549 
1550     if( !CV_NODE_IS_FLOW(parent_flags) )
1551         fs->struct_indent += CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags);
1552 }
1553 
1554 
1555 static void
icvYMLEndWriteStruct(CvFileStorage * fs)1556 icvYMLEndWriteStruct( CvFileStorage* fs )
1557 {
1558     int parent_flags = 0, struct_flags;
1559     char* ptr;
1560 
1561     struct_flags = fs->struct_flags;
1562     if( fs->write_stack->total == 0 )
1563         CV_Error( CV_StsError, "EndWriteStruct w/o matching StartWriteStruct" );
1564 
1565     cvSeqPop( fs->write_stack, &parent_flags );
1566 
1567     if( CV_NODE_IS_FLOW(struct_flags) )
1568     {
1569         ptr = fs->buffer;
1570         if( ptr > fs->buffer_start + fs->struct_indent && !CV_NODE_IS_EMPTY(struct_flags) )
1571             *ptr++ = ' ';
1572         *ptr++ = CV_NODE_IS_MAP(struct_flags) ? '}' : ']';
1573         fs->buffer = ptr;
1574     }
1575     else if( CV_NODE_IS_EMPTY(struct_flags) )
1576     {
1577         ptr = icvFSFlush(fs);
1578         memcpy( ptr, CV_NODE_IS_MAP(struct_flags) ? "{}" : "[]", 2 );
1579         fs->buffer = ptr + 2;
1580     }
1581 
1582     if( !CV_NODE_IS_FLOW(parent_flags) )
1583         fs->struct_indent -= CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags);
1584     assert( fs->struct_indent >= 0 );
1585 
1586     fs->struct_flags = parent_flags;
1587 }
1588 
1589 
1590 static void
icvYMLStartNextStream(CvFileStorage * fs)1591 icvYMLStartNextStream( CvFileStorage* fs )
1592 {
1593     if( !fs->is_first )
1594     {
1595         while( fs->write_stack->total > 0 )
1596             icvYMLEndWriteStruct(fs);
1597 
1598         fs->struct_indent = 0;
1599         icvFSFlush(fs);
1600         icvPuts( fs, "...\n" );
1601         icvPuts( fs, "---\n" );
1602         fs->buffer = fs->buffer_start;
1603     }
1604 }
1605 
1606 
1607 static void
icvYMLWriteInt(CvFileStorage * fs,const char * key,int value)1608 icvYMLWriteInt( CvFileStorage* fs, const char* key, int value )
1609 {
1610     char buf[128];
1611     icvYMLWrite( fs, key, icv_itoa( value, buf, 10 ));
1612 }
1613 
1614 
1615 static void
icvYMLWriteReal(CvFileStorage * fs,const char * key,double value)1616 icvYMLWriteReal( CvFileStorage* fs, const char* key, double value )
1617 {
1618     char buf[128];
1619     icvYMLWrite( fs, key, icvDoubleToString( buf, value ));
1620 }
1621 
1622 
1623 static void
1624 icvYMLWriteString( CvFileStorage* fs, const char* key,
1625                    const char* str, int quote CV_DEFAULT(0))
1626 {
1627     char buf[CV_FS_MAX_LEN*4+16];
1628     char* data = (char*)str;
1629     int i, len;
1630 
1631     if( !str )
1632         CV_Error( CV_StsNullPtr, "Null string pointer" );
1633 
1634     len = (int)strlen(str);
1635     if( len > CV_FS_MAX_LEN )
1636         CV_Error( CV_StsBadArg, "The written string is too long" );
1637 
1638     if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
1639     {
1640         int need_quote = quote || len == 0;
1641         data = buf;
1642         *data++ = '\"';
1643         for( i = 0; i < len; i++ )
1644         {
1645             char c = str[i];
1646 
1647             if( !need_quote && !cv_isalnum(c) && c != '_' && c != ' ' && c != '-' &&
1648                 c != '(' && c != ')' && c != '/' && c != '+' && c != ';' )
1649                 need_quote = 1;
1650 
1651             if( !cv_isalnum(c) && (!cv_isprint(c) || c == '\\' || c == '\'' || c == '\"') )
1652             {
1653                 *data++ = '\\';
1654                 if( cv_isprint(c) )
1655                     *data++ = c;
1656                 else if( c == '\n' )
1657                     *data++ = 'n';
1658                 else if( c == '\r' )
1659                     *data++ = 'r';
1660                 else if( c == '\t' )
1661                     *data++ = 't';
1662                 else
1663                 {
1664                     sprintf( data, "x%02x", c );
1665                     data += 3;
1666                 }
1667             }
1668             else
1669                 *data++ = c;
1670         }
1671         if( !need_quote && (cv_isdigit(str[0]) ||
1672             str[0] == '+' || str[0] == '-' || str[0] == '.' ))
1673             need_quote = 1;
1674 
1675         if( need_quote )
1676             *data++ = '\"';
1677         *data++ = '\0';
1678         data = buf + !need_quote;
1679     }
1680 
1681     icvYMLWrite( fs, key, data );
1682 }
1683 
1684 
1685 static void
icvYMLWriteComment(CvFileStorage * fs,const char * comment,int eol_comment)1686 icvYMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
1687 {
1688     int len; //, indent;
1689     int multiline;
1690     const char* eol;
1691     char* ptr;
1692 
1693     if( !comment )
1694         CV_Error( CV_StsNullPtr, "Null comment" );
1695 
1696     len = (int)strlen(comment);
1697     eol = strchr(comment, '\n');
1698     multiline = eol != 0;
1699     ptr = fs->buffer;
1700 
1701     if( !eol_comment || multiline ||
1702         fs->buffer_end - ptr < len || ptr == fs->buffer_start )
1703         ptr = icvFSFlush( fs );
1704     else
1705         *ptr++ = ' ';
1706 
1707     while( comment )
1708     {
1709         *ptr++ = '#';
1710         *ptr++ = ' ';
1711         if( eol )
1712         {
1713             ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 );
1714             memcpy( ptr, comment, eol - comment + 1 );
1715             fs->buffer = ptr + (eol - comment);
1716             comment = eol + 1;
1717             eol = strchr( comment, '\n' );
1718         }
1719         else
1720         {
1721             len = (int)strlen(comment);
1722             ptr = icvFSResizeWriteBuffer( fs, ptr, len );
1723             memcpy( ptr, comment, len );
1724             fs->buffer = ptr + len;
1725             comment = 0;
1726         }
1727         ptr = icvFSFlush( fs );
1728     }
1729 }
1730 
1731 
1732 /****************************************************************************************\
1733 *                                       XML Parser                                       *
1734 \****************************************************************************************/
1735 
1736 #define CV_XML_INSIDE_COMMENT 1
1737 #define CV_XML_INSIDE_TAG 2
1738 #define CV_XML_INSIDE_DIRECTIVE 3
1739 
1740 static char*
icvXMLSkipSpaces(CvFileStorage * fs,char * ptr,int mode)1741 icvXMLSkipSpaces( CvFileStorage* fs, char* ptr, int mode )
1742 {
1743     int level = 0;
1744 
1745     for(;;)
1746     {
1747         char c;
1748         ptr--;
1749 
1750         if( mode == CV_XML_INSIDE_COMMENT )
1751         {
1752             do c = *++ptr;
1753             while( cv_isprint_or_tab(c) && (c != '-' || ptr[1] != '-' || ptr[2] != '>') );
1754 
1755             if( c == '-' )
1756             {
1757                 assert( ptr[1] == '-' && ptr[2] == '>' );
1758                 mode = 0;
1759                 ptr += 3;
1760             }
1761         }
1762         else if( mode == CV_XML_INSIDE_DIRECTIVE )
1763         {
1764             // !!!NOTE!!! This is not quite correct, but should work in most cases
1765             do
1766             {
1767                 c = *++ptr;
1768                 level += c == '<';
1769                 level -= c == '>';
1770                 if( level < 0 )
1771                     return ptr;
1772             } while( cv_isprint_or_tab(c) );
1773         }
1774         else
1775         {
1776             do c = *++ptr;
1777             while( c == ' ' || c == '\t' );
1778 
1779             if( c == '<' && ptr[1] == '!' && ptr[2] == '-' && ptr[3] == '-' )
1780             {
1781                 if( mode != 0 )
1782                     CV_PARSE_ERROR( "Comments are not allowed here" );
1783                 mode = CV_XML_INSIDE_COMMENT;
1784                 ptr += 4;
1785             }
1786             else if( cv_isprint(c) )
1787                 break;
1788         }
1789 
1790         if( !cv_isprint(*ptr) )
1791         {
1792             int max_size = (int)(fs->buffer_end - fs->buffer_start);
1793             if( *ptr != '\0' && *ptr != '\n' && *ptr != '\r' )
1794                 CV_PARSE_ERROR( "Invalid character in the stream" );
1795             ptr = icvGets( fs, fs->buffer_start, max_size );
1796             if( !ptr )
1797             {
1798                 ptr = fs->buffer_start;
1799                 *ptr = '\0';
1800                 fs->dummy_eof = 1;
1801                 break;
1802             }
1803             else
1804             {
1805                 int l = (int)strlen(ptr);
1806                 if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) )
1807                     CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
1808             }
1809             fs->lineno++;
1810         }
1811     }
1812     return ptr;
1813 }
1814 
1815 
1816 static char*
1817 icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
1818                 CvAttrList** _list, int* _tag_type );
1819 
1820 static char*
icvXMLParseValue(CvFileStorage * fs,char * ptr,CvFileNode * node,int value_type CV_DEFAULT (CV_NODE_NONE))1821 icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
1822                   int value_type CV_DEFAULT(CV_NODE_NONE))
1823 {
1824     CvFileNode *elem = node;
1825     int have_space = 1, is_simple = 1;
1826     int is_user_type = CV_NODE_IS_USER(value_type);
1827     memset( node, 0, sizeof(*node) );
1828 
1829     value_type = CV_NODE_TYPE(value_type);
1830 
1831     for(;;)
1832     {
1833         char c = *ptr, d;
1834         char* endptr;
1835 
1836         if( cv_isspace(c) || c == '\0' || (c == '<' && ptr[1] == '!' && ptr[2] == '-') )
1837         {
1838             ptr = icvXMLSkipSpaces( fs, ptr, 0 );
1839             have_space = 1;
1840             c = *ptr;
1841         }
1842 
1843         d = ptr[1];
1844 
1845         if( c =='<' || c == '\0' )
1846         {
1847             CvStringHashNode *key = 0, *key2 = 0;
1848             CvAttrList* list = 0;
1849             CvTypeInfo* info = 0;
1850             int tag_type = 0;
1851             int is_noname = 0;
1852             const char* type_name = 0;
1853             int elem_type = CV_NODE_NONE;
1854 
1855             if( d == '/' || c == '\0' )
1856                 break;
1857 
1858             ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type );
1859 
1860             if( tag_type == CV_XML_DIRECTIVE_TAG )
1861                 CV_PARSE_ERROR( "Directive tags are not allowed here" );
1862             if( tag_type == CV_XML_EMPTY_TAG )
1863                 CV_PARSE_ERROR( "Empty tags are not supported" );
1864 
1865             assert( tag_type == CV_XML_OPENING_TAG );
1866 
1867             type_name = list ? cvAttrValue( list, "type_id" ) : 0;
1868             if( type_name )
1869             {
1870                 if( strcmp( type_name, "str" ) == 0 )
1871                     elem_type = CV_NODE_STRING;
1872                 else if( strcmp( type_name, "map" ) == 0 )
1873                     elem_type = CV_NODE_MAP;
1874                 else if( strcmp( type_name, "seq" ) == 0 )
1875                     elem_type = CV_NODE_SEQ;
1876                 else
1877                 {
1878                     info = cvFindType( type_name );
1879                     if( info )
1880                         elem_type = CV_NODE_USER;
1881                 }
1882             }
1883 
1884             is_noname = key->str.len == 1 && key->str.ptr[0] == '_';
1885             if( !CV_NODE_IS_COLLECTION(node->tag) )
1886             {
1887                 icvFSCreateCollection( fs, is_noname ? CV_NODE_SEQ : CV_NODE_MAP, node );
1888             }
1889             else if( is_noname ^ CV_NODE_IS_SEQ(node->tag) )
1890                 CV_PARSE_ERROR( is_noname ? "Map element should have a name" :
1891                               "Sequence element should not have name (use <_></_>)" );
1892 
1893             if( is_noname )
1894                 elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
1895             else
1896                 elem = cvGetFileNode( fs, node, key, 1 );
1897 
1898             ptr = icvXMLParseValue( fs, ptr, elem, elem_type);
1899             if( !is_noname )
1900                 elem->tag |= CV_NODE_NAMED;
1901             is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
1902             elem->info = info;
1903             ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type );
1904             if( tag_type != CV_XML_CLOSING_TAG || key2 != key )
1905                 CV_PARSE_ERROR( "Mismatched closing tag" );
1906             have_space = 1;
1907         }
1908         else
1909         {
1910             if( !have_space )
1911                 CV_PARSE_ERROR( "There should be space between literals" );
1912 
1913             elem = node;
1914             if( node->tag != CV_NODE_NONE )
1915             {
1916                 if( !CV_NODE_IS_COLLECTION(node->tag) )
1917                     icvFSCreateCollection( fs, CV_NODE_SEQ, node );
1918 
1919                 elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
1920                 elem->info = 0;
1921             }
1922 
1923             if( value_type != CV_NODE_STRING &&
1924                 (cv_isdigit(c) || ((c == '-' || c == '+') &&
1925                 (cv_isdigit(d) || d == '.')) || (c == '.' && cv_isalnum(d))) ) // a number
1926             {
1927                 double fval;
1928                 int ival;
1929                 endptr = ptr + (c == '-' || c == '+');
1930                 while( cv_isdigit(*endptr) )
1931                     endptr++;
1932                 if( *endptr == '.' || *endptr == 'e' )
1933                 {
1934                     fval = icv_strtod( fs, ptr, &endptr );
1935                     /*if( endptr == ptr || cv_isalpha(*endptr) )
1936                         icvProcessSpecialDouble( fs, ptr, &fval, &endptr ));*/
1937                     elem->tag = CV_NODE_REAL;
1938                     elem->data.f = fval;
1939                 }
1940                 else
1941                 {
1942                     ival = (int)strtol( ptr, &endptr, 0 );
1943                     elem->tag = CV_NODE_INT;
1944                     elem->data.i = ival;
1945                 }
1946 
1947                 if( endptr == ptr )
1948                     CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
1949 
1950                 ptr = endptr;
1951             }
1952             else
1953             {
1954                 // string
1955                 char buf[CV_FS_MAX_LEN+16];
1956                 int i = 0, len, is_quoted = 0;
1957                 elem->tag = CV_NODE_STRING;
1958                 if( c == '\"' )
1959                     is_quoted = 1;
1960                 else
1961                     --ptr;
1962 
1963                 for( ;; )
1964                 {
1965                     c = *++ptr;
1966                     if( !cv_isalnum(c) )
1967                     {
1968                         if( c == '\"' )
1969                         {
1970                             if( !is_quoted )
1971                                 CV_PARSE_ERROR( "Literal \" is not allowed within a string. Use &quot;" );
1972                             ++ptr;
1973                             break;
1974                         }
1975                         else if( !cv_isprint(c) || c == '<' || (!is_quoted && cv_isspace(c)))
1976                         {
1977                             if( is_quoted )
1978                                 CV_PARSE_ERROR( "Closing \" is expected" );
1979                             break;
1980                         }
1981                         else if( c == '\'' || c == '>' )
1982                         {
1983                             CV_PARSE_ERROR( "Literal \' or > are not allowed. Use &apos; or &gt;" );
1984                         }
1985                         else if( c == '&' )
1986                         {
1987                             if( *++ptr == '#' )
1988                             {
1989                                 int val, base = 10;
1990                                 ptr++;
1991                                 if( *ptr == 'x' )
1992                                 {
1993                                     base = 16;
1994                                     ptr++;
1995                                 }
1996                                 val = (int)strtol( ptr, &endptr, base );
1997                                 if( (unsigned)val > (unsigned)255 ||
1998                                     !endptr || *endptr != ';' )
1999                                     CV_PARSE_ERROR( "Invalid numeric value in the string" );
2000                                 c = (char)val;
2001                             }
2002                             else
2003                             {
2004                                 endptr = ptr;
2005                                 do c = *++endptr;
2006                                 while( cv_isalnum(c) );
2007                                 if( c != ';' )
2008                                     CV_PARSE_ERROR( "Invalid character in the symbol entity name" );
2009                                 len = (int)(endptr - ptr);
2010                                 if( len == 2 && memcmp( ptr, "lt", len ) == 0 )
2011                                     c = '<';
2012                                 else if( len == 2 && memcmp( ptr, "gt", len ) == 0 )
2013                                     c = '>';
2014                                 else if( len == 3 && memcmp( ptr, "amp", len ) == 0 )
2015                                     c = '&';
2016                                 else if( len == 4 && memcmp( ptr, "apos", len ) == 0 )
2017                                     c = '\'';
2018                                 else if( len == 4 && memcmp( ptr, "quot", len ) == 0 )
2019                                     c = '\"';
2020                                 else
2021                                 {
2022                                     memcpy( buf + i, ptr-1, len + 2 );
2023                                     i += len + 2;
2024                                 }
2025                             }
2026                             ptr = endptr;
2027                         }
2028                     }
2029                     buf[i++] = c;
2030                     if( i >= CV_FS_MAX_LEN )
2031                         CV_PARSE_ERROR( "Too long string literal" );
2032                 }
2033                 elem->data.str = cvMemStorageAllocString( fs->memstorage, buf, i );
2034             }
2035 
2036             if( !CV_NODE_IS_COLLECTION(value_type) && value_type != CV_NODE_NONE )
2037                 break;
2038             have_space = 0;
2039         }
2040     }
2041 
2042     if( (CV_NODE_TYPE(node->tag) == CV_NODE_NONE ||
2043         (CV_NODE_TYPE(node->tag) != value_type &&
2044         !CV_NODE_IS_COLLECTION(node->tag))) &&
2045         CV_NODE_IS_COLLECTION(value_type) )
2046     {
2047         icvFSCreateCollection( fs, CV_NODE_IS_MAP(value_type) ?
2048                                         CV_NODE_MAP : CV_NODE_SEQ, node );
2049     }
2050 
2051     if( value_type != CV_NODE_NONE &&
2052         value_type != CV_NODE_TYPE(node->tag) )
2053         CV_PARSE_ERROR( "The actual type is different from the specified type" );
2054 
2055     if( CV_NODE_IS_COLLECTION(node->tag) && is_simple )
2056             node->data.seq->flags |= CV_NODE_SEQ_SIMPLE;
2057 
2058     node->tag |= is_user_type ? CV_NODE_USER : 0;
2059     return ptr;
2060 }
2061 
2062 
2063 static char*
icvXMLParseTag(CvFileStorage * fs,char * ptr,CvStringHashNode ** _tag,CvAttrList ** _list,int * _tag_type)2064 icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
2065                 CvAttrList** _list, int* _tag_type )
2066 {
2067     int tag_type = 0;
2068     CvStringHashNode* tagname = 0;
2069     CvAttrList *first = 0, *last = 0;
2070     int count = 0, max_count = 4;
2071     int attr_buf_size = (max_count*2 + 1)*sizeof(char*) + sizeof(CvAttrList);
2072     char* endptr;
2073     char c;
2074     int have_space;
2075 
2076     if( *ptr == '\0' )
2077         CV_PARSE_ERROR( "Preliminary end of the stream" );
2078 
2079     if( *ptr != '<' )
2080         CV_PARSE_ERROR( "Tag should start with \'<\'" );
2081 
2082     ptr++;
2083     if( cv_isalnum(*ptr) || *ptr == '_' )
2084         tag_type = CV_XML_OPENING_TAG;
2085     else if( *ptr == '/' )
2086     {
2087         tag_type = CV_XML_CLOSING_TAG;
2088         ptr++;
2089     }
2090     else if( *ptr == '?' )
2091     {
2092         tag_type = CV_XML_HEADER_TAG;
2093         ptr++;
2094     }
2095     else if( *ptr == '!' )
2096     {
2097         tag_type = CV_XML_DIRECTIVE_TAG;
2098         assert( ptr[1] != '-' || ptr[2] != '-' );
2099         ptr++;
2100     }
2101     else
2102         CV_PARSE_ERROR( "Unknown tag type" );
2103 
2104     for(;;)
2105     {
2106         CvStringHashNode* attrname;
2107 
2108         if( !cv_isalpha(*ptr) && *ptr != '_' )
2109             CV_PARSE_ERROR( "Name should start with a letter or underscore" );
2110 
2111         endptr = ptr - 1;
2112         do c = *++endptr;
2113         while( cv_isalnum(c) || c == '_' || c == '-' );
2114 
2115         attrname = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 );
2116         ptr = endptr;
2117 
2118         if( !tagname )
2119             tagname = attrname;
2120         else
2121         {
2122             if( tag_type == CV_XML_CLOSING_TAG )
2123                 CV_PARSE_ERROR( "Closing tag should not contain any attributes" );
2124 
2125             if( !last || count >= max_count )
2126             {
2127                 CvAttrList* chunk;
2128 
2129                 chunk = (CvAttrList*)cvMemStorageAlloc( fs->memstorage, attr_buf_size );
2130                 memset( chunk, 0, attr_buf_size );
2131                 chunk->attr = (const char**)(chunk + 1);
2132                 count = 0;
2133                 if( !last )
2134                     first = last = chunk;
2135                 else
2136                     last = last->next = chunk;
2137             }
2138             last->attr[count*2] = attrname->str.ptr;
2139         }
2140 
2141         if( last )
2142         {
2143             CvFileNode stub;
2144 
2145             if( *ptr != '=' )
2146             {
2147                 ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
2148                 if( *ptr != '=' )
2149                     CV_PARSE_ERROR( "Attribute name should be followed by \'=\'" );
2150             }
2151 
2152             c = *++ptr;
2153             if( c != '\"' && c != '\'' )
2154             {
2155                 ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
2156                 if( *ptr != '\"' && *ptr != '\'' )
2157                     CV_PARSE_ERROR( "Attribute value should be put into single or double quotes" );
2158             }
2159 
2160             ptr = icvXMLParseValue( fs, ptr, &stub, CV_NODE_STRING );
2161             assert( stub.tag == CV_NODE_STRING );
2162             last->attr[count*2+1] = stub.data.str.ptr;
2163             count++;
2164         }
2165 
2166         c = *ptr;
2167         have_space = cv_isspace(c) || c == '\0';
2168 
2169         if( c != '>' )
2170         {
2171             ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
2172             c = *ptr;
2173         }
2174 
2175         if( c == '>' )
2176         {
2177             if( tag_type == CV_XML_HEADER_TAG )
2178                 CV_PARSE_ERROR( "Invalid closing tag for <?xml ..." );
2179             ptr++;
2180             break;
2181         }
2182         else if( c == '?' && tag_type == CV_XML_HEADER_TAG )
2183         {
2184             if( ptr[1] != '>'  )
2185                 CV_PARSE_ERROR( "Invalid closing tag for <?xml ..." );
2186             ptr += 2;
2187             break;
2188         }
2189         else if( c == '/' && ptr[1] == '>' && tag_type == CV_XML_OPENING_TAG )
2190         {
2191             tag_type = CV_XML_EMPTY_TAG;
2192             ptr += 2;
2193             break;
2194         }
2195 
2196         if( !have_space )
2197             CV_PARSE_ERROR( "There should be space between attributes" );
2198     }
2199 
2200     *_tag = tagname;
2201     *_tag_type = tag_type;
2202     *_list = first;
2203 
2204     return ptr;
2205 }
2206 
2207 
2208 static void
icvXMLParse(CvFileStorage * fs)2209 icvXMLParse( CvFileStorage* fs )
2210 {
2211     char* ptr = fs->buffer_start;
2212     CvStringHashNode *key = 0, *key2 = 0;
2213     CvAttrList* list = 0;
2214     int tag_type = 0;
2215 
2216     // CV_XML_INSIDE_TAG is used to prohibit leading comments
2217     ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
2218 
2219     if( memcmp( ptr, "<?xml", 5 ) != 0 )
2220         CV_PARSE_ERROR( "Valid XML should start with \'<?xml ...?>\'" );
2221 
2222     ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type );
2223 
2224     /*{
2225         const char* version = cvAttrValue( list, "version" );
2226         if( version && strncmp( version, "1.", 2 ) != 0 )
2227             CV_Error( CV_StsParseError, "Unsupported version of XML" );
2228     }*/
2229     // we support any 8-bit encoding, so we do not need to check the actual encoding.
2230     // we do not support utf-16, but in the case of utf-16 we will not get here anyway.
2231     /*{
2232         const char* encoding = cvAttrValue( list, "encoding" );
2233         if( encoding && strcmp( encoding, "ASCII" ) != 0 &&
2234             strcmp( encoding, "UTF-8" ) != 0 &&
2235             strcmp( encoding, "utf-8" ) != 0 )
2236             CV_PARSE_ERROR( "Unsupported encoding" );
2237     }*/
2238 
2239     while( *ptr != '\0' )
2240     {
2241         ptr = icvXMLSkipSpaces( fs, ptr, 0 );
2242 
2243         if( *ptr != '\0' )
2244         {
2245             CvFileNode* root_node;
2246             ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type );
2247             if( tag_type != CV_XML_OPENING_TAG ||
2248                 strcmp(key->str.ptr,"opencv_storage") != 0 )
2249                 CV_PARSE_ERROR( "<opencv_storage> tag is missing" );
2250 
2251             root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
2252             ptr = icvXMLParseValue( fs, ptr, root_node, CV_NODE_NONE );
2253             ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type );
2254             if( tag_type != CV_XML_CLOSING_TAG || key != key2 )
2255                 CV_PARSE_ERROR( "</opencv_storage> tag is missing" );
2256             ptr = icvXMLSkipSpaces( fs, ptr, 0 );
2257         }
2258     }
2259 
2260     assert( fs->dummy_eof != 0 );
2261 }
2262 
2263 
2264 /****************************************************************************************\
2265 *                                       XML Emitter                                      *
2266 \****************************************************************************************/
2267 
2268 #define icvXMLFlush icvFSFlush
2269 
2270 static void
icvXMLWriteTag(CvFileStorage * fs,const char * key,int tag_type,CvAttrList list)2271 icvXMLWriteTag( CvFileStorage* fs, const char* key, int tag_type, CvAttrList list )
2272 {
2273     char* ptr = fs->buffer;
2274     int i, len = 0;
2275     int struct_flags = fs->struct_flags;
2276 
2277     if( key && key[0] == '\0' )
2278         key = 0;
2279 
2280     if( tag_type == CV_XML_OPENING_TAG || tag_type == CV_XML_EMPTY_TAG )
2281     {
2282         if( CV_NODE_IS_COLLECTION(struct_flags) )
2283         {
2284             if( CV_NODE_IS_MAP(struct_flags) ^ (key != 0) )
2285                 CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
2286                                         "or add element with key to sequence" );
2287         }
2288         else
2289         {
2290             struct_flags = CV_NODE_EMPTY + (key ? CV_NODE_MAP : CV_NODE_SEQ);
2291             fs->is_first = 0;
2292         }
2293 
2294         if( !CV_NODE_IS_EMPTY(struct_flags) )
2295             ptr = icvXMLFlush(fs);
2296     }
2297 
2298     if( !key )
2299         key = "_";
2300     else if( key[0] == '_' && key[1] == '\0' )
2301         CV_Error( CV_StsBadArg, "A single _ is a reserved tag name" );
2302 
2303     len = (int)strlen( key );
2304     *ptr++ = '<';
2305     if( tag_type == CV_XML_CLOSING_TAG )
2306     {
2307         if( list.attr )
2308             CV_Error( CV_StsBadArg, "Closing tag should not include any attributes" );
2309         *ptr++ = '/';
2310     }
2311 
2312     if( !cv_isalpha(key[0]) && key[0] != '_' )
2313         CV_Error( CV_StsBadArg, "Key should start with a letter or _" );
2314 
2315     ptr = icvFSResizeWriteBuffer( fs, ptr, len );
2316     for( i = 0; i < len; i++ )
2317     {
2318         char c = key[i];
2319         if( !cv_isalnum(c) && c != '_' && c != '-' )
2320             CV_Error( CV_StsBadArg, "Key name may only contain alphanumeric characters [a-zA-Z0-9], '-' and '_'" );
2321         ptr[i] = c;
2322     }
2323     ptr += len;
2324 
2325     for(;;)
2326     {
2327         const char** attr = list.attr;
2328 
2329         for( ; attr && attr[0] != 0; attr += 2 )
2330         {
2331             int len0 = (int)strlen(attr[0]);
2332             int len1 = (int)strlen(attr[1]);
2333 
2334             ptr = icvFSResizeWriteBuffer( fs, ptr, len0 + len1 + 4 );
2335             *ptr++ = ' ';
2336             memcpy( ptr, attr[0], len0 );
2337             ptr += len0;
2338             *ptr++ = '=';
2339             *ptr++ = '\"';
2340             memcpy( ptr, attr[1], len1 );
2341             ptr += len1;
2342             *ptr++ = '\"';
2343         }
2344         if( !list.next )
2345             break;
2346         list = *list.next;
2347     }
2348 
2349     if( tag_type == CV_XML_EMPTY_TAG )
2350         *ptr++ = '/';
2351     *ptr++ = '>';
2352     fs->buffer = ptr;
2353     fs->struct_flags = struct_flags & ~CV_NODE_EMPTY;
2354 }
2355 
2356 
2357 static void
2358 icvXMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
2359                         const char* type_name CV_DEFAULT(0))
2360 {
2361     CvXMLStackRecord parent;
2362     const char* attr[10];
2363     int idx = 0;
2364 
2365     struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
2366     if( !CV_NODE_IS_COLLECTION(struct_flags))
2367         CV_Error( CV_StsBadArg,
2368         "Some collection type: CV_NODE_SEQ or CV_NODE_MAP must be specified" );
2369 
2370     if( type_name )
2371     {
2372         attr[idx++] = "type_id";
2373         attr[idx++] = type_name;
2374     }
2375     attr[idx++] = 0;
2376 
2377     icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(attr,0) );
2378 
2379     parent.struct_flags = fs->struct_flags & ~CV_NODE_EMPTY;
2380     parent.struct_indent = fs->struct_indent;
2381     parent.struct_tag = fs->struct_tag;
2382     cvSaveMemStoragePos( fs->strstorage, &parent.pos );
2383     cvSeqPush( fs->write_stack, &parent );
2384 
2385     fs->struct_indent += CV_XML_INDENT;
2386     if( !CV_NODE_IS_FLOW(struct_flags) )
2387         icvXMLFlush( fs );
2388 
2389     fs->struct_flags = struct_flags;
2390     if( key )
2391     {
2392         fs->struct_tag = cvMemStorageAllocString( fs->strstorage, (char*)key, -1 );
2393     }
2394     else
2395     {
2396         fs->struct_tag.ptr = 0;
2397         fs->struct_tag.len = 0;
2398     }
2399 }
2400 
2401 
2402 static void
icvXMLEndWriteStruct(CvFileStorage * fs)2403 icvXMLEndWriteStruct( CvFileStorage* fs )
2404 {
2405     CvXMLStackRecord parent;
2406 
2407     if( fs->write_stack->total == 0 )
2408         CV_Error( CV_StsError, "An extra closing tag" );
2409 
2410     icvXMLWriteTag( fs, fs->struct_tag.ptr, CV_XML_CLOSING_TAG, cvAttrList(0,0) );
2411     cvSeqPop( fs->write_stack, &parent );
2412 
2413     fs->struct_indent = parent.struct_indent;
2414     fs->struct_flags = parent.struct_flags;
2415     fs->struct_tag = parent.struct_tag;
2416     cvRestoreMemStoragePos( fs->strstorage, &parent.pos );
2417 }
2418 
2419 
2420 static void
icvXMLStartNextStream(CvFileStorage * fs)2421 icvXMLStartNextStream( CvFileStorage* fs )
2422 {
2423     if( !fs->is_first )
2424     {
2425         while( fs->write_stack->total > 0 )
2426             icvXMLEndWriteStruct(fs);
2427 
2428         fs->struct_indent = 0;
2429         icvXMLFlush(fs);
2430         /* XML does not allow multiple top-level elements,
2431            so we just put a comment and continue
2432            the current (and the only) "stream" */
2433         icvPuts( fs, "\n<!-- next stream -->\n" );
2434         /*fputs( "</opencv_storage>\n", fs->file );
2435         fputs( "<opencv_storage>\n", fs->file );*/
2436         fs->buffer = fs->buffer_start;
2437     }
2438 }
2439 
2440 
2441 static void
icvXMLWriteScalar(CvFileStorage * fs,const char * key,const char * data,int len)2442 icvXMLWriteScalar( CvFileStorage* fs, const char* key, const char* data, int len )
2443 {
2444     if( CV_NODE_IS_MAP(fs->struct_flags) ||
2445         (!CV_NODE_IS_COLLECTION(fs->struct_flags) && key) )
2446     {
2447         icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(0,0) );
2448         char* ptr = icvFSResizeWriteBuffer( fs, fs->buffer, len );
2449         memcpy( ptr, data, len );
2450         fs->buffer = ptr + len;
2451         icvXMLWriteTag( fs, key, CV_XML_CLOSING_TAG, cvAttrList(0,0) );
2452     }
2453     else
2454     {
2455         char* ptr = fs->buffer;
2456         int new_offset = (int)(ptr - fs->buffer_start) + len;
2457 
2458         if( key )
2459             CV_Error( CV_StsBadArg, "elements with keys can not be written to sequence" );
2460 
2461         fs->struct_flags = CV_NODE_SEQ;
2462 
2463         if( (new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10) ||
2464             (ptr > fs->buffer_start && ptr[-1] == '>' && !CV_NODE_IS_EMPTY(fs->struct_flags)) )
2465         {
2466             ptr = icvXMLFlush(fs);
2467         }
2468         else if( ptr > fs->buffer_start + fs->struct_indent && ptr[-1] != '>' )
2469             *ptr++ = ' ';
2470 
2471         memcpy( ptr, data, len );
2472         fs->buffer = ptr + len;
2473     }
2474 }
2475 
2476 
2477 static void
icvXMLWriteInt(CvFileStorage * fs,const char * key,int value)2478 icvXMLWriteInt( CvFileStorage* fs, const char* key, int value )
2479 {
2480     char buf[128], *ptr = icv_itoa( value, buf, 10 );
2481     int len = (int)strlen(ptr);
2482     icvXMLWriteScalar( fs, key, ptr, len );
2483 }
2484 
2485 
2486 static void
icvXMLWriteReal(CvFileStorage * fs,const char * key,double value)2487 icvXMLWriteReal( CvFileStorage* fs, const char* key, double value )
2488 {
2489     char buf[128];
2490     int len = (int)strlen( icvDoubleToString( buf, value ));
2491     icvXMLWriteScalar( fs, key, buf, len );
2492 }
2493 
2494 
2495 static void
icvXMLWriteString(CvFileStorage * fs,const char * key,const char * str,int quote)2496 icvXMLWriteString( CvFileStorage* fs, const char* key, const char* str, int quote )
2497 {
2498     char buf[CV_FS_MAX_LEN*6+16];
2499     char* data = (char*)str;
2500     int i, len;
2501 
2502     if( !str )
2503         CV_Error( CV_StsNullPtr, "Null string pointer" );
2504 
2505     len = (int)strlen(str);
2506     if( len > CV_FS_MAX_LEN )
2507         CV_Error( CV_StsBadArg, "The written string is too long" );
2508 
2509     if( quote || len == 0 || str[0] != '\"' || str[0] != str[len-1] )
2510     {
2511         int need_quote = quote || len == 0;
2512         data = buf;
2513         *data++ = '\"';
2514         for( i = 0; i < len; i++ )
2515         {
2516             char c = str[i];
2517 
2518             if( (uchar)c >= 128 || c == ' ' )
2519             {
2520                 *data++ = c;
2521                 need_quote = 1;
2522             }
2523             else if( !cv_isprint(c) || c == '<' || c == '>' || c == '&' || c == '\'' || c == '\"' )
2524             {
2525                 *data++ = '&';
2526                 if( c == '<' )
2527                 {
2528                     memcpy(data, "lt", 2);
2529                     data += 2;
2530                 }
2531                 else if( c == '>' )
2532                 {
2533                     memcpy(data, "gt", 2);
2534                     data += 2;
2535                 }
2536                 else if( c == '&' )
2537                 {
2538                     memcpy(data, "amp", 3);
2539                     data += 3;
2540                 }
2541                 else if( c == '\'' )
2542                 {
2543                     memcpy(data, "apos", 4);
2544                     data += 4;
2545                 }
2546                 else if( c == '\"' )
2547                 {
2548                     memcpy( data, "quot", 4);
2549                     data += 4;
2550                 }
2551                 else
2552                 {
2553                     sprintf( data, "#x%02x", (uchar)c );
2554                     data += 4;
2555                 }
2556                 *data++ = ';';
2557                 need_quote = 1;
2558             }
2559             else
2560                 *data++ = c;
2561         }
2562         if( !need_quote && (cv_isdigit(str[0]) ||
2563             str[0] == '+' || str[0] == '-' || str[0] == '.' ))
2564             need_quote = 1;
2565 
2566         if( need_quote )
2567             *data++ = '\"';
2568         len = (int)(data - buf) - !need_quote;
2569         *data++ = '\0';
2570         data = buf + !need_quote;
2571     }
2572 
2573     icvXMLWriteScalar( fs, key, data, len );
2574 }
2575 
2576 
2577 static void
icvXMLWriteComment(CvFileStorage * fs,const char * comment,int eol_comment)2578 icvXMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
2579 {
2580     int len;
2581     int multiline;
2582     const char* eol;
2583     char* ptr;
2584 
2585     if( !comment )
2586         CV_Error( CV_StsNullPtr, "Null comment" );
2587 
2588     if( strstr(comment, "--") != 0 )
2589         CV_Error( CV_StsBadArg, "Double hyphen \'--\' is not allowed in the comments" );
2590 
2591     len = (int)strlen(comment);
2592     eol = strchr(comment, '\n');
2593     multiline = eol != 0;
2594     ptr = fs->buffer;
2595 
2596     if( multiline || !eol_comment || fs->buffer_end - ptr < len + 5 )
2597         ptr = icvXMLFlush( fs );
2598     else if( ptr > fs->buffer_start + fs->struct_indent )
2599         *ptr++ = ' ';
2600 
2601     if( !multiline )
2602     {
2603         ptr = icvFSResizeWriteBuffer( fs, ptr, len + 9 );
2604         sprintf( ptr, "<!-- %s -->", comment );
2605         len = (int)strlen(ptr);
2606     }
2607     else
2608     {
2609         strcpy( ptr, "<!--" );
2610         len = 4;
2611     }
2612 
2613     fs->buffer = ptr + len;
2614     ptr = icvXMLFlush(fs);
2615 
2616     if( multiline )
2617     {
2618         while( comment )
2619         {
2620             if( eol )
2621             {
2622                 ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 );
2623                 memcpy( ptr, comment, eol - comment + 1 );
2624                 ptr += eol - comment;
2625                 comment = eol + 1;
2626                 eol = strchr( comment, '\n' );
2627             }
2628             else
2629             {
2630                 len = (int)strlen(comment);
2631                 ptr = icvFSResizeWriteBuffer( fs, ptr, len );
2632                 memcpy( ptr, comment, len );
2633                 ptr += len;
2634                 comment = 0;
2635             }
2636             fs->buffer = ptr;
2637             ptr = icvXMLFlush( fs );
2638         }
2639         sprintf( ptr, "-->" );
2640         fs->buffer = ptr + 3;
2641         icvXMLFlush( fs );
2642     }
2643 }
2644 
2645 
2646 /****************************************************************************************\
2647 *                              Common High-Level Functions                               *
2648 \****************************************************************************************/
2649 
2650 CV_IMPL CvFileStorage*
cvOpenFileStorage(const char * filename,CvMemStorage * dststorage,int flags,const char * encoding)2651 cvOpenFileStorage( const char* filename, CvMemStorage* dststorage, int flags, const char* encoding )
2652 {
2653     CvFileStorage* fs = 0;
2654     int default_block_size = 1 << 18;
2655     bool append = (flags & 3) == CV_STORAGE_APPEND;
2656     bool mem = (flags & CV_STORAGE_MEMORY) != 0;
2657     bool write_mode = (flags & 3) != 0;
2658     bool isGZ = false;
2659     size_t fnamelen = 0;
2660 
2661     if( !filename || filename[0] == '\0' )
2662     {
2663         if( !write_mode )
2664             CV_Error( CV_StsNullPtr, mem ? "NULL or empty filename" : "NULL or empty buffer" );
2665         mem = true;
2666     }
2667     else
2668         fnamelen = strlen(filename);
2669 
2670     if( mem && append )
2671         CV_Error( CV_StsBadFlag, "CV_STORAGE_APPEND and CV_STORAGE_MEMORY are not currently compatible" );
2672 
2673     fs = (CvFileStorage*)cvAlloc( sizeof(*fs) );
2674     memset( fs, 0, sizeof(*fs));
2675 
2676     fs->memstorage = cvCreateMemStorage( default_block_size );
2677     fs->dststorage = dststorage ? dststorage : fs->memstorage;
2678 
2679     fs->flags = CV_FILE_STORAGE;
2680     fs->write_mode = write_mode;
2681 
2682     if( !mem )
2683     {
2684         fs->filename = (char*)cvMemStorageAlloc( fs->memstorage, fnamelen+1 );
2685         strcpy( fs->filename, filename );
2686 
2687         char* dot_pos = strrchr(fs->filename, '.');
2688         char compression = '\0';
2689 
2690         if( dot_pos && dot_pos[1] == 'g' && dot_pos[2] == 'z' &&
2691             (dot_pos[3] == '\0' || (cv_isdigit(dot_pos[3]) && dot_pos[4] == '\0')) )
2692         {
2693             if( append )
2694             {
2695                 cvReleaseFileStorage( &fs );
2696                 CV_Error(CV_StsNotImplemented, "Appending data to compressed file is not implemented" );
2697             }
2698             isGZ = true;
2699             compression = dot_pos[3];
2700             if( compression )
2701                 dot_pos[3] = '\0', fnamelen--;
2702         }
2703 
2704         if( !isGZ )
2705         {
2706             fs->file = fopen(fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" );
2707             if( !fs->file )
2708                 goto _exit_;
2709         }
2710         else
2711         {
2712             #if USE_ZLIB
2713             char mode[] = { fs->write_mode ? 'w' : 'r', 'b', compression ? compression : '3', '\0' };
2714             fs->gzfile = gzopen(fs->filename, mode);
2715             if( !fs->gzfile )
2716                 goto _exit_;
2717             #else
2718             cvReleaseFileStorage( &fs );
2719             CV_Error(CV_StsNotImplemented, "There is no compressed file storage support in this configuration");
2720             #endif
2721         }
2722     }
2723 
2724     fs->roots = 0;
2725     fs->struct_indent = 0;
2726     fs->struct_flags = 0;
2727     fs->wrap_margin = 71;
2728 
2729     if( fs->write_mode )
2730     {
2731         int fmt = flags & CV_STORAGE_FORMAT_MASK;
2732 
2733         if( mem )
2734             fs->outbuf = new std::deque<char>;
2735 
2736         if( fmt == CV_STORAGE_FORMAT_AUTO && filename )
2737         {
2738             const char* dot_pos = filename + fnamelen - (isGZ ? 7 : 4);
2739             fs->fmt = (dot_pos >= filename && (memcmp( dot_pos, ".xml", 4) == 0 ||
2740                     memcmp(dot_pos, ".XML", 4) == 0 || memcmp(dot_pos, ".Xml", 4) == 0)) ?
2741                 CV_STORAGE_FORMAT_XML : CV_STORAGE_FORMAT_YAML;
2742         }
2743         else
2744             fs->fmt = fmt != CV_STORAGE_FORMAT_AUTO ? fmt : CV_STORAGE_FORMAT_XML;
2745 
2746         // we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (&apos; and &quot;)
2747         // and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB))
2748         int buf_size = CV_FS_MAX_LEN*(fs->fmt == CV_STORAGE_FORMAT_XML ? 6 : 4) + 1024;
2749 
2750         if( append )
2751             fseek( fs->file, 0, SEEK_END );
2752 
2753         fs->write_stack = cvCreateSeq( 0, sizeof(CvSeq), fs->fmt == CV_STORAGE_FORMAT_XML ?
2754                 sizeof(CvXMLStackRecord) : sizeof(int), fs->memstorage );
2755         fs->is_first = 1;
2756         fs->struct_indent = 0;
2757         fs->struct_flags = CV_NODE_EMPTY;
2758         fs->buffer_start = fs->buffer = (char*)cvAlloc( buf_size + 1024 );
2759         fs->buffer_end = fs->buffer_start + buf_size;
2760         if( fs->fmt == CV_STORAGE_FORMAT_XML )
2761         {
2762             size_t file_size = fs->file ? (size_t)ftell( fs->file ) : (size_t)0;
2763             fs->strstorage = cvCreateChildMemStorage( fs->memstorage );
2764             if( !append || file_size == 0 )
2765             {
2766                 if( encoding )
2767                 {
2768                     if( strcmp( encoding, "UTF-16" ) == 0 ||
2769                         strcmp( encoding, "utf-16" ) == 0 ||
2770                         strcmp( encoding, "Utf-16" ) == 0 )
2771                     {
2772                         cvReleaseFileStorage( &fs );
2773                         CV_Error( CV_StsBadArg, "UTF-16 XML encoding is not supported! Use 8-bit encoding\n");
2774                     }
2775 
2776                     CV_Assert( strlen(encoding) < 1000 );
2777                     char buf[1100];
2778                     sprintf(buf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding);
2779                     icvPuts( fs, buf );
2780                 }
2781                 else
2782                     icvPuts( fs, "<?xml version=\"1.0\"?>\n" );
2783                 icvPuts( fs, "<opencv_storage>\n" );
2784             }
2785             else
2786             {
2787                 int xml_buf_size = 1 << 10;
2788                 char substr[] = "</opencv_storage>";
2789                 int last_occurence = -1;
2790                 xml_buf_size = MIN(xml_buf_size, int(file_size));
2791                 fseek( fs->file, -xml_buf_size, SEEK_END );
2792                 char* xml_buf = (char*)cvAlloc( xml_buf_size+2 );
2793                 // find the last occurence of </opencv_storage>
2794                 for(;;)
2795                 {
2796                     int line_offset = (int)ftell( fs->file );
2797                     char* ptr0 = icvGets( fs, xml_buf, xml_buf_size ), *ptr;
2798                     if( !ptr0 )
2799                         break;
2800                     ptr = ptr0;
2801                     for(;;)
2802                     {
2803                         ptr = strstr( ptr, substr );
2804                         if( !ptr )
2805                             break;
2806                         last_occurence = line_offset + (int)(ptr - ptr0);
2807                         ptr += strlen(substr);
2808                     }
2809                 }
2810                 cvFree( &xml_buf );
2811                 if( last_occurence < 0 )
2812                 {
2813                     cvReleaseFileStorage( &fs );
2814                     CV_Error( CV_StsError, "Could not find </opencv_storage> in the end of file.\n" );
2815                 }
2816                 icvCloseFile( fs );
2817                 fs->file = fopen( fs->filename, "r+t" );
2818                 fseek( fs->file, last_occurence, SEEK_SET );
2819                 // replace the last "</opencv_storage>" with " <!-- resumed -->", which has the same length
2820                 icvPuts( fs, " <!-- resumed -->" );
2821                 fseek( fs->file, 0, SEEK_END );
2822                 icvPuts( fs, "\n" );
2823             }
2824             fs->start_write_struct = icvXMLStartWriteStruct;
2825             fs->end_write_struct = icvXMLEndWriteStruct;
2826             fs->write_int = icvXMLWriteInt;
2827             fs->write_real = icvXMLWriteReal;
2828             fs->write_string = icvXMLWriteString;
2829             fs->write_comment = icvXMLWriteComment;
2830             fs->start_next_stream = icvXMLStartNextStream;
2831         }
2832         else
2833         {
2834             if( !append )
2835                 icvPuts( fs, "%YAML:1.0\n" );
2836             else
2837                 icvPuts( fs, "...\n---\n" );
2838             fs->start_write_struct = icvYMLStartWriteStruct;
2839             fs->end_write_struct = icvYMLEndWriteStruct;
2840             fs->write_int = icvYMLWriteInt;
2841             fs->write_real = icvYMLWriteReal;
2842             fs->write_string = icvYMLWriteString;
2843             fs->write_comment = icvYMLWriteComment;
2844             fs->start_next_stream = icvYMLStartNextStream;
2845         }
2846     }
2847     else
2848     {
2849         if( mem )
2850         {
2851             fs->strbuf = filename;
2852             fs->strbufsize = fnamelen;
2853         }
2854 
2855         size_t buf_size = 1 << 20;
2856         const char* yaml_signature = "%YAML:";
2857         char buf[16];
2858         icvGets( fs, buf, sizeof(buf)-2 );
2859         fs->fmt = strncmp( buf, yaml_signature, strlen(yaml_signature) ) == 0 ?
2860             CV_STORAGE_FORMAT_YAML : CV_STORAGE_FORMAT_XML;
2861 
2862         if( !isGZ )
2863         {
2864             if( !mem )
2865             {
2866                 fseek( fs->file, 0, SEEK_END );
2867                 buf_size = ftell( fs->file );
2868             }
2869             else
2870                 buf_size = fs->strbufsize;
2871             buf_size = MIN( buf_size, (size_t)(1 << 20) );
2872             buf_size = MAX( buf_size, (size_t)(CV_FS_MAX_LEN*2 + 1024) );
2873         }
2874         icvRewind(fs);
2875 
2876         fs->str_hash = cvCreateMap( 0, sizeof(CvStringHash),
2877                         sizeof(CvStringHashNode), fs->memstorage, 256 );
2878 
2879         fs->roots = cvCreateSeq( 0, sizeof(CvSeq),
2880                         sizeof(CvFileNode), fs->memstorage );
2881 
2882         fs->buffer = fs->buffer_start = (char*)cvAlloc( buf_size + 256 );
2883         fs->buffer_end = fs->buffer_start + buf_size;
2884         fs->buffer[0] = '\n';
2885         fs->buffer[1] = '\0';
2886 
2887         //mode = cvGetErrMode();
2888         //cvSetErrMode( CV_ErrModeSilent );
2889         try
2890         {
2891             if( fs->fmt == CV_STORAGE_FORMAT_XML )
2892                 icvXMLParse( fs );
2893             else
2894                 icvYMLParse( fs );
2895         }
2896         catch (...)
2897         {
2898             cvReleaseFileStorage( &fs );
2899             throw;
2900         }
2901         //cvSetErrMode( mode );
2902 
2903         // release resources that we do not need anymore
2904         cvFree( &fs->buffer_start );
2905         fs->buffer = fs->buffer_end = 0;
2906     }
2907     fs->is_opened = true;
2908 
2909 _exit_:
2910     if( fs )
2911     {
2912         if( cvGetErrStatus() < 0 || (!fs->file && !fs->gzfile && !fs->outbuf && !fs->strbuf) )
2913         {
2914             cvReleaseFileStorage( &fs );
2915         }
2916         else if( !fs->write_mode )
2917         {
2918             icvCloseFile(fs);
2919             // we close the file since it's not needed anymore. But icvCloseFile() resets is_opened,
2920             // which may be misleading. Since we restore the value of is_opened.
2921             fs->is_opened = true;
2922         }
2923     }
2924 
2925     return  fs;
2926 }
2927 
2928 
2929 CV_IMPL void
cvStartWriteStruct(CvFileStorage * fs,const char * key,int struct_flags,const char * type_name,CvAttrList)2930 cvStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
2931                     const char* type_name, CvAttrList /*attributes*/ )
2932 {
2933     CV_CHECK_OUTPUT_FILE_STORAGE(fs);
2934     fs->start_write_struct( fs, key, struct_flags, type_name );
2935 }
2936 
2937 
2938 CV_IMPL void
cvEndWriteStruct(CvFileStorage * fs)2939 cvEndWriteStruct( CvFileStorage* fs )
2940 {
2941     CV_CHECK_OUTPUT_FILE_STORAGE(fs);
2942     fs->end_write_struct( fs );
2943 }
2944 
2945 
2946 CV_IMPL void
cvWriteInt(CvFileStorage * fs,const char * key,int value)2947 cvWriteInt( CvFileStorage* fs, const char* key, int value )
2948 {
2949     CV_CHECK_OUTPUT_FILE_STORAGE(fs);
2950     fs->write_int( fs, key, value );
2951 }
2952 
2953 
2954 CV_IMPL void
cvWriteReal(CvFileStorage * fs,const char * key,double value)2955 cvWriteReal( CvFileStorage* fs, const char* key, double value )
2956 {
2957     CV_CHECK_OUTPUT_FILE_STORAGE(fs);
2958     fs->write_real( fs, key, value );
2959 }
2960 
2961 
2962 CV_IMPL void
cvWriteString(CvFileStorage * fs,const char * key,const char * value,int quote)2963 cvWriteString( CvFileStorage* fs, const char* key, const char* value, int quote )
2964 {
2965     CV_CHECK_OUTPUT_FILE_STORAGE(fs);
2966     fs->write_string( fs, key, value, quote );
2967 }
2968 
2969 
2970 CV_IMPL void
cvWriteComment(CvFileStorage * fs,const char * comment,int eol_comment)2971 cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
2972 {
2973     CV_CHECK_OUTPUT_FILE_STORAGE(fs);
2974     fs->write_comment( fs, comment, eol_comment );
2975 }
2976 
2977 
2978 CV_IMPL void
cvStartNextStream(CvFileStorage * fs)2979 cvStartNextStream( CvFileStorage* fs )
2980 {
2981     CV_CHECK_OUTPUT_FILE_STORAGE(fs);
2982     fs->start_next_stream( fs );
2983 }
2984 
2985 
2986 static const char icvTypeSymbol[] = "ucwsifdr";
2987 #define CV_FS_MAX_FMT_PAIRS  128
2988 
2989 static char*
icvEncodeFormat(int elem_type,char * dt)2990 icvEncodeFormat( int elem_type, char* dt )
2991 {
2992     sprintf( dt, "%d%c", CV_MAT_CN(elem_type), icvTypeSymbol[CV_MAT_DEPTH(elem_type)] );
2993     return dt + ( dt[2] == '\0' && dt[0] == '1' );
2994 }
2995 
2996 static int
icvDecodeFormat(const char * dt,int * fmt_pairs,int max_len)2997 icvDecodeFormat( const char* dt, int* fmt_pairs, int max_len )
2998 {
2999     int fmt_pair_count = 0;
3000     int i = 0, k = 0, len = dt ? (int)strlen(dt) : 0;
3001 
3002     if( !dt || !len )
3003         return 0;
3004 
3005     assert( fmt_pairs != 0 && max_len > 0 );
3006     fmt_pairs[0] = 0;
3007     max_len *= 2;
3008 
3009     for( ; k < len; k++ )
3010     {
3011         char c = dt[k];
3012 
3013         if( cv_isdigit(c) )
3014         {
3015             int count = c - '0';
3016             if( cv_isdigit(dt[k+1]) )
3017             {
3018                 char* endptr = 0;
3019                 count = (int)strtol( dt+k, &endptr, 10 );
3020                 k = (int)(endptr - dt) - 1;
3021             }
3022 
3023             if( count <= 0 )
3024                 CV_Error( CV_StsBadArg, "Invalid data type specification" );
3025 
3026             fmt_pairs[i] = count;
3027         }
3028         else
3029         {
3030             const char* pos = strchr( icvTypeSymbol, c );
3031             if( !pos )
3032                 CV_Error( CV_StsBadArg, "Invalid data type specification" );
3033             if( fmt_pairs[i] == 0 )
3034                 fmt_pairs[i] = 1;
3035             fmt_pairs[i+1] = (int)(pos - icvTypeSymbol);
3036             if( i > 0 && fmt_pairs[i+1] == fmt_pairs[i-1] )
3037                 fmt_pairs[i-2] += fmt_pairs[i];
3038             else
3039             {
3040                 i += 2;
3041                 if( i >= max_len )
3042                     CV_Error( CV_StsBadArg, "Too long data type specification" );
3043             }
3044             fmt_pairs[i] = 0;
3045         }
3046     }
3047 
3048     fmt_pair_count = i/2;
3049     return fmt_pair_count;
3050 }
3051 
3052 
3053 static int
icvCalcElemSize(const char * dt,int initial_size)3054 icvCalcElemSize( const char* dt, int initial_size )
3055 {
3056     int size = 0;
3057     int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
3058     int comp_size;
3059 
3060     fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
3061     fmt_pair_count *= 2;
3062     for( i = 0, size = initial_size; i < fmt_pair_count; i += 2 )
3063     {
3064         comp_size = CV_ELEM_SIZE(fmt_pairs[i+1]);
3065         size = cvAlign( size, comp_size );
3066         size += comp_size * fmt_pairs[i];
3067     }
3068     if( initial_size == 0 )
3069     {
3070         comp_size = CV_ELEM_SIZE(fmt_pairs[1]);
3071         size = cvAlign( size, comp_size );
3072     }
3073     return size;
3074 }
3075 
3076 
3077 static int
icvDecodeSimpleFormat(const char * dt)3078 icvDecodeSimpleFormat( const char* dt )
3079 {
3080     int elem_type = -1;
3081     int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
3082 
3083     fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
3084     if( fmt_pair_count != 1 || fmt_pairs[0] > 4 )
3085         CV_Error( CV_StsError, "Too complex format for the matrix" );
3086 
3087     elem_type = CV_MAKETYPE( fmt_pairs[1], fmt_pairs[0] );
3088 
3089     return elem_type;
3090 }
3091 
3092 
3093 CV_IMPL void
cvWriteRawData(CvFileStorage * fs,const void * _data,int len,const char * dt)3094 cvWriteRawData( CvFileStorage* fs, const void* _data, int len, const char* dt )
3095 {
3096     const char* data0 = (const char*)_data;
3097     int offset = 0;
3098     int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k, fmt_pair_count;
3099     char buf[256] = "";
3100 
3101     CV_CHECK_OUTPUT_FILE_STORAGE( fs );
3102 
3103     if( len < 0 )
3104         CV_Error( CV_StsOutOfRange, "Negative number of elements" );
3105 
3106     fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
3107 
3108     if( !len )
3109         return;
3110 
3111     if( !data0 )
3112         CV_Error( CV_StsNullPtr, "Null data pointer" );
3113 
3114     if( fmt_pair_count == 1 )
3115     {
3116         fmt_pairs[0] *= len;
3117         len = 1;
3118     }
3119 
3120     for(;len--;)
3121     {
3122         for( k = 0; k < fmt_pair_count; k++ )
3123         {
3124             int i, count = fmt_pairs[k*2];
3125             int elem_type = fmt_pairs[k*2+1];
3126             int elem_size = CV_ELEM_SIZE(elem_type);
3127             const char* data, *ptr;
3128 
3129             offset = cvAlign( offset, elem_size );
3130             data = data0 + offset;
3131 
3132             for( i = 0; i < count; i++ )
3133             {
3134                 switch( elem_type )
3135                 {
3136                 case CV_8U:
3137                     ptr = icv_itoa( *(uchar*)data, buf, 10 );
3138                     data++;
3139                     break;
3140                 case CV_8S:
3141                     ptr = icv_itoa( *(char*)data, buf, 10 );
3142                     data++;
3143                     break;
3144                 case CV_16U:
3145                     ptr = icv_itoa( *(ushort*)data, buf, 10 );
3146                     data += sizeof(ushort);
3147                     break;
3148                 case CV_16S:
3149                     ptr = icv_itoa( *(short*)data, buf, 10 );
3150                     data += sizeof(short);
3151                     break;
3152                 case CV_32S:
3153                     ptr = icv_itoa( *(int*)data, buf, 10 );
3154                     data += sizeof(int);
3155                     break;
3156                 case CV_32F:
3157                     ptr = icvFloatToString( buf, *(float*)data );
3158                     data += sizeof(float);
3159                     break;
3160                 case CV_64F:
3161                     ptr = icvDoubleToString( buf, *(double*)data );
3162                     data += sizeof(double);
3163                     break;
3164                 case CV_USRTYPE1: /* reference */
3165                     ptr = icv_itoa( (int)*(size_t*)data, buf, 10 );
3166                     data += sizeof(size_t);
3167                     break;
3168                 default:
3169                     assert(0);
3170                     return;
3171                 }
3172 
3173                 if( fs->fmt == CV_STORAGE_FORMAT_XML )
3174                 {
3175                     int buf_len = (int)strlen(ptr);
3176                     icvXMLWriteScalar( fs, 0, ptr, buf_len );
3177                 }
3178                 else
3179                     icvYMLWrite( fs, 0, ptr );
3180             }
3181 
3182             offset = (int)(data - data0);
3183         }
3184     }
3185 }
3186 
3187 
3188 CV_IMPL void
cvStartReadRawData(const CvFileStorage * fs,const CvFileNode * src,CvSeqReader * reader)3189 cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, CvSeqReader* reader )
3190 {
3191     int node_type;
3192     CV_CHECK_FILE_STORAGE( fs );
3193 
3194     if( !src || !reader )
3195         CV_Error( CV_StsNullPtr, "Null pointer to source file node or reader" );
3196 
3197     node_type = CV_NODE_TYPE(src->tag);
3198     if( node_type == CV_NODE_INT || node_type == CV_NODE_REAL )
3199     {
3200         // emulate reading from 1-element sequence
3201         reader->ptr = (schar*)src;
3202         reader->block_max = reader->ptr + sizeof(*src)*2;
3203         reader->block_min = reader->ptr;
3204         reader->seq = 0;
3205     }
3206     else if( node_type == CV_NODE_SEQ )
3207     {
3208         cvStartReadSeq( src->data.seq, reader, 0 );
3209     }
3210     else if( node_type == CV_NODE_NONE )
3211     {
3212         memset( reader, 0, sizeof(*reader) );
3213     }
3214     else
3215         CV_Error( CV_StsBadArg, "The file node should be a numerical scalar or a sequence" );
3216 }
3217 
3218 
3219 CV_IMPL void
cvReadRawDataSlice(const CvFileStorage * fs,CvSeqReader * reader,int len,void * _data,const char * dt)3220 cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader,
3221                     int len, void* _data, const char* dt )
3222 {
3223     char* data0 = (char*)_data;
3224     int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k = 0, fmt_pair_count;
3225     int i = 0, offset = 0, count = 0;
3226 
3227     CV_CHECK_FILE_STORAGE( fs );
3228 
3229     if( !reader || !data0 )
3230         CV_Error( CV_StsNullPtr, "Null pointer to reader or destination array" );
3231 
3232     if( !reader->seq && len != 1 )
3233         CV_Error( CV_StsBadSize, "The readed sequence is a scalar, thus len must be 1" );
3234 
3235     fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
3236 
3237     for(;;)
3238     {
3239         for( k = 0; k < fmt_pair_count; k++ )
3240         {
3241             int elem_type = fmt_pairs[k*2+1];
3242             int elem_size = CV_ELEM_SIZE(elem_type);
3243             char* data;
3244 
3245             count = fmt_pairs[k*2];
3246             offset = cvAlign( offset, elem_size );
3247             data = data0 + offset;
3248 
3249             for( i = 0; i < count; i++ )
3250             {
3251                 CvFileNode* node = (CvFileNode*)reader->ptr;
3252                 if( CV_NODE_IS_INT(node->tag) )
3253                 {
3254                     int ival = node->data.i;
3255 
3256                     switch( elem_type )
3257                     {
3258                     case CV_8U:
3259                         *(uchar*)data = cv::saturate_cast<uchar>(ival);
3260                         data++;
3261                         break;
3262                     case CV_8S:
3263                         *(char*)data = cv::saturate_cast<schar>(ival);
3264                         data++;
3265                         break;
3266                     case CV_16U:
3267                         *(ushort*)data = cv::saturate_cast<ushort>(ival);
3268                         data += sizeof(ushort);
3269                         break;
3270                     case CV_16S:
3271                         *(short*)data = cv::saturate_cast<short>(ival);
3272                         data += sizeof(short);
3273                         break;
3274                     case CV_32S:
3275                         *(int*)data = ival;
3276                         data += sizeof(int);
3277                         break;
3278                     case CV_32F:
3279                         *(float*)data = (float)ival;
3280                         data += sizeof(float);
3281                         break;
3282                     case CV_64F:
3283                         *(double*)data = (double)ival;
3284                         data += sizeof(double);
3285                         break;
3286                     case CV_USRTYPE1: /* reference */
3287                         *(size_t*)data = ival;
3288                         data += sizeof(size_t);
3289                         break;
3290                     default:
3291                         assert(0);
3292                         return;
3293                     }
3294                 }
3295                 else if( CV_NODE_IS_REAL(node->tag) )
3296                 {
3297                     double fval = node->data.f;
3298                     int ival;
3299 
3300                     switch( elem_type )
3301                     {
3302                     case CV_8U:
3303                         ival = cvRound(fval);
3304                         *(uchar*)data = cv::saturate_cast<uchar>(ival);
3305                         data++;
3306                         break;
3307                     case CV_8S:
3308                         ival = cvRound(fval);
3309                         *(char*)data = cv::saturate_cast<schar>(ival);
3310                         data++;
3311                         break;
3312                     case CV_16U:
3313                         ival = cvRound(fval);
3314                         *(ushort*)data = cv::saturate_cast<ushort>(ival);
3315                         data += sizeof(ushort);
3316                         break;
3317                     case CV_16S:
3318                         ival = cvRound(fval);
3319                         *(short*)data = cv::saturate_cast<short>(ival);
3320                         data += sizeof(short);
3321                         break;
3322                     case CV_32S:
3323                         ival = cvRound(fval);
3324                         *(int*)data = ival;
3325                         data += sizeof(int);
3326                         break;
3327                     case CV_32F:
3328                         *(float*)data = (float)fval;
3329                         data += sizeof(float);
3330                         break;
3331                     case CV_64F:
3332                         *(double*)data = fval;
3333                         data += sizeof(double);
3334                         break;
3335                     case CV_USRTYPE1: /* reference */
3336                         ival = cvRound(fval);
3337                         *(size_t*)data = ival;
3338                         data += sizeof(size_t);
3339                         break;
3340                     default:
3341                         assert(0);
3342                         return;
3343                     }
3344                 }
3345                 else
3346                     CV_Error( CV_StsError,
3347                     "The sequence element is not a numerical scalar" );
3348 
3349                 CV_NEXT_SEQ_ELEM( sizeof(CvFileNode), *reader );
3350                 if( !--len )
3351                     goto end_loop;
3352             }
3353 
3354             offset = (int)(data - data0);
3355         }
3356     }
3357 
3358 end_loop:
3359     if( i != count - 1 || k != fmt_pair_count - 1 )
3360         CV_Error( CV_StsBadSize,
3361         "The sequence slice does not fit an integer number of records" );
3362 
3363     if( !reader->seq )
3364         reader->ptr -= sizeof(CvFileNode);
3365 }
3366 
3367 
3368 CV_IMPL void
cvReadRawData(const CvFileStorage * fs,const CvFileNode * src,void * data,const char * dt)3369 cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
3370                void* data, const char* dt )
3371 {
3372     CvSeqReader reader;
3373 
3374     if( !src || !data )
3375         CV_Error( CV_StsNullPtr, "Null pointers to source file node or destination array" );
3376 
3377     cvStartReadRawData( fs, src, &reader );
3378     cvReadRawDataSlice( fs, &reader, CV_NODE_IS_SEQ(src->tag) ?
3379                         src->data.seq->total : 1, data, dt );
3380 }
3381 
3382 
3383 static void
3384 icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node );
3385 
3386 static void
icvWriteCollection(CvFileStorage * fs,const CvFileNode * node)3387 icvWriteCollection( CvFileStorage* fs, const CvFileNode* node )
3388 {
3389     int i, total = node->data.seq->total;
3390     int elem_size = node->data.seq->elem_size;
3391     int is_map = CV_NODE_IS_MAP(node->tag);
3392     CvSeqReader reader;
3393 
3394     cvStartReadSeq( node->data.seq, &reader, 0 );
3395 
3396     for( i = 0; i < total; i++ )
3397     {
3398         CvFileMapNode* elem = (CvFileMapNode*)reader.ptr;
3399         if( !is_map || CV_IS_SET_ELEM(elem) )
3400         {
3401             const char* name = is_map ? elem->key->str.ptr : 0;
3402             icvWriteFileNode( fs, name, &elem->value );
3403         }
3404         CV_NEXT_SEQ_ELEM( elem_size, reader );
3405     }
3406 }
3407 
3408 static void
icvWriteFileNode(CvFileStorage * fs,const char * name,const CvFileNode * node)3409 icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node )
3410 {
3411     switch( CV_NODE_TYPE(node->tag) )
3412     {
3413     case CV_NODE_INT:
3414         fs->write_int( fs, name, node->data.i );
3415         break;
3416     case CV_NODE_REAL:
3417         fs->write_real( fs, name, node->data.f );
3418         break;
3419     case CV_NODE_STR:
3420         fs->write_string( fs, name, node->data.str.ptr, 0 );
3421         break;
3422     case CV_NODE_SEQ:
3423     case CV_NODE_MAP:
3424         fs->start_write_struct( fs, name, CV_NODE_TYPE(node->tag) +
3425                 (CV_NODE_SEQ_IS_SIMPLE(node->data.seq) ? CV_NODE_FLOW : 0),
3426                 node->info ? node->info->type_name : 0 );
3427         icvWriteCollection( fs, node );
3428         fs->end_write_struct( fs );
3429         break;
3430     case CV_NODE_NONE:
3431         fs->start_write_struct( fs, name, CV_NODE_SEQ, 0 );
3432         fs->end_write_struct( fs );
3433         break;
3434     default:
3435         CV_Error( CV_StsBadFlag, "Unknown type of file node" );
3436     }
3437 }
3438 
3439 
3440 CV_IMPL void
cvWriteFileNode(CvFileStorage * fs,const char * new_node_name,const CvFileNode * node,int embed)3441 cvWriteFileNode( CvFileStorage* fs, const char* new_node_name,
3442                  const CvFileNode* node, int embed )
3443 {
3444     CvFileStorage* dst = 0;
3445     CV_CHECK_OUTPUT_FILE_STORAGE(fs);
3446 
3447     if( !node )
3448         return;
3449 
3450     if( CV_NODE_IS_COLLECTION(node->tag) && embed )
3451     {
3452         icvWriteCollection( fs, node );
3453     }
3454     else
3455     {
3456         icvWriteFileNode( fs, new_node_name, node );
3457     }
3458     /*
3459     int i, stream_count;
3460     stream_count = fs->roots->total;
3461     for( i = 0; i < stream_count; i++ )
3462     {
3463         CvFileNode* node = (CvFileNode*)cvGetSeqElem( fs->roots, i, 0 );
3464         icvDumpCollection( dst, node );
3465         if( i < stream_count - 1 )
3466             dst->start_next_stream( dst );
3467     }*/
3468     cvReleaseFileStorage( &dst );
3469 }
3470 
3471 
3472 CV_IMPL const char*
cvGetFileNodeName(const CvFileNode * file_node)3473 cvGetFileNodeName( const CvFileNode* file_node )
3474 {
3475     return file_node && CV_NODE_HAS_NAME(file_node->tag) ?
3476         ((CvFileMapNode*)file_node)->key->str.ptr : 0;
3477 }
3478 
3479 /****************************************************************************************\
3480 *                          Reading/Writing etc. for standard types                       *
3481 \****************************************************************************************/
3482 
3483 /*#define CV_TYPE_NAME_MAT "opencv-matrix"
3484 #define CV_TYPE_NAME_MATND "opencv-nd-matrix"
3485 #define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix"
3486 #define CV_TYPE_NAME_IMAGE "opencv-image"
3487 #define CV_TYPE_NAME_SEQ "opencv-sequence"
3488 #define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree"
3489 #define CV_TYPE_NAME_GRAPH "opencv-graph"*/
3490 
3491 /******************************* CvMat ******************************/
3492 
3493 static int
icvIsMat(const void * ptr)3494 icvIsMat( const void* ptr )
3495 {
3496     return CV_IS_MAT_HDR_Z(ptr);
3497 }
3498 
3499 static void
icvWriteMat(CvFileStorage * fs,const char * name,const void * struct_ptr,CvAttrList)3500 icvWriteMat( CvFileStorage* fs, const char* name,
3501              const void* struct_ptr, CvAttrList /*attr*/ )
3502 {
3503     const CvMat* mat = (const CvMat*)struct_ptr;
3504     char dt[16];
3505     CvSize size;
3506     int y;
3507 
3508     assert( CV_IS_MAT_HDR_Z(mat) );
3509 
3510     cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MAT );
3511     cvWriteInt( fs, "rows", mat->rows );
3512     cvWriteInt( fs, "cols", mat->cols );
3513     cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
3514     cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
3515 
3516     size = cvGetSize(mat);
3517     if( size.height > 0 && size.width > 0 && mat->data.ptr )
3518     {
3519         if( CV_IS_MAT_CONT(mat->type) )
3520         {
3521             size.width *= size.height;
3522             size.height = 1;
3523         }
3524 
3525         for( y = 0; y < size.height; y++ )
3526             cvWriteRawData( fs, mat->data.ptr + (size_t)y*mat->step, size.width, dt );
3527     }
3528     cvEndWriteStruct( fs );
3529     cvEndWriteStruct( fs );
3530 }
3531 
3532 
3533 static int
icvFileNodeSeqLen(CvFileNode * node)3534 icvFileNodeSeqLen( CvFileNode* node )
3535 {
3536     return CV_NODE_IS_COLLECTION(node->tag) ? node->data.seq->total :
3537            CV_NODE_TYPE(node->tag) != CV_NODE_NONE;
3538 }
3539 
3540 
3541 static void*
icvReadMat(CvFileStorage * fs,CvFileNode * node)3542 icvReadMat( CvFileStorage* fs, CvFileNode* node )
3543 {
3544     void* ptr = 0;
3545     CvMat* mat;
3546     const char* dt;
3547     CvFileNode* data;
3548     int rows, cols, elem_type;
3549 
3550     rows = cvReadIntByName( fs, node, "rows", -1 );
3551     cols = cvReadIntByName( fs, node, "cols", -1 );
3552     dt = cvReadStringByName( fs, node, "dt", 0 );
3553 
3554     if( rows < 0 || cols < 0 || !dt )
3555         CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
3556 
3557     elem_type = icvDecodeSimpleFormat( dt );
3558 
3559     data = cvGetFileNodeByName( fs, node, "data" );
3560     if( !data )
3561         CV_Error( CV_StsError, "The matrix data is not found in file storage" );
3562 
3563     int nelems = icvFileNodeSeqLen( data );
3564     if( nelems > 0 && nelems != rows*cols*CV_MAT_CN(elem_type) )
3565         CV_Error( CV_StsUnmatchedSizes,
3566                  "The matrix size does not match to the number of stored elements" );
3567 
3568     if( nelems > 0 )
3569     {
3570         mat = cvCreateMat( rows, cols, elem_type );
3571         cvReadRawData( fs, data, mat->data.ptr, dt );
3572     }
3573     else if( rows == 0 && cols == 0 )
3574         mat = cvCreateMatHeader( 0, 1, elem_type );
3575     else
3576         mat = cvCreateMatHeader( rows, cols, elem_type );
3577 
3578     ptr = mat;
3579     return ptr;
3580 }
3581 
3582 
3583 /******************************* CvMatND ******************************/
3584 
3585 static int
icvIsMatND(const void * ptr)3586 icvIsMatND( const void* ptr )
3587 {
3588     return CV_IS_MATND_HDR(ptr);
3589 }
3590 
3591 
3592 static void
icvWriteMatND(CvFileStorage * fs,const char * name,const void * struct_ptr,CvAttrList)3593 icvWriteMatND( CvFileStorage* fs, const char* name,
3594                const void* struct_ptr, CvAttrList /*attr*/ )
3595 {
3596     CvMatND* mat = (CvMatND*)struct_ptr;
3597     CvMatND stub;
3598     CvNArrayIterator iterator;
3599     int dims, sizes[CV_MAX_DIM];
3600     char dt[16];
3601 
3602     assert( CV_IS_MATND_HDR(mat) );
3603 
3604     cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MATND );
3605     dims = cvGetDims( mat, sizes );
3606     cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
3607     cvWriteRawData( fs, sizes, dims, "i" );
3608     cvEndWriteStruct( fs );
3609     cvWriteString( fs, "dt", icvEncodeFormat( cvGetElemType(mat), dt ), 0 );
3610     cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
3611 
3612     if( mat->dim[0].size > 0 && mat->data.ptr )
3613     {
3614         cvInitNArrayIterator( 1, (CvArr**)&mat, 0, &stub, &iterator );
3615 
3616         do
3617             cvWriteRawData( fs, iterator.ptr[0], iterator.size.width, dt );
3618         while( cvNextNArraySlice( &iterator ));
3619     }
3620     cvEndWriteStruct( fs );
3621     cvEndWriteStruct( fs );
3622 }
3623 
3624 
3625 static void*
icvReadMatND(CvFileStorage * fs,CvFileNode * node)3626 icvReadMatND( CvFileStorage* fs, CvFileNode* node )
3627 {
3628     void* ptr = 0;
3629     CvMatND* mat;
3630     const char* dt;
3631     CvFileNode* data;
3632     CvFileNode* sizes_node;
3633     int sizes[CV_MAX_DIM], dims, elem_type;
3634     int i, total_size;
3635 
3636     sizes_node = cvGetFileNodeByName( fs, node, "sizes" );
3637     dt = cvReadStringByName( fs, node, "dt", 0 );
3638 
3639     if( !sizes_node || !dt )
3640         CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
3641 
3642     dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
3643            CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
3644 
3645     if( dims <= 0 || dims > CV_MAX_DIM )
3646         CV_Error( CV_StsParseError, "Could not determine the matrix dimensionality" );
3647 
3648     cvReadRawData( fs, sizes_node, sizes, "i" );
3649     elem_type = icvDecodeSimpleFormat( dt );
3650 
3651     data = cvGetFileNodeByName( fs, node, "data" );
3652     if( !data )
3653         CV_Error( CV_StsError, "The matrix data is not found in file storage" );
3654 
3655 
3656 
3657     for( total_size = CV_MAT_CN(elem_type), i = 0; i < dims; i++ )
3658         total_size *= sizes[i];
3659 
3660     int nelems = icvFileNodeSeqLen( data );
3661 
3662     if( nelems > 0 && nelems != total_size )
3663         CV_Error( CV_StsUnmatchedSizes,
3664                  "The matrix size does not match to the number of stored elements" );
3665 
3666     if( nelems > 0 )
3667     {
3668         mat = cvCreateMatND( dims, sizes, elem_type );
3669         cvReadRawData( fs, data, mat->data.ptr, dt );
3670     }
3671     else
3672         mat = cvCreateMatNDHeader( dims, sizes, elem_type );
3673 
3674     ptr = mat;
3675     return ptr;
3676 }
3677 
3678 
3679 /******************************* CvSparseMat ******************************/
3680 
3681 static int
icvIsSparseMat(const void * ptr)3682 icvIsSparseMat( const void* ptr )
3683 {
3684     return CV_IS_SPARSE_MAT(ptr);
3685 }
3686 
3687 
3688 static int
icvSortIdxCmpFunc(const void * _a,const void * _b,void * userdata)3689 icvSortIdxCmpFunc( const void* _a, const void* _b, void* userdata )
3690 {
3691     int i, dims = *(int*)userdata;
3692     const int* a = *(const int**)_a;
3693     const int* b = *(const int**)_b;
3694 
3695     for( i = 0; i < dims; i++ )
3696     {
3697         int delta = a[i] - b[i];
3698         if( delta )
3699             return delta;
3700     }
3701 
3702     return 0;
3703 }
3704 
3705 
3706 static void
icvWriteSparseMat(CvFileStorage * fs,const char * name,const void * struct_ptr,CvAttrList)3707 icvWriteSparseMat( CvFileStorage* fs, const char* name,
3708                    const void* struct_ptr, CvAttrList /*attr*/ )
3709 {
3710     CvMemStorage* memstorage = 0;
3711     const CvSparseMat* mat = (const CvSparseMat*)struct_ptr;
3712     CvSparseMatIterator iterator;
3713     CvSparseNode* node;
3714     CvSeq* elements;
3715     CvSeqReader reader;
3716     int i, dims;
3717     int *prev_idx = 0;
3718     char dt[16];
3719 
3720     assert( CV_IS_SPARSE_MAT(mat) );
3721 
3722     memstorage = cvCreateMemStorage();
3723 
3724     cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SPARSE_MAT );
3725     dims = cvGetDims( mat, 0 );
3726 
3727     cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
3728     cvWriteRawData( fs, mat->size, dims, "i" );
3729     cvEndWriteStruct( fs );
3730     cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
3731     cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
3732 
3733     elements = cvCreateSeq( CV_SEQ_ELTYPE_PTR, sizeof(CvSeq), sizeof(int*), memstorage );
3734 
3735     node = cvInitSparseMatIterator( mat, &iterator );
3736     while( node )
3737     {
3738         int* idx = CV_NODE_IDX( mat, node );
3739         cvSeqPush( elements, &idx );
3740         node = cvGetNextSparseNode( &iterator );
3741     }
3742 
3743     cvSeqSort( elements, icvSortIdxCmpFunc, &dims );
3744     cvStartReadSeq( elements, &reader, 0 );
3745 
3746     for( i = 0; i < elements->total; i++ )
3747     {
3748         int* idx;
3749         void* val;
3750         int k = 0;
3751 
3752         CV_READ_SEQ_ELEM( idx, reader );
3753         if( i > 0 )
3754         {
3755             for( ; idx[k] == prev_idx[k]; k++ )
3756                 assert( k < dims );
3757             if( k < dims - 1 )
3758                 fs->write_int( fs, 0, k - dims + 1 );
3759         }
3760         for( ; k < dims; k++ )
3761             fs->write_int( fs, 0, idx[k] );
3762         prev_idx = idx;
3763 
3764         node = (CvSparseNode*)((uchar*)idx - mat->idxoffset );
3765         val = CV_NODE_VAL( mat, node );
3766 
3767         cvWriteRawData( fs, val, 1, dt );
3768     }
3769 
3770     cvEndWriteStruct( fs );
3771     cvEndWriteStruct( fs );
3772     cvReleaseMemStorage( &memstorage );
3773 }
3774 
3775 
3776 static void*
icvReadSparseMat(CvFileStorage * fs,CvFileNode * node)3777 icvReadSparseMat( CvFileStorage* fs, CvFileNode* node )
3778 {
3779     void* ptr = 0;
3780     CvSparseMat* mat;
3781     const char* dt;
3782     CvFileNode* data;
3783     CvFileNode* sizes_node;
3784     CvSeqReader reader;
3785     CvSeq* elements;
3786     int sizes[CV_MAX_DIM_HEAP], dims, elem_type, cn;
3787     int i;
3788 
3789     sizes_node = cvGetFileNodeByName( fs, node, "sizes" );
3790     dt = cvReadStringByName( fs, node, "dt", 0 );
3791 
3792     if( !sizes_node || !dt )
3793         CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
3794 
3795     dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
3796            CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
3797 
3798     if( dims <= 0 || dims > CV_MAX_DIM_HEAP )
3799         CV_Error( CV_StsParseError, "Could not determine sparse matrix dimensionality" );
3800 
3801     cvReadRawData( fs, sizes_node, sizes, "i" );
3802     elem_type = icvDecodeSimpleFormat( dt );
3803 
3804     data = cvGetFileNodeByName( fs, node, "data" );
3805     if( !data || !CV_NODE_IS_SEQ(data->tag) )
3806         CV_Error( CV_StsError, "The matrix data is not found in file storage" );
3807 
3808     mat = cvCreateSparseMat( dims, sizes, elem_type );
3809 
3810     cn = CV_MAT_CN(elem_type);
3811     int idx[CV_MAX_DIM_HEAP];
3812     elements = data->data.seq;
3813     cvStartReadRawData( fs, data, &reader );
3814 
3815     for( i = 0; i < elements->total; )
3816     {
3817         CvFileNode* elem = (CvFileNode*)reader.ptr;
3818         uchar* val;
3819         int k;
3820         if( !CV_NODE_IS_INT(elem->tag ))
3821             CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" );
3822         k = elem->data.i;
3823         if( i > 0 && k >= 0 )
3824             idx[dims-1] = k;
3825         else
3826         {
3827             if( i > 0 )
3828                 k = dims + k - 1;
3829             else
3830                 idx[0] = k, k = 1;
3831             for( ; k < dims; k++ )
3832             {
3833                 CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
3834                 i++;
3835                 elem = (CvFileNode*)reader.ptr;
3836                 if( !CV_NODE_IS_INT(elem->tag ) || elem->data.i < 0 )
3837                     CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" );
3838                 idx[k] = elem->data.i;
3839             }
3840         }
3841         CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
3842         i++;
3843         val = cvPtrND( mat, idx, 0, 1, 0 );
3844         cvReadRawDataSlice( fs, &reader, cn, val, dt );
3845         i += cn;
3846     }
3847 
3848     ptr = mat;
3849     return ptr;
3850 }
3851 
3852 
3853 /******************************* IplImage ******************************/
3854 
3855 static int
icvIsImage(const void * ptr)3856 icvIsImage( const void* ptr )
3857 {
3858     return CV_IS_IMAGE_HDR(ptr);
3859 }
3860 
3861 static void
icvWriteImage(CvFileStorage * fs,const char * name,const void * struct_ptr,CvAttrList)3862 icvWriteImage( CvFileStorage* fs, const char* name,
3863                const void* struct_ptr, CvAttrList /*attr*/ )
3864 {
3865     const IplImage* image = (const IplImage*)struct_ptr;
3866     char dt_buf[16], *dt;
3867     CvSize size;
3868     int y, depth;
3869 
3870     assert( CV_IS_IMAGE(image) );
3871 
3872     if( image->dataOrder == IPL_DATA_ORDER_PLANE )
3873         CV_Error( CV_StsUnsupportedFormat,
3874         "Images with planar data layout are not supported" );
3875 
3876     cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_IMAGE );
3877     cvWriteInt( fs, "width", image->width );
3878     cvWriteInt( fs, "height", image->height );
3879     cvWriteString( fs, "origin", image->origin == IPL_ORIGIN_TL
3880                    ? "top-left" : "bottom-left", 0 );
3881     cvWriteString( fs, "layout", image->dataOrder == IPL_DATA_ORDER_PLANE
3882                    ? "planar" : "interleaved", 0 );
3883     if( image->roi )
3884     {
3885         cvStartWriteStruct( fs, "roi", CV_NODE_MAP + CV_NODE_FLOW );
3886         cvWriteInt( fs, "x", image->roi->xOffset );
3887         cvWriteInt( fs, "y", image->roi->yOffset );
3888         cvWriteInt( fs, "width", image->roi->width );
3889         cvWriteInt( fs, "height", image->roi->height );
3890         cvWriteInt( fs, "coi", image->roi->coi );
3891         cvEndWriteStruct( fs );
3892     }
3893 
3894     depth = IPL2CV_DEPTH(image->depth);
3895     sprintf( dt_buf, "%d%c", image->nChannels, icvTypeSymbol[depth] );
3896     dt = dt_buf + (dt_buf[2] == '\0' && dt_buf[0] == '1');
3897     cvWriteString( fs, "dt", dt, 0 );
3898 
3899     size = cvSize(image->width, image->height);
3900     if( size.width*image->nChannels*CV_ELEM_SIZE(depth) == image->widthStep )
3901     {
3902         size.width *= size.height;
3903         size.height = 1;
3904     }
3905 
3906     cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
3907     for( y = 0; y < size.height; y++ )
3908         cvWriteRawData( fs, image->imageData + y*image->widthStep, size.width, dt );
3909     cvEndWriteStruct( fs );
3910     cvEndWriteStruct( fs );
3911 }
3912 
3913 
3914 static void*
icvReadImage(CvFileStorage * fs,CvFileNode * node)3915 icvReadImage( CvFileStorage* fs, CvFileNode* node )
3916 {
3917     void* ptr = 0;
3918     IplImage* image;
3919     const char* dt;
3920     CvFileNode* data;
3921     CvFileNode* roi_node;
3922     CvSeqReader reader;
3923     CvRect roi;
3924     int y, width, height, elem_type, coi, depth;
3925     const char* origin, *data_order;
3926 
3927     width = cvReadIntByName( fs, node, "width", 0 );
3928     height = cvReadIntByName( fs, node, "height", 0 );
3929     dt = cvReadStringByName( fs, node, "dt", 0 );
3930     origin = cvReadStringByName( fs, node, "origin", 0 );
3931 
3932     if( width == 0 || height == 0 || dt == 0 || origin == 0 )
3933         CV_Error( CV_StsError, "Some of essential image attributes are absent" );
3934 
3935     elem_type = icvDecodeSimpleFormat( dt );
3936     data_order = cvReadStringByName( fs, node, "layout", "interleaved" );
3937     if( strcmp( data_order, "interleaved" ) != 0 )
3938         CV_Error( CV_StsError, "Only interleaved images can be read" );
3939 
3940     data = cvGetFileNodeByName( fs, node, "data" );
3941     if( !data )
3942         CV_Error( CV_StsError, "The image data is not found in file storage" );
3943 
3944     if( icvFileNodeSeqLen( data ) != width*height*CV_MAT_CN(elem_type) )
3945         CV_Error( CV_StsUnmatchedSizes,
3946         "The matrix size does not match to the number of stored elements" );
3947 
3948     depth = cvIplDepth(elem_type);
3949     image = cvCreateImage( cvSize(width,height), depth, CV_MAT_CN(elem_type) );
3950 
3951     roi_node = cvGetFileNodeByName( fs, node, "roi" );
3952     if( roi_node )
3953     {
3954         roi.x = cvReadIntByName( fs, roi_node, "x", 0 );
3955         roi.y = cvReadIntByName( fs, roi_node, "y", 0 );
3956         roi.width = cvReadIntByName( fs, roi_node, "width", 0 );
3957         roi.height = cvReadIntByName( fs, roi_node, "height", 0 );
3958         coi = cvReadIntByName( fs, roi_node, "coi", 0 );
3959 
3960         cvSetImageROI( image, roi );
3961         cvSetImageCOI( image, coi );
3962     }
3963 
3964     if( width*CV_ELEM_SIZE(elem_type) == image->widthStep )
3965     {
3966         width *= height;
3967         height = 1;
3968     }
3969 
3970     width *= CV_MAT_CN(elem_type);
3971     cvStartReadRawData( fs, data, &reader );
3972     for( y = 0; y < height; y++ )
3973     {
3974         cvReadRawDataSlice( fs, &reader, width,
3975             image->imageData + y*image->widthStep, dt );
3976     }
3977 
3978     ptr = image;
3979     return ptr;
3980 }
3981 
3982 
3983 /******************************* CvSeq ******************************/
3984 
3985 static int
icvIsSeq(const void * ptr)3986 icvIsSeq( const void* ptr )
3987 {
3988     return CV_IS_SEQ(ptr);
3989 }
3990 
3991 
3992 static void
icvReleaseSeq(void ** ptr)3993 icvReleaseSeq( void** ptr )
3994 {
3995     if( !ptr )
3996         CV_Error( CV_StsNullPtr, "NULL double pointer" );
3997     *ptr = 0; // it's impossible now to release seq, so just clear the pointer
3998 }
3999 
4000 
4001 static void*
icvCloneSeq(const void * ptr)4002 icvCloneSeq( const void* ptr )
4003 {
4004     return cvSeqSlice( (CvSeq*)ptr, CV_WHOLE_SEQ,
4005                        0 /* use the same storage as for the original sequence */, 1 );
4006 }
4007 
4008 
4009 static void
icvWriteHeaderData(CvFileStorage * fs,const CvSeq * seq,CvAttrList * attr,int initial_header_size)4010 icvWriteHeaderData( CvFileStorage* fs, const CvSeq* seq,
4011                     CvAttrList* attr, int initial_header_size )
4012 {
4013     char header_dt_buf[128];
4014     const char* header_dt = cvAttrValue( attr, "header_dt" );
4015 
4016     if( header_dt )
4017     {
4018         int dt_header_size;
4019         dt_header_size = icvCalcElemSize( header_dt, initial_header_size );
4020         if( dt_header_size > seq->header_size )
4021             CV_Error( CV_StsUnmatchedSizes,
4022             "The size of header calculated from \"header_dt\" is greater than header_size" );
4023     }
4024     else if( seq->header_size > initial_header_size )
4025     {
4026         if( CV_IS_SEQ(seq) && CV_IS_SEQ_POINT_SET(seq) &&
4027             seq->header_size == sizeof(CvPoint2DSeq) &&
4028             seq->elem_size == sizeof(int)*2 )
4029         {
4030             CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
4031 
4032             cvStartWriteStruct( fs, "rect", CV_NODE_MAP + CV_NODE_FLOW );
4033             cvWriteInt( fs, "x", point_seq->rect.x );
4034             cvWriteInt( fs, "y", point_seq->rect.y );
4035             cvWriteInt( fs, "width", point_seq->rect.width );
4036             cvWriteInt( fs, "height", point_seq->rect.height );
4037             cvEndWriteStruct( fs );
4038             cvWriteInt( fs, "color", point_seq->color );
4039         }
4040         else if( CV_IS_SEQ(seq) && CV_IS_SEQ_CHAIN(seq) &&
4041                  CV_MAT_TYPE(seq->flags) == CV_8UC1 )
4042         {
4043             CvChain* chain = (CvChain*)seq;
4044 
4045             cvStartWriteStruct( fs, "origin", CV_NODE_MAP + CV_NODE_FLOW );
4046             cvWriteInt( fs, "x", chain->origin.x );
4047             cvWriteInt( fs, "y", chain->origin.y );
4048             cvEndWriteStruct( fs );
4049         }
4050         else
4051         {
4052             unsigned extra_size = seq->header_size - initial_header_size;
4053             // a heuristic to provide nice defaults for sequences of int's & float's
4054             if( extra_size % sizeof(int) == 0 )
4055                 sprintf( header_dt_buf, "%ui", (unsigned)(extra_size/sizeof(int)) );
4056             else
4057                 sprintf( header_dt_buf, "%uu", extra_size );
4058             header_dt = header_dt_buf;
4059         }
4060     }
4061 
4062     if( header_dt )
4063     {
4064         cvWriteString( fs, "header_dt", header_dt, 0 );
4065         cvStartWriteStruct( fs, "header_user_data", CV_NODE_SEQ + CV_NODE_FLOW );
4066         cvWriteRawData( fs, (uchar*)seq + sizeof(CvSeq), 1, header_dt );
4067         cvEndWriteStruct( fs );
4068     }
4069 }
4070 
4071 
4072 static char*
icvGetFormat(const CvSeq * seq,const char * dt_key,CvAttrList * attr,int initial_elem_size,char * dt_buf)4073 icvGetFormat( const CvSeq* seq, const char* dt_key, CvAttrList* attr,
4074               int initial_elem_size, char* dt_buf )
4075 {
4076     char* dt = 0;
4077     dt = (char*)cvAttrValue( attr, dt_key );
4078 
4079     if( dt )
4080     {
4081         int dt_elem_size;
4082         dt_elem_size = icvCalcElemSize( dt, initial_elem_size );
4083         if( dt_elem_size != seq->elem_size )
4084             CV_Error( CV_StsUnmatchedSizes,
4085             "The size of element calculated from \"dt\" and "
4086             "the elem_size do not match" );
4087     }
4088     else if( CV_MAT_TYPE(seq->flags) != 0 || seq->elem_size == 1 )
4089     {
4090         if( CV_ELEM_SIZE(seq->flags) != seq->elem_size )
4091             CV_Error( CV_StsUnmatchedSizes,
4092             "Size of sequence element (elem_size) is inconsistent with seq->flags" );
4093         dt = icvEncodeFormat( CV_MAT_TYPE(seq->flags), dt_buf );
4094     }
4095     else if( seq->elem_size > initial_elem_size )
4096     {
4097         unsigned extra_elem_size = seq->elem_size - initial_elem_size;
4098         // a heuristic to provide nice defaults for sequences of int's & float's
4099         if( extra_elem_size % sizeof(int) == 0 )
4100             sprintf( dt_buf, "%ui", (unsigned)(extra_elem_size/sizeof(int)) );
4101         else
4102             sprintf( dt_buf, "%uu", extra_elem_size );
4103         dt = dt_buf;
4104     }
4105 
4106     return dt;
4107 }
4108 
4109 
4110 static void
icvWriteSeq(CvFileStorage * fs,const char * name,const void * struct_ptr,CvAttrList attr,int level)4111 icvWriteSeq( CvFileStorage* fs, const char* name,
4112              const void* struct_ptr,
4113              CvAttrList attr, int level )
4114 {
4115     const CvSeq* seq = (CvSeq*)struct_ptr;
4116     CvSeqBlock* block;
4117     char buf[128];
4118     char dt_buf[128], *dt;
4119 
4120     assert( CV_IS_SEQ( seq ));
4121     cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ );
4122 
4123     if( level >= 0 )
4124         cvWriteInt( fs, "level", level );
4125 
4126     dt = icvGetFormat( seq, "dt", &attr, 0, dt_buf );
4127 
4128     strcpy(buf, "");
4129     if( CV_IS_SEQ_CLOSED(seq) )
4130         strcat(buf, " closed");
4131     if( CV_IS_SEQ_HOLE(seq) )
4132         strcat(buf, " hole");
4133     if( CV_IS_SEQ_CURVE(seq) )
4134         strcat(buf, " curve");
4135     if( CV_SEQ_ELTYPE(seq) == 0 && seq->elem_size != 1 )
4136         strcat(buf, " untyped");
4137 
4138     cvWriteString( fs, "flags", buf + (buf[0] ? 1 : 0), 1 );
4139 
4140     cvWriteInt( fs, "count", seq->total );
4141 
4142     cvWriteString( fs, "dt", dt, 0 );
4143 
4144     icvWriteHeaderData( fs, seq, &attr, sizeof(CvSeq) );
4145     cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
4146 
4147     for( block = seq->first; block; block = block->next )
4148     {
4149         cvWriteRawData( fs, block->data, block->count, dt );
4150         if( block == seq->first->prev )
4151             break;
4152     }
4153     cvEndWriteStruct( fs );
4154     cvEndWriteStruct( fs );
4155 }
4156 
4157 
4158 static void
icvWriteSeqTree(CvFileStorage * fs,const char * name,const void * struct_ptr,CvAttrList attr)4159 icvWriteSeqTree( CvFileStorage* fs, const char* name,
4160                  const void* struct_ptr, CvAttrList attr )
4161 {
4162     const CvSeq* seq = (CvSeq*)struct_ptr;
4163     const char* recursive_value = cvAttrValue( &attr, "recursive" );
4164     int is_recursive = recursive_value &&
4165                        strcmp(recursive_value,"0") != 0 &&
4166                        strcmp(recursive_value,"false") != 0 &&
4167                        strcmp(recursive_value,"False") != 0 &&
4168                        strcmp(recursive_value,"FALSE") != 0;
4169 
4170     assert( CV_IS_SEQ( seq ));
4171 
4172     if( !is_recursive )
4173     {
4174         icvWriteSeq( fs, name, seq, attr, -1 );
4175     }
4176     else
4177     {
4178         CvTreeNodeIterator tree_iterator;
4179 
4180         cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ_TREE );
4181         cvStartWriteStruct( fs, "sequences", CV_NODE_SEQ );
4182         cvInitTreeNodeIterator( &tree_iterator, seq, INT_MAX );
4183 
4184         for(;;)
4185         {
4186             if( !tree_iterator.node )
4187                 break;
4188             icvWriteSeq( fs, 0, tree_iterator.node, attr, tree_iterator.level );
4189             cvNextTreeNode( &tree_iterator );
4190         }
4191 
4192         cvEndWriteStruct( fs );
4193         cvEndWriteStruct( fs );
4194     }
4195 }
4196 
4197 
4198 static void*
icvReadSeq(CvFileStorage * fs,CvFileNode * node)4199 icvReadSeq( CvFileStorage* fs, CvFileNode* node )
4200 {
4201     void* ptr = 0;
4202     CvSeq* seq;
4203     CvSeqBlock* block;
4204     CvFileNode *data, *header_node, *rect_node, *origin_node;
4205     CvSeqReader reader;
4206     int total, flags;
4207     int elem_size, header_size = sizeof(CvSeq);
4208     int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
4209     int items_per_elem = 0;
4210     const char* flags_str;
4211     const char* header_dt;
4212     const char* dt;
4213     char* endptr = 0;
4214 
4215     flags_str = cvReadStringByName( fs, node, "flags", 0 );
4216     total = cvReadIntByName( fs, node, "count", -1 );
4217     dt = cvReadStringByName( fs, node, "dt", 0 );
4218 
4219     if( !flags_str || total == -1 || !dt )
4220         CV_Error( CV_StsError, "Some of essential sequence attributes are absent" );
4221 
4222     flags = CV_SEQ_MAGIC_VAL;
4223 
4224     if( cv_isdigit(flags_str[0]) )
4225     {
4226         const int OLD_SEQ_ELTYPE_BITS = 9;
4227         const int OLD_SEQ_ELTYPE_MASK = (1 << OLD_SEQ_ELTYPE_BITS) - 1;
4228         const int OLD_SEQ_KIND_BITS = 3;
4229         const int OLD_SEQ_KIND_MASK = ((1 << OLD_SEQ_KIND_BITS) - 1) << OLD_SEQ_ELTYPE_BITS;
4230         const int OLD_SEQ_KIND_CURVE = 1 << OLD_SEQ_ELTYPE_BITS;
4231         const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS;
4232         const int OLD_SEQ_FLAG_CLOSED = 1 << OLD_SEQ_FLAG_SHIFT;
4233         const int OLD_SEQ_FLAG_HOLE = 8 << OLD_SEQ_FLAG_SHIFT;
4234 
4235         int flags0 = (int)strtol( flags_str, &endptr, 16 );
4236         if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SEQ_MAGIC_VAL )
4237             CV_Error( CV_StsError, "The sequence flags are invalid" );
4238         if( (flags0 & OLD_SEQ_KIND_MASK) == OLD_SEQ_KIND_CURVE )
4239             flags |= CV_SEQ_KIND_CURVE;
4240         if( flags0 & OLD_SEQ_FLAG_CLOSED )
4241             flags |= CV_SEQ_FLAG_CLOSED;
4242         if( flags0 & OLD_SEQ_FLAG_HOLE )
4243             flags |= CV_SEQ_FLAG_HOLE;
4244         flags |= flags0 & OLD_SEQ_ELTYPE_MASK;
4245     }
4246     else
4247     {
4248         if( strstr(flags_str, "curve") )
4249             flags |= CV_SEQ_KIND_CURVE;
4250         if( strstr(flags_str, "closed") )
4251             flags |= CV_SEQ_FLAG_CLOSED;
4252         if( strstr(flags_str, "hole") )
4253             flags |= CV_SEQ_FLAG_HOLE;
4254         if( !strstr(flags_str, "untyped") )
4255         {
4256             try
4257             {
4258                 flags |= icvDecodeSimpleFormat(dt);
4259             }
4260             catch(...)
4261             {
4262             }
4263         }
4264     }
4265 
4266     header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
4267     header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
4268 
4269     if( (header_dt != 0) ^ (header_node != 0) )
4270         CV_Error( CV_StsError,
4271         "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
4272 
4273     rect_node = cvGetFileNodeByName( fs, node, "rect" );
4274     origin_node = cvGetFileNodeByName( fs, node, "origin" );
4275 
4276     if( (header_node != 0) + (rect_node != 0) + (origin_node != 0) > 1 )
4277         CV_Error( CV_StsError, "Only one of \"header_user_data\", \"rect\" and \"origin\" tags may occur" );
4278 
4279     if( header_dt )
4280     {
4281         header_size = icvCalcElemSize( header_dt, header_size );
4282     }
4283     else if( rect_node )
4284         header_size = sizeof(CvPoint2DSeq);
4285     else if( origin_node )
4286         header_size = sizeof(CvChain);
4287 
4288     elem_size = icvCalcElemSize( dt, 0 );
4289     seq = cvCreateSeq( flags, header_size, elem_size, fs->dststorage );
4290 
4291     if( header_node )
4292     {
4293         cvReadRawData( fs, header_node, (char*)seq + sizeof(CvSeq), header_dt );
4294     }
4295     else if( rect_node )
4296     {
4297         CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
4298         point_seq->rect.x = cvReadIntByName( fs, rect_node, "x", 0 );
4299         point_seq->rect.y = cvReadIntByName( fs, rect_node, "y", 0 );
4300         point_seq->rect.width = cvReadIntByName( fs, rect_node, "width", 0 );
4301         point_seq->rect.height = cvReadIntByName( fs, rect_node, "height", 0 );
4302         point_seq->color = cvReadIntByName( fs, node, "color", 0 );
4303     }
4304     else if( origin_node )
4305     {
4306         CvChain* chain = (CvChain*)seq;
4307         chain->origin.x = cvReadIntByName( fs, origin_node, "x", 0 );
4308         chain->origin.y = cvReadIntByName( fs, origin_node, "y", 0 );
4309     }
4310 
4311     cvSeqPushMulti( seq, 0, total, 0 );
4312     fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
4313     fmt_pair_count *= 2;
4314     for( i = 0; i < fmt_pair_count; i += 2 )
4315         items_per_elem += fmt_pairs[i];
4316 
4317     data = cvGetFileNodeByName( fs, node, "data" );
4318     if( !data )
4319         CV_Error( CV_StsError, "The image data is not found in file storage" );
4320 
4321     if( icvFileNodeSeqLen( data ) != total*items_per_elem )
4322         CV_Error( CV_StsError, "The number of stored elements does not match to \"count\"" );
4323 
4324     cvStartReadRawData( fs, data, &reader );
4325     for( block = seq->first; block; block = block->next )
4326     {
4327         int delta = block->count*items_per_elem;
4328         cvReadRawDataSlice( fs, &reader, delta, block->data, dt );
4329         if( block == seq->first->prev )
4330             break;
4331     }
4332 
4333     ptr = seq;
4334     return ptr;
4335 }
4336 
4337 
4338 static void*
icvReadSeqTree(CvFileStorage * fs,CvFileNode * node)4339 icvReadSeqTree( CvFileStorage* fs, CvFileNode* node )
4340 {
4341     void* ptr = 0;
4342     CvFileNode *sequences_node = cvGetFileNodeByName( fs, node, "sequences" );
4343     CvSeq* sequences;
4344     CvSeq* root = 0;
4345     CvSeq* parent = 0;
4346     CvSeq* prev_seq = 0;
4347     CvSeqReader reader;
4348     int i, total;
4349     int prev_level = 0;
4350 
4351     if( !sequences_node || !CV_NODE_IS_SEQ(sequences_node->tag) )
4352         CV_Error( CV_StsParseError,
4353         "opencv-sequence-tree instance should contain a field \"sequences\" that should be a sequence" );
4354 
4355     sequences = sequences_node->data.seq;
4356     total = sequences->total;
4357 
4358     cvStartReadSeq( sequences, &reader, 0 );
4359     for( i = 0; i < total; i++ )
4360     {
4361         CvFileNode* elem = (CvFileNode*)reader.ptr;
4362         CvSeq* seq;
4363         int level;
4364         seq = (CvSeq*)cvRead( fs, elem );
4365         level = cvReadIntByName( fs, elem, "level", -1 );
4366         if( level < 0 )
4367             CV_Error( CV_StsParseError, "All the sequence tree nodes should contain \"level\" field" );
4368         if( !root )
4369             root = seq;
4370         if( level > prev_level )
4371         {
4372             assert( level == prev_level + 1 );
4373             parent = prev_seq;
4374             prev_seq = 0;
4375             if( parent )
4376                 parent->v_next = seq;
4377         }
4378         else if( level < prev_level )
4379         {
4380             for( ; prev_level > level; prev_level-- )
4381                 prev_seq = prev_seq->v_prev;
4382             parent = prev_seq->v_prev;
4383         }
4384         seq->h_prev = prev_seq;
4385         if( prev_seq )
4386             prev_seq->h_next = seq;
4387         seq->v_prev = parent;
4388         prev_seq = seq;
4389         prev_level = level;
4390         CV_NEXT_SEQ_ELEM( sequences->elem_size, reader );
4391     }
4392 
4393     ptr = root;
4394     return ptr;
4395 }
4396 
4397 /******************************* CvGraph ******************************/
4398 
4399 static int
icvIsGraph(const void * ptr)4400 icvIsGraph( const void* ptr )
4401 {
4402     return CV_IS_GRAPH(ptr);
4403 }
4404 
4405 
4406 static void
icvReleaseGraph(void ** ptr)4407 icvReleaseGraph( void** ptr )
4408 {
4409     if( !ptr )
4410         CV_Error( CV_StsNullPtr, "NULL double pointer" );
4411 
4412     *ptr = 0; // it's impossible now to release graph, so just clear the pointer
4413 }
4414 
4415 
4416 static void*
icvCloneGraph(const void * ptr)4417 icvCloneGraph( const void* ptr )
4418 {
4419     return cvCloneGraph( (const CvGraph*)ptr, 0 );
4420 }
4421 
4422 
4423 static void
icvWriteGraph(CvFileStorage * fs,const char * name,const void * struct_ptr,CvAttrList attr)4424 icvWriteGraph( CvFileStorage* fs, const char* name,
4425                const void* struct_ptr, CvAttrList attr )
4426 {
4427     int* flag_buf = 0;
4428     char* write_buf = 0;
4429     const CvGraph* graph = (const CvGraph*)struct_ptr;
4430     CvSeqReader reader;
4431     char buf[128];
4432     int i, k, vtx_count, edge_count;
4433     char vtx_dt_buf[128], *vtx_dt;
4434     char edge_dt_buf[128], *edge_dt;
4435     int write_buf_size;
4436 
4437     assert( CV_IS_GRAPH(graph) );
4438     vtx_count = cvGraphGetVtxCount( graph );
4439     edge_count = cvGraphGetEdgeCount( graph );
4440     flag_buf = (int*)cvAlloc( vtx_count*sizeof(flag_buf[0]));
4441 
4442     // count vertices
4443     cvStartReadSeq( (CvSeq*)graph, &reader );
4444     for( i = 0, k = 0; i < graph->total; i++ )
4445     {
4446         if( CV_IS_SET_ELEM( reader.ptr ))
4447         {
4448             CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
4449             flag_buf[k] = vtx->flags;
4450             vtx->flags = k++;
4451         }
4452         CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
4453     }
4454 
4455     // write header
4456     cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_GRAPH );
4457 
4458     cvWriteString(fs, "flags", CV_IS_GRAPH_ORIENTED(graph) ? "oriented" : "", 1);
4459 
4460     cvWriteInt( fs, "vertex_count", vtx_count );
4461     vtx_dt = icvGetFormat( (CvSeq*)graph, "vertex_dt",
4462                     &attr, sizeof(CvGraphVtx), vtx_dt_buf );
4463     if( vtx_dt )
4464         cvWriteString( fs, "vertex_dt", vtx_dt, 0 );
4465 
4466     cvWriteInt( fs, "edge_count", edge_count );
4467     edge_dt = icvGetFormat( (CvSeq*)graph->edges, "edge_dt",
4468                                 &attr, sizeof(CvGraphEdge), buf );
4469     sprintf( edge_dt_buf, "2if%s", edge_dt ? edge_dt : "" );
4470     edge_dt = edge_dt_buf;
4471     cvWriteString( fs, "edge_dt", edge_dt, 0 );
4472 
4473     icvWriteHeaderData( fs, (CvSeq*)graph, &attr, sizeof(CvGraph) );
4474 
4475     write_buf_size = MAX( 3*graph->elem_size, 1 << 16 );
4476     write_buf_size = MAX( 3*graph->edges->elem_size, write_buf_size );
4477     write_buf = (char*)cvAlloc( write_buf_size );
4478 
4479     // as vertices and edges are written in similar way,
4480     // do it as a parametrized 2-iteration loop
4481     for( k = 0; k < 2; k++ )
4482     {
4483         const char* dt = k == 0 ? vtx_dt : edge_dt;
4484         if( dt )
4485         {
4486             CvSet* data = k == 0 ? (CvSet*)graph : graph->edges;
4487             int elem_size = data->elem_size;
4488             int write_elem_size = icvCalcElemSize( dt, 0 );
4489             char* src_ptr = write_buf;
4490             int write_max = write_buf_size / write_elem_size, write_count = 0;
4491 
4492             // alignment of user part of the edge data following 2if
4493             int edge_user_align = sizeof(float);
4494 
4495             if( k == 1 )
4496             {
4497                 int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
4498                 fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
4499                 if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[2*2+1]) >= (int)sizeof(double))
4500                     edge_user_align = sizeof(double);
4501             }
4502 
4503             cvStartWriteStruct( fs, k == 0 ? "vertices" : "edges",
4504                                 CV_NODE_SEQ + CV_NODE_FLOW );
4505             cvStartReadSeq( (CvSeq*)data, &reader );
4506             for( i = 0; i < data->total; i++ )
4507             {
4508                 if( CV_IS_SET_ELEM( reader.ptr ))
4509                 {
4510                     if( k == 0 ) // vertices
4511                         memcpy( src_ptr, reader.ptr + sizeof(CvGraphVtx), write_elem_size );
4512                     else
4513                     {
4514                         CvGraphEdge* edge = (CvGraphEdge*)reader.ptr;
4515                         src_ptr = (char*)cvAlignPtr( src_ptr, sizeof(int) );
4516                         ((int*)src_ptr)[0] = edge->vtx[0]->flags;
4517                         ((int*)src_ptr)[1] = edge->vtx[1]->flags;
4518                         *(float*)(src_ptr + sizeof(int)*2) = edge->weight;
4519                         if( elem_size > (int)sizeof(CvGraphEdge) )
4520                         {
4521                             char* src_ptr2 = (char*)cvAlignPtr( src_ptr + 2*sizeof(int)
4522                                                 + sizeof(float), edge_user_align );
4523                             memcpy( src_ptr2, edge + 1, elem_size - sizeof(CvGraphEdge) );
4524                         }
4525                     }
4526                     src_ptr += write_elem_size;
4527                     if( ++write_count >= write_max )
4528                     {
4529                         cvWriteRawData( fs, write_buf, write_count, dt );
4530                         write_count = 0;
4531                         src_ptr = write_buf;
4532                     }
4533                 }
4534                 CV_NEXT_SEQ_ELEM( data->elem_size, reader );
4535             }
4536 
4537             if( write_count > 0 )
4538                 cvWriteRawData( fs, write_buf, write_count, dt );
4539             cvEndWriteStruct( fs );
4540         }
4541     }
4542 
4543     cvEndWriteStruct( fs );
4544 
4545     // final stage. restore the graph flags
4546     cvStartReadSeq( (CvSeq*)graph, &reader );
4547     vtx_count = 0;
4548     for( i = 0; i < graph->total; i++ )
4549     {
4550         if( CV_IS_SET_ELEM( reader.ptr ))
4551             ((CvGraphVtx*)reader.ptr)->flags = flag_buf[vtx_count++];
4552         CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
4553     }
4554 
4555     cvFree( &write_buf );
4556     cvFree( &flag_buf );
4557 }
4558 
4559 
4560 static void*
icvReadGraph(CvFileStorage * fs,CvFileNode * node)4561 icvReadGraph( CvFileStorage* fs, CvFileNode* node )
4562 {
4563     void* ptr = 0;
4564     char* read_buf = 0;
4565     CvGraphVtx** vtx_buf = 0;
4566     CvGraph* graph;
4567     CvFileNode *header_node, *vtx_node, *edge_node;
4568     int flags, vtx_count, edge_count;
4569     int vtx_size = sizeof(CvGraphVtx), edge_size, header_size = sizeof(CvGraph);
4570     int src_vtx_size = 0, src_edge_size;
4571     int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
4572     int vtx_items_per_elem = 0, edge_items_per_elem = 0;
4573     int edge_user_align = sizeof(float);
4574     int read_buf_size;
4575     int i, k;
4576     const char* flags_str;
4577     const char* header_dt;
4578     const char* vtx_dt;
4579     const char* edge_dt;
4580     char* endptr = 0;
4581 
4582     flags_str = cvReadStringByName( fs, node, "flags", 0 );
4583     vtx_dt = cvReadStringByName( fs, node, "vertex_dt", 0 );
4584     edge_dt = cvReadStringByName( fs, node, "edge_dt", 0 );
4585     vtx_count = cvReadIntByName( fs, node, "vertex_count", -1 );
4586     edge_count = cvReadIntByName( fs, node, "edge_count", -1 );
4587 
4588     if( !flags_str || vtx_count == -1 || edge_count == -1 || !edge_dt )
4589         CV_Error( CV_StsError, "Some of essential graph attributes are absent" );
4590 
4591     flags = CV_SET_MAGIC_VAL + CV_GRAPH;
4592 
4593     if( isxdigit(flags_str[0]) )
4594     {
4595         const int OLD_SEQ_ELTYPE_BITS = 9;
4596         const int OLD_SEQ_KIND_BITS = 3;
4597         const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS;
4598         const int OLD_GRAPH_FLAG_ORIENTED = 1 << OLD_SEQ_FLAG_SHIFT;
4599 
4600         int flags0 = (int)strtol( flags_str, &endptr, 16 );
4601         if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SET_MAGIC_VAL )
4602             CV_Error( CV_StsError, "The sequence flags are invalid" );
4603         if( flags0 & OLD_GRAPH_FLAG_ORIENTED )
4604             flags |= CV_GRAPH_FLAG_ORIENTED;
4605     }
4606     else
4607     {
4608         if( strstr(flags_str, "oriented") )
4609             flags |= CV_GRAPH_FLAG_ORIENTED;
4610     }
4611 
4612     header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
4613     header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
4614 
4615     if( (header_dt != 0) ^ (header_node != 0) )
4616         CV_Error( CV_StsError,
4617         "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
4618 
4619     if( header_dt )
4620         header_size = icvCalcElemSize( header_dt, header_size );
4621 
4622     if( vtx_dt )
4623     {
4624         src_vtx_size = icvCalcElemSize( vtx_dt, 0 );
4625         vtx_size = icvCalcElemSize( vtx_dt, vtx_size );
4626         fmt_pair_count = icvDecodeFormat( edge_dt,
4627                             fmt_pairs, CV_FS_MAX_FMT_PAIRS );
4628         fmt_pair_count *= 2;
4629         for( i = 0; i < fmt_pair_count; i += 2 )
4630             vtx_items_per_elem += fmt_pairs[i];
4631     }
4632 
4633     {
4634         char dst_edge_dt_buf[128];
4635         const char* dst_edge_dt = 0;
4636 
4637         fmt_pair_count = icvDecodeFormat( edge_dt,
4638                             fmt_pairs, CV_FS_MAX_FMT_PAIRS );
4639         if( fmt_pair_count < 2 ||
4640             fmt_pairs[0] != 2 || fmt_pairs[1] != CV_32S ||
4641             fmt_pairs[2] < 1 || fmt_pairs[3] != CV_32F )
4642             CV_Error( CV_StsBadArg,
4643             "Graph edges should start with 2 integers and a float" );
4644 
4645         // alignment of user part of the edge data following 2if
4646         if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[5]) >= (int)sizeof(double))
4647             edge_user_align = sizeof(double);
4648 
4649         fmt_pair_count *= 2;
4650         for( i = 0; i < fmt_pair_count; i += 2 )
4651             edge_items_per_elem += fmt_pairs[i];
4652 
4653         if( edge_dt[2] == 'f' || (edge_dt[2] == '1' && edge_dt[3] == 'f') )
4654             dst_edge_dt = edge_dt + 3 + cv_isdigit(edge_dt[2]);
4655         else
4656         {
4657             int val = (int)strtol( edge_dt + 2, &endptr, 10 );
4658             sprintf( dst_edge_dt_buf, "%df%s", val-1, endptr );
4659             dst_edge_dt = dst_edge_dt_buf;
4660         }
4661 
4662         edge_size = icvCalcElemSize( dst_edge_dt, sizeof(CvGraphEdge) );
4663         src_edge_size = icvCalcElemSize( edge_dt, 0 );
4664     }
4665 
4666     graph = cvCreateGraph( flags, header_size, vtx_size, edge_size, fs->dststorage );
4667 
4668     if( header_node )
4669         cvReadRawData( fs, header_node, (char*)graph + sizeof(CvGraph), header_dt );
4670 
4671     read_buf_size = MAX( src_vtx_size*3, 1 << 16 );
4672     read_buf_size = MAX( src_edge_size*3, read_buf_size );
4673     read_buf = (char*)cvAlloc( read_buf_size );
4674     vtx_buf = (CvGraphVtx**)cvAlloc( vtx_count * sizeof(vtx_buf[0]) );
4675 
4676     vtx_node = cvGetFileNodeByName( fs, node, "vertices" );
4677     edge_node = cvGetFileNodeByName( fs, node, "edges" );
4678     if( !edge_node )
4679         CV_Error( CV_StsBadArg, "No edges data" );
4680     if( vtx_dt && !vtx_node )
4681         CV_Error( CV_StsBadArg, "No vertices data" );
4682 
4683     // as vertices and edges are read in similar way,
4684     // do it as a parametrized 2-iteration loop
4685     for( k = 0; k < 2; k++ )
4686     {
4687         const char* dt = k == 0 ? vtx_dt : edge_dt;
4688         int elem_size = k == 0 ? vtx_size : edge_size;
4689         int src_elem_size = k == 0 ? src_vtx_size : src_edge_size;
4690         int items_per_elem = k == 0 ? vtx_items_per_elem : edge_items_per_elem;
4691         int elem_count = k == 0 ? vtx_count : edge_count;
4692         char* dst_ptr = read_buf;
4693         int read_max = read_buf_size /MAX(src_elem_size, 1), read_count = 0;
4694         CvSeqReader reader;
4695         if(dt)
4696             cvStartReadRawData( fs, k == 0 ? vtx_node : edge_node, &reader );
4697 
4698         for( i = 0; i < elem_count; i++ )
4699         {
4700             if( read_count == 0 && dt )
4701             {
4702                 int count = MIN( elem_count - i, read_max )*items_per_elem;
4703                 cvReadRawDataSlice( fs, &reader, count, read_buf, dt );
4704                 read_count = count;
4705                 dst_ptr = read_buf;
4706             }
4707 
4708             if( k == 0 )
4709             {
4710                 CvGraphVtx* vtx;
4711                 cvGraphAddVtx( graph, 0, &vtx );
4712                 vtx_buf[i] = vtx;
4713                 if( dt )
4714                     memcpy( vtx + 1, dst_ptr, src_elem_size );
4715             }
4716             else
4717             {
4718                 CvGraphEdge* edge = 0;
4719                 int vtx1 = ((int*)dst_ptr)[0];
4720                 int vtx2 = ((int*)dst_ptr)[1];
4721                 int result;
4722 
4723                 if( (unsigned)vtx1 >= (unsigned)vtx_count ||
4724                     (unsigned)vtx2 >= (unsigned)vtx_count )
4725                     CV_Error( CV_StsOutOfRange,
4726                     "Some of stored vertex indices are out of range" );
4727 
4728                 result = cvGraphAddEdgeByPtr( graph,
4729                     vtx_buf[vtx1], vtx_buf[vtx2], 0, &edge );
4730 
4731                 if( result == 0 )
4732                     CV_Error( CV_StsBadArg, "Duplicated edge has occured" );
4733 
4734                 edge->weight = *(float*)(dst_ptr + sizeof(int)*2);
4735                 if( elem_size > (int)sizeof(CvGraphEdge) )
4736                 {
4737                     char* dst_ptr2 = (char*)cvAlignPtr( dst_ptr + sizeof(int)*2 +
4738                                                 sizeof(float), edge_user_align );
4739                     memcpy( edge + 1, dst_ptr2, elem_size - sizeof(CvGraphEdge) );
4740                 }
4741             }
4742 
4743             dst_ptr += src_elem_size;
4744             read_count--;
4745         }
4746     }
4747 
4748     ptr = graph;
4749     cvFree( &read_buf );
4750     cvFree( &vtx_buf );
4751 
4752     return ptr;
4753 }
4754 
4755 /****************************************************************************************\
4756 *                                    RTTI Functions                                      *
4757 \****************************************************************************************/
4758 
4759 CvTypeInfo *CvType::first = 0, *CvType::last = 0;
4760 
CvType(const char * type_name,CvIsInstanceFunc is_instance,CvReleaseFunc release,CvReadFunc read,CvWriteFunc write,CvCloneFunc clone)4761 CvType::CvType( const char* type_name,
4762                 CvIsInstanceFunc is_instance, CvReleaseFunc release,
4763                 CvReadFunc read, CvWriteFunc write, CvCloneFunc clone )
4764 {
4765     CvTypeInfo _info;
4766     _info.flags = 0;
4767     _info.header_size = sizeof(_info);
4768     _info.type_name = type_name;
4769     _info.prev = _info.next = 0;
4770     _info.is_instance = is_instance;
4771     _info.release = release;
4772     _info.clone = clone;
4773     _info.read = read;
4774     _info.write = write;
4775 
4776     cvRegisterType( &_info );
4777     info = first;
4778 }
4779 
4780 
~CvType()4781 CvType::~CvType()
4782 {
4783     cvUnregisterType( info->type_name );
4784 }
4785 
4786 
4787 CvType seq_type( CV_TYPE_NAME_SEQ, icvIsSeq, icvReleaseSeq, icvReadSeq,
4788                  icvWriteSeqTree /* this is the entry point for
4789                  writing a single sequence too */, icvCloneSeq );
4790 
4791 CvType seq_tree_type( CV_TYPE_NAME_SEQ_TREE, icvIsSeq, icvReleaseSeq,
4792                       icvReadSeqTree, icvWriteSeqTree, icvCloneSeq );
4793 
4794 CvType seq_graph_type( CV_TYPE_NAME_GRAPH, icvIsGraph, icvReleaseGraph,
4795                        icvReadGraph, icvWriteGraph, icvCloneGraph );
4796 
4797 CvType sparse_mat_type( CV_TYPE_NAME_SPARSE_MAT, icvIsSparseMat,
4798                         (CvReleaseFunc)cvReleaseSparseMat, icvReadSparseMat,
4799                         icvWriteSparseMat, (CvCloneFunc)cvCloneSparseMat );
4800 
4801 CvType image_type( CV_TYPE_NAME_IMAGE, icvIsImage, (CvReleaseFunc)cvReleaseImage,
4802                    icvReadImage, icvWriteImage, (CvCloneFunc)cvCloneImage );
4803 
4804 CvType mat_type( CV_TYPE_NAME_MAT, icvIsMat, (CvReleaseFunc)cvReleaseMat,
4805                  icvReadMat, icvWriteMat, (CvCloneFunc)cvCloneMat );
4806 
4807 CvType matnd_type( CV_TYPE_NAME_MATND, icvIsMatND, (CvReleaseFunc)cvReleaseMatND,
4808                    icvReadMatND, icvWriteMatND, (CvCloneFunc)cvCloneMatND );
4809 
4810 CV_IMPL  void
cvRegisterType(const CvTypeInfo * _info)4811 cvRegisterType( const CvTypeInfo* _info )
4812 {
4813     CvTypeInfo* info = 0;
4814     int i, len;
4815     char c;
4816 
4817     //if( !CvType::first )
4818     //    icvCreateStandardTypes();
4819 
4820     if( !_info || _info->header_size != sizeof(CvTypeInfo) )
4821         CV_Error( CV_StsBadSize, "Invalid type info" );
4822 
4823     if( !_info->is_instance || !_info->release ||
4824         !_info->read || !_info->write )
4825         CV_Error( CV_StsNullPtr,
4826         "Some of required function pointers "
4827         "(is_instance, release, read or write) are NULL");
4828 
4829     c = _info->type_name[0];
4830     if( !cv_isalpha(c) && c != '_' )
4831         CV_Error( CV_StsBadArg, "Type name should start with a letter or _" );
4832 
4833     len = (int)strlen(_info->type_name);
4834 
4835     for( i = 0; i < len; i++ )
4836     {
4837         c = _info->type_name[i];
4838         if( !cv_isalnum(c) && c != '-' && c != '_' )
4839             CV_Error( CV_StsBadArg,
4840             "Type name should contain only letters, digits, - and _" );
4841     }
4842 
4843     info = (CvTypeInfo*)cvAlloc( sizeof(*info) + len + 1 );
4844 
4845     *info = *_info;
4846     info->type_name = (char*)(info + 1);
4847     memcpy( (char*)info->type_name, _info->type_name, len + 1 );
4848 
4849     info->flags = 0;
4850     info->next = CvType::first;
4851     info->prev = 0;
4852     if( CvType::first )
4853         CvType::first->prev = info;
4854     else
4855         CvType::last = info;
4856     CvType::first = info;
4857 }
4858 
4859 
4860 CV_IMPL void
cvUnregisterType(const char * type_name)4861 cvUnregisterType( const char* type_name )
4862 {
4863     CvTypeInfo* info;
4864 
4865     info = cvFindType( type_name );
4866     if( info )
4867     {
4868         if( info->prev )
4869             info->prev->next = info->next;
4870         else
4871             CvType::first = info->next;
4872 
4873         if( info->next )
4874             info->next->prev = info->prev;
4875         else
4876             CvType::last = info->prev;
4877 
4878         if( !CvType::first || !CvType::last )
4879             CvType::first = CvType::last = 0;
4880 
4881         cvFree( &info );
4882     }
4883 }
4884 
4885 
4886 CV_IMPL CvTypeInfo*
cvFirstType(void)4887 cvFirstType( void )
4888 {
4889     return CvType::first;
4890 }
4891 
4892 
4893 CV_IMPL CvTypeInfo*
cvFindType(const char * type_name)4894 cvFindType( const char* type_name )
4895 {
4896     CvTypeInfo* info = 0;
4897 
4898     if (type_name)
4899       for( info = CvType::first; info != 0; info = info->next )
4900         if( strcmp( info->type_name, type_name ) == 0 )
4901       break;
4902 
4903     return info;
4904 }
4905 
4906 
4907 CV_IMPL CvTypeInfo*
cvTypeOf(const void * struct_ptr)4908 cvTypeOf( const void* struct_ptr )
4909 {
4910     CvTypeInfo* info = 0;
4911 
4912     if( struct_ptr )
4913     {
4914         for( info = CvType::first; info != 0; info = info->next )
4915             if( info->is_instance( struct_ptr ))
4916                 break;
4917     }
4918 
4919     return info;
4920 }
4921 
4922 
4923 /* universal functions */
4924 CV_IMPL void
cvRelease(void ** struct_ptr)4925 cvRelease( void** struct_ptr )
4926 {
4927     CvTypeInfo* info;
4928 
4929     if( !struct_ptr )
4930         CV_Error( CV_StsNullPtr, "NULL double pointer" );
4931 
4932     if( *struct_ptr )
4933     {
4934         info = cvTypeOf( *struct_ptr );
4935         if( !info )
4936             CV_Error( CV_StsError, "Unknown object type" );
4937         if( !info->release )
4938             CV_Error( CV_StsError, "release function pointer is NULL" );
4939 
4940         info->release( struct_ptr );
4941         *struct_ptr = 0;
4942     }
4943 }
4944 
4945 
cvClone(const void * struct_ptr)4946 void* cvClone( const void* struct_ptr )
4947 {
4948     void* struct_copy = 0;
4949     CvTypeInfo* info;
4950 
4951     if( !struct_ptr )
4952         CV_Error( CV_StsNullPtr, "NULL structure pointer" );
4953 
4954     info = cvTypeOf( struct_ptr );
4955     if( !info )
4956         CV_Error( CV_StsError, "Unknown object type" );
4957     if( !info->clone )
4958         CV_Error( CV_StsError, "clone function pointer is NULL" );
4959 
4960     struct_copy = info->clone( struct_ptr );
4961     return struct_copy;
4962 }
4963 
4964 
4965 /* reads matrix, image, sequence, graph etc. */
4966 CV_IMPL void*
cvRead(CvFileStorage * fs,CvFileNode * node,CvAttrList * list)4967 cvRead( CvFileStorage* fs, CvFileNode* node, CvAttrList* list )
4968 {
4969     void* obj = 0;
4970     CV_CHECK_FILE_STORAGE( fs );
4971 
4972     if( !node )
4973         return 0;
4974 
4975     if( !CV_NODE_IS_USER(node->tag) || !node->info )
4976         CV_Error( CV_StsError, "The node does not represent a user object (unknown type?)" );
4977 
4978     obj = node->info->read( fs, node );
4979     if( list )
4980         *list = cvAttrList(0,0);
4981 
4982     return obj;
4983 }
4984 
4985 
4986 /* writes matrix, image, sequence, graph etc. */
4987 CV_IMPL void
cvWrite(CvFileStorage * fs,const char * name,const void * ptr,CvAttrList attributes)4988 cvWrite( CvFileStorage* fs, const char* name,
4989          const void* ptr, CvAttrList attributes )
4990 {
4991     CvTypeInfo* info;
4992 
4993     CV_CHECK_OUTPUT_FILE_STORAGE( fs );
4994 
4995     if( !ptr )
4996         CV_Error( CV_StsNullPtr, "Null pointer to the written object" );
4997 
4998     info = cvTypeOf( ptr );
4999     if( !info )
5000         CV_Error( CV_StsBadArg, "Unknown object" );
5001 
5002     if( !info->write )
5003         CV_Error( CV_StsBadArg, "The object does not have write function" );
5004 
5005     info->write( fs, name, ptr, attributes );
5006 }
5007 
5008 
5009 /* simple API for reading/writing data */
5010 CV_IMPL void
cvSave(const char * filename,const void * struct_ptr,const char * _name,const char * comment,CvAttrList attributes)5011 cvSave( const char* filename, const void* struct_ptr,
5012         const char* _name, const char* comment, CvAttrList attributes )
5013 {
5014     CvFileStorage* fs = 0;
5015 
5016     if( !struct_ptr )
5017         CV_Error( CV_StsNullPtr, "NULL object pointer" );
5018 
5019     fs = cvOpenFileStorage( filename, 0, CV_STORAGE_WRITE );
5020     if( !fs )
5021         CV_Error( CV_StsError, "Could not open the file storage. Check the path and permissions" );
5022 
5023     cv::String name = _name ? cv::String(_name) : cv::FileStorage::getDefaultObjectName(filename);
5024 
5025     if( comment )
5026         cvWriteComment( fs, comment, 0 );
5027     cvWrite( fs, name.c_str(), struct_ptr, attributes );
5028     cvReleaseFileStorage( &fs );
5029 }
5030 
5031 CV_IMPL void*
cvLoad(const char * filename,CvMemStorage * memstorage,const char * name,const char ** _real_name)5032 cvLoad( const char* filename, CvMemStorage* memstorage,
5033         const char* name, const char** _real_name )
5034 {
5035     void* ptr = 0;
5036     const char* real_name = 0;
5037     cv::FileStorage fs(cvOpenFileStorage(filename, memstorage, CV_STORAGE_READ));
5038 
5039     CvFileNode* node = 0;
5040 
5041     if( !fs.isOpened() )
5042         return 0;
5043 
5044     if( name )
5045     {
5046         node = cvGetFileNodeByName( *fs, 0, name );
5047     }
5048     else
5049     {
5050         int i, k;
5051         for( k = 0; k < (*fs)->roots->total; k++ )
5052         {
5053             CvSeq* seq;
5054             CvSeqReader reader;
5055 
5056             node = (CvFileNode*)cvGetSeqElem( (*fs)->roots, k );
5057             if( !CV_NODE_IS_MAP( node->tag ))
5058                 return 0;
5059             seq = node->data.seq;
5060             node = 0;
5061 
5062             cvStartReadSeq( seq, &reader, 0 );
5063 
5064             // find the first element in the map
5065             for( i = 0; i < seq->total; i++ )
5066             {
5067                 if( CV_IS_SET_ELEM( reader.ptr ))
5068                 {
5069                     node = (CvFileNode*)reader.ptr;
5070                     goto stop_search;
5071                 }
5072                 CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
5073             }
5074         }
5075 
5076 stop_search:
5077         ;
5078     }
5079 
5080     if( !node )
5081         CV_Error( CV_StsObjectNotFound, "Could not find the/an object in file storage" );
5082 
5083     real_name = cvGetFileNodeName( node );
5084     ptr = cvRead( *fs, node, 0 );
5085 
5086     // sanity check
5087     if( !memstorage && (CV_IS_SEQ( ptr ) || CV_IS_SET( ptr )) )
5088         CV_Error( CV_StsNullPtr,
5089         "NULL memory storage is passed - the loaded dynamic structure can not be stored" );
5090 
5091     if( cvGetErrStatus() < 0 )
5092     {
5093         cvRelease( (void**)&ptr );
5094         real_name = 0;
5095     }
5096 
5097     if( _real_name)
5098     {
5099     if (real_name)
5100     {
5101         *_real_name = (const char*)cvAlloc(strlen(real_name));
5102             memcpy((void*)*_real_name, real_name, strlen(real_name));
5103     } else {
5104         *_real_name = 0;
5105     }
5106     }
5107 
5108     return ptr;
5109 }
5110 
5111 
5112 ///////////////////////// new C++ interface for CvFileStorage ///////////////////////////
5113 
5114 namespace cv
5115 {
5116 
getElemSize(const String & fmt,size_t & elemSize,size_t & cn)5117 static void getElemSize( const String& fmt, size_t& elemSize, size_t& cn )
5118 {
5119     const char* dt = fmt.c_str();
5120     cn = 1;
5121     if( cv_isdigit(dt[0]) )
5122     {
5123         cn = dt[0] - '0';
5124         dt++;
5125     }
5126     char c = dt[0];
5127     elemSize = cn*(c == 'u' || c == 'c' ? sizeof(uchar) : c == 'w' || c == 's' ? sizeof(ushort) :
5128         c == 'i' ? sizeof(int) : c == 'f' ? sizeof(float) : c == 'd' ? sizeof(double) :
5129         c == 'r' ? sizeof(void*) : (size_t)0);
5130 }
5131 
FileStorage()5132 FileStorage::FileStorage()
5133 {
5134     state = UNDEFINED;
5135 }
5136 
FileStorage(const String & filename,int flags,const String & encoding)5137 FileStorage::FileStorage(const String& filename, int flags, const String& encoding)
5138 {
5139     state = UNDEFINED;
5140     open( filename, flags, encoding );
5141 }
5142 
FileStorage(CvFileStorage * _fs,bool owning)5143 FileStorage::FileStorage(CvFileStorage* _fs, bool owning)
5144 {
5145     if (owning) fs.reset(_fs);
5146     else fs = Ptr<CvFileStorage>(Ptr<CvFileStorage>(), _fs);
5147 
5148     state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
5149 }
5150 
~FileStorage()5151 FileStorage::~FileStorage()
5152 {
5153     while( structs.size() > 0 )
5154     {
5155         cvEndWriteStruct(fs);
5156         structs.pop_back();
5157     }
5158 }
5159 
open(const String & filename,int flags,const String & encoding)5160 bool FileStorage::open(const String& filename, int flags, const String& encoding)
5161 {
5162     release();
5163     fs.reset(cvOpenFileStorage( filename.c_str(), 0, flags,
5164                                 !encoding.empty() ? encoding.c_str() : 0));
5165     bool ok = isOpened();
5166     state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
5167     return ok;
5168 }
5169 
isOpened() const5170 bool FileStorage::isOpened() const
5171 {
5172     return fs && fs->is_opened;
5173 }
5174 
release()5175 void FileStorage::release()
5176 {
5177     fs.release();
5178     structs.clear();
5179     state = UNDEFINED;
5180 }
5181 
releaseAndGetString()5182 String FileStorage::releaseAndGetString()
5183 {
5184     String buf;
5185     if( fs && fs->outbuf )
5186         icvClose(fs, &buf);
5187 
5188     release();
5189     return buf;
5190 }
5191 
root(int streamidx) const5192 FileNode FileStorage::root(int streamidx) const
5193 {
5194     return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode();
5195 }
5196 
operator <<(FileStorage & fs,const String & str)5197 FileStorage& operator << (FileStorage& fs, const String& str)
5198 {
5199     enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED,
5200         VALUE_EXPECTED = FileStorage::VALUE_EXPECTED,
5201         INSIDE_MAP = FileStorage::INSIDE_MAP };
5202     const char* _str = str.c_str();
5203     if( !fs.isOpened() || !_str )
5204         return fs;
5205     if( *_str == '}' || *_str == ']' )
5206     {
5207         if( fs.structs.empty() )
5208             CV_Error_( CV_StsError, ("Extra closing '%c'", *_str) );
5209         if( (*_str == ']' ? '[' : '{') != fs.structs.back() )
5210             CV_Error_( CV_StsError,
5211             ("The closing '%c' does not match the opening '%c'", *_str, fs.structs.back()));
5212         fs.structs.pop_back();
5213         fs.state = fs.structs.empty() || fs.structs.back() == '{' ?
5214             INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED;
5215         cvEndWriteStruct( *fs );
5216         fs.elname = String();
5217     }
5218     else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
5219     {
5220         if( !cv_isalpha(*_str) )
5221             CV_Error_( CV_StsError, ("Incorrect element name %s", _str) );
5222         fs.elname = str;
5223         fs.state = VALUE_EXPECTED + INSIDE_MAP;
5224     }
5225     else if( (fs.state & 3) == VALUE_EXPECTED )
5226     {
5227         if( *_str == '{' || *_str == '[' )
5228         {
5229             fs.structs.push_back(*_str);
5230             int flags = *_str++ == '{' ? CV_NODE_MAP : CV_NODE_SEQ;
5231             fs.state = flags == CV_NODE_MAP ? INSIDE_MAP +
5232                 NAME_EXPECTED : VALUE_EXPECTED;
5233             if( *_str == ':' )
5234             {
5235                 flags |= CV_NODE_FLOW;
5236                 _str++;
5237             }
5238             cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0,
5239                 flags, *_str ? _str : 0 );
5240             fs.elname = String();
5241         }
5242         else
5243         {
5244             write( fs, fs.elname, (_str[0] == '\\' && (_str[1] == '{' || _str[1] == '}' ||
5245                 _str[1] == '[' || _str[1] == ']')) ? String(_str+1) : str );
5246             if( fs.state == INSIDE_MAP + VALUE_EXPECTED )
5247                 fs.state = INSIDE_MAP + NAME_EXPECTED;
5248         }
5249     }
5250     else
5251         CV_Error( CV_StsError, "Invalid fs.state" );
5252     return fs;
5253 }
5254 
5255 
writeRaw(const String & fmt,const uchar * vec,size_t len)5256 void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len )
5257 {
5258     if( !isOpened() )
5259         return;
5260     size_t elemSize, cn;
5261     getElemSize( fmt, elemSize, cn );
5262     CV_Assert( len % elemSize == 0 );
5263     cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str());
5264 }
5265 
5266 
writeObj(const String & name,const void * obj)5267 void FileStorage::writeObj( const String& name, const void* obj )
5268 {
5269     if( !isOpened() )
5270         return;
5271     cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj );
5272 }
5273 
5274 
operator [](const String & nodename) const5275 FileNode FileStorage::operator[](const String& nodename) const
5276 {
5277     return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str()));
5278 }
5279 
operator [](const char * nodename) const5280 FileNode FileStorage::operator[](const char* nodename) const
5281 {
5282     return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename));
5283 }
5284 
operator [](const String & nodename) const5285 FileNode FileNode::operator[](const String& nodename) const
5286 {
5287     return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str()));
5288 }
5289 
operator [](const char * nodename) const5290 FileNode FileNode::operator[](const char* nodename) const
5291 {
5292     return FileNode(fs, cvGetFileNodeByName(fs, node, nodename));
5293 }
5294 
operator [](int i) const5295 FileNode FileNode::operator[](int i) const
5296 {
5297     return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) :
5298         i == 0 ? *this : FileNode();
5299 }
5300 
name() const5301 String FileNode::name() const
5302 {
5303     const char* str;
5304     return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str);
5305 }
5306 
readObj() const5307 void* FileNode::readObj() const
5308 {
5309     if( !fs || !node )
5310         return 0;
5311     return cvRead( (CvFileStorage*)fs, (CvFileNode*)node );
5312 }
5313 
FileNodeIterator()5314 FileNodeIterator::FileNodeIterator()
5315 {
5316     fs = 0;
5317     container = 0;
5318     reader.ptr = 0;
5319     remaining = 0;
5320 }
5321 
FileNodeIterator(const CvFileStorage * _fs,const CvFileNode * _node,size_t _ofs)5322 FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs,
5323                                    const CvFileNode* _node, size_t _ofs)
5324 {
5325     if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE )
5326     {
5327         int node_type = _node->tag & FileNode::TYPE_MASK;
5328         fs = _fs;
5329         container = _node;
5330         if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) )
5331         {
5332             cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader );
5333             remaining = FileNode(_fs, _node).size();
5334         }
5335         else
5336         {
5337             reader.ptr = (schar*)_node;
5338             reader.seq = 0;
5339             remaining = 1;
5340         }
5341         (*this) += (int)_ofs;
5342     }
5343     else
5344     {
5345         fs = 0;
5346         container = 0;
5347         reader.ptr = 0;
5348         remaining = 0;
5349     }
5350 }
5351 
FileNodeIterator(const FileNodeIterator & it)5352 FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
5353 {
5354     fs = it.fs;
5355     container = it.container;
5356     reader = it.reader;
5357     remaining = it.remaining;
5358 }
5359 
operator ++()5360 FileNodeIterator& FileNodeIterator::operator ++()
5361 {
5362     if( remaining > 0 )
5363     {
5364         if( reader.seq )
5365         {
5366             if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max )
5367             {
5368                 cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 );
5369             }
5370         }
5371         remaining--;
5372     }
5373     return *this;
5374 }
5375 
operator ++(int)5376 FileNodeIterator FileNodeIterator::operator ++(int)
5377 {
5378     FileNodeIterator it = *this;
5379     ++(*this);
5380     return it;
5381 }
5382 
operator --()5383 FileNodeIterator& FileNodeIterator::operator --()
5384 {
5385     if( remaining < FileNode(fs, container).size() )
5386     {
5387         if( reader.seq )
5388         {
5389             if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min )
5390             {
5391                 cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 );
5392             }
5393         }
5394         remaining++;
5395     }
5396     return *this;
5397 }
5398 
operator --(int)5399 FileNodeIterator FileNodeIterator::operator --(int)
5400 {
5401     FileNodeIterator it = *this;
5402     --(*this);
5403     return it;
5404 }
5405 
operator +=(int ofs)5406 FileNodeIterator& FileNodeIterator::operator += (int ofs)
5407 {
5408     if( ofs == 0 )
5409         return *this;
5410     if( ofs > 0 )
5411         ofs = std::min(ofs, (int)remaining);
5412     else
5413     {
5414         size_t count = FileNode(fs, container).size();
5415         ofs = (int)(remaining - std::min(remaining - ofs, count));
5416     }
5417     remaining -= ofs;
5418     if( reader.seq )
5419         cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 );
5420     return *this;
5421 }
5422 
operator -=(int ofs)5423 FileNodeIterator& FileNodeIterator::operator -= (int ofs)
5424 {
5425     return operator += (-ofs);
5426 }
5427 
5428 
readRaw(const String & fmt,uchar * vec,size_t maxCount)5429 FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount )
5430 {
5431     if( fs && container && remaining > 0 )
5432     {
5433         size_t elem_size, cn;
5434         getElemSize( fmt, elem_size, cn );
5435         CV_Assert( elem_size > 0 );
5436         size_t count = std::min(remaining, maxCount);
5437 
5438         if( reader.seq )
5439         {
5440             cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() );
5441             remaining -= count*cn;
5442         }
5443         else
5444         {
5445             cvReadRawData( fs, container, vec, fmt.c_str() );
5446             remaining = 0;
5447         }
5448     }
5449     return *this;
5450 }
5451 
5452 
write(FileStorage & fs,const String & name,int value)5453 void write( FileStorage& fs, const String& name, int value )
5454 { cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); }
5455 
write(FileStorage & fs,const String & name,float value)5456 void write( FileStorage& fs, const String& name, float value )
5457 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
5458 
write(FileStorage & fs,const String & name,double value)5459 void write( FileStorage& fs, const String& name, double value )
5460 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
5461 
write(FileStorage & fs,const String & name,const String & value)5462 void write( FileStorage& fs, const String& name, const String& value )
5463 { cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); }
5464 
writeScalar(FileStorage & fs,int value)5465 void writeScalar(FileStorage& fs, int value )
5466 { cvWriteInt( *fs, 0, value ); }
5467 
writeScalar(FileStorage & fs,float value)5468 void writeScalar(FileStorage& fs, float value )
5469 { cvWriteReal( *fs, 0, value ); }
5470 
writeScalar(FileStorage & fs,double value)5471 void writeScalar(FileStorage& fs, double value )
5472 { cvWriteReal( *fs, 0, value ); }
5473 
writeScalar(FileStorage & fs,const String & value)5474 void writeScalar(FileStorage& fs, const String& value )
5475 { cvWriteString( *fs, 0, value.c_str() ); }
5476 
5477 
write(FileStorage & fs,const String & name,const Mat & value)5478 void write( FileStorage& fs, const String& name, const Mat& value )
5479 {
5480     if( value.dims <= 2 )
5481     {
5482         CvMat mat = value;
5483         cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
5484     }
5485     else
5486     {
5487         CvMatND mat = value;
5488         cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
5489     }
5490 }
5491 
5492 // TODO: the 4 functions below need to be implemented more efficiently
write(FileStorage & fs,const String & name,const SparseMat & value)5493 void write( FileStorage& fs, const String& name, const SparseMat& value )
5494 {
5495     Ptr<CvSparseMat> mat(cvCreateSparseMat(value));
5496     cvWrite( *fs, name.size() ? name.c_str() : 0, mat );
5497 }
5498 
5499 
WriteStructContext(FileStorage & _fs,const String & name,int flags,const String & typeName)5500 internal::WriteStructContext::WriteStructContext(FileStorage& _fs,
5501     const String& name, int flags, const String& typeName) : fs(&_fs)
5502 {
5503     cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags,
5504                        !typeName.empty() ? typeName.c_str() : 0);
5505     fs->elname = String();
5506     if ((flags & FileNode::TYPE_MASK) == FileNode::SEQ)
5507     {
5508         fs->state = FileStorage::VALUE_EXPECTED;
5509         fs->structs.push_back('[');
5510     }
5511     else
5512     {
5513         fs->state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
5514         fs->structs.push_back('{');
5515     }
5516 }
5517 
~WriteStructContext()5518 internal::WriteStructContext::~WriteStructContext()
5519 {
5520     cvEndWriteStruct(**fs);
5521     fs->structs.pop_back();
5522     fs->state = fs->structs.empty() || fs->structs.back() == '{' ?
5523         FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP :
5524         FileStorage::VALUE_EXPECTED;
5525     fs->elname = String();
5526 }
5527 
5528 
read(const FileNode & node,Mat & mat,const Mat & default_mat)5529 void read( const FileNode& node, Mat& mat, const Mat& default_mat )
5530 {
5531     if( node.empty() )
5532     {
5533         default_mat.copyTo(mat);
5534         return;
5535     }
5536     void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node);
5537     if(CV_IS_MAT_HDR_Z(obj))
5538     {
5539         cvarrToMat(obj).copyTo(mat);
5540         cvReleaseMat((CvMat**)&obj);
5541     }
5542     else if(CV_IS_MATND_HDR(obj))
5543     {
5544         cvarrToMat(obj).copyTo(mat);
5545         cvReleaseMatND((CvMatND**)&obj);
5546     }
5547     else
5548     {
5549         cvRelease(&obj);
5550         CV_Error(CV_StsBadArg, "Unknown array type");
5551     }
5552 }
5553 
read(const FileNode & node,SparseMat & mat,const SparseMat & default_mat)5554 void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat )
5555 {
5556     if( node.empty() )
5557     {
5558         default_mat.copyTo(mat);
5559         return;
5560     }
5561     Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node));
5562     CV_Assert(CV_IS_SPARSE_MAT(m));
5563     m->copyToSparseMat(mat);
5564 }
5565 
write(FileStorage & fs,const String & objname,const std::vector<KeyPoint> & keypoints)5566 void write(FileStorage& fs, const String& objname, const std::vector<KeyPoint>& keypoints)
5567 {
5568     cv::internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);
5569 
5570     int i, npoints = (int)keypoints.size();
5571     for( i = 0; i < npoints; i++ )
5572     {
5573         const KeyPoint& kpt = keypoints[i];
5574         cv::write(fs, kpt.pt.x);
5575         cv::write(fs, kpt.pt.y);
5576         cv::write(fs, kpt.size);
5577         cv::write(fs, kpt.angle);
5578         cv::write(fs, kpt.response);
5579         cv::write(fs, kpt.octave);
5580         cv::write(fs, kpt.class_id);
5581     }
5582 }
5583 
5584 
read(const FileNode & node,std::vector<KeyPoint> & keypoints)5585 void read(const FileNode& node, std::vector<KeyPoint>& keypoints)
5586 {
5587     keypoints.resize(0);
5588     FileNodeIterator it = node.begin(), it_end = node.end();
5589     for( ; it != it_end; )
5590     {
5591         KeyPoint kpt;
5592         it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
5593         keypoints.push_back(kpt);
5594     }
5595 }
5596 
5597 
write(FileStorage & fs,const String & objname,const std::vector<DMatch> & matches)5598 void write(FileStorage& fs, const String& objname, const std::vector<DMatch>& matches)
5599 {
5600     cv::internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);
5601 
5602     int i, n = (int)matches.size();
5603     for( i = 0; i < n; i++ )
5604     {
5605         const DMatch& m = matches[i];
5606         cv::write(fs, m.queryIdx);
5607         cv::write(fs, m.trainIdx);
5608         cv::write(fs, m.imgIdx);
5609         cv::write(fs, m.distance);
5610     }
5611 }
5612 
read(const FileNode & node,std::vector<DMatch> & matches)5613 void read(const FileNode& node, std::vector<DMatch>& matches)
5614 {
5615     matches.resize(0);
5616     FileNodeIterator it = node.begin(), it_end = node.end();
5617     for( ; it != it_end; )
5618     {
5619         DMatch m;
5620         it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance;
5621         matches.push_back(m);
5622     }
5623 }
5624 
5625 
type() const5626 int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); }
isNamed() const5627 bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; }
5628 
size() const5629 size_t FileNode::size() const
5630 {
5631     int t = type();
5632     return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count :
5633         t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone();
5634 }
5635 
read(const FileNode & node,int & value,int default_value)5636 void read(const FileNode& node, int& value, int default_value)
5637 {
5638     value = !node.node ? default_value :
5639     CV_NODE_IS_INT(node.node->tag) ? node.node->data.i :
5640     CV_NODE_IS_REAL(node.node->tag) ? cvRound(node.node->data.f) : 0x7fffffff;
5641 }
5642 
read(const FileNode & node,float & value,float default_value)5643 void read(const FileNode& node, float& value, float default_value)
5644 {
5645     value = !node.node ? default_value :
5646         CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i :
5647         CV_NODE_IS_REAL(node.node->tag) ? (float)node.node->data.f : 1e30f;
5648 }
5649 
read(const FileNode & node,double & value,double default_value)5650 void read(const FileNode& node, double& value, double default_value)
5651 {
5652     value = !node.node ? default_value :
5653         CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i :
5654         CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : 1e300;
5655 }
5656 
read(const FileNode & node,String & value,const String & default_value)5657 void read(const FileNode& node, String& value, const String& default_value)
5658 {
5659     value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String();
5660 }
5661 
5662 }
5663 
5664 /* End of file. */
5665