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 "" );
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 ' or >" );
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 (' and ")
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