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 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 82 static inline bool cv_isalpha(char c) 83 { 84 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); 85 } 86 87 static inline bool cv_isdigit(char c) 88 { 89 return '0' <= c && c <= '9'; 90 } 91 92 static inline bool cv_isspace(char c) 93 { 94 return (9 <= c && c <= 13) || c == ' '; 95 } 96 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 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 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 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 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 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 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* 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* 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 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 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* 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 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* 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 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 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* 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* 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* 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* 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* 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* 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 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 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* 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* 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* 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 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 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 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 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 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 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 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* 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* 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* 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 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 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 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 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 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 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 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 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 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* 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 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 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 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 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 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 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 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* 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 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 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 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 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 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 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 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 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 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 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* 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 3494 icvIsMat( const void* ptr ) 3495 { 3496 return CV_IS_MAT_HDR_Z(ptr); 3497 } 3498 3499 static void 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 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* 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 3586 icvIsMatND( const void* ptr ) 3587 { 3588 return CV_IS_MATND_HDR(ptr); 3589 } 3590 3591 3592 static void 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* 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 3682 icvIsSparseMat( const void* ptr ) 3683 { 3684 return CV_IS_SPARSE_MAT(ptr); 3685 } 3686 3687 3688 static int 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 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* 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 3856 icvIsImage( const void* ptr ) 3857 { 3858 return CV_IS_IMAGE_HDR(ptr); 3859 } 3860 3861 static void 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* 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 3986 icvIsSeq( const void* ptr ) 3987 { 3988 return CV_IS_SEQ(ptr); 3989 } 3990 3991 3992 static void 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* 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 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* 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 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 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* 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* 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 4400 icvIsGraph( const void* ptr ) 4401 { 4402 return CV_IS_GRAPH(ptr); 4403 } 4404 4405 4406 static void 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* 4417 icvCloneGraph( const void* ptr ) 4418 { 4419 return cvCloneGraph( (const CvGraph*)ptr, 0 ); 4420 } 4421 4422 4423 static void 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* 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 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 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 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 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* 4887 cvFirstType( void ) 4888 { 4889 return CvType::first; 4890 } 4891 4892 4893 CV_IMPL CvTypeInfo* 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* 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 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 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* 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 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 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* 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 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 5132 FileStorage::FileStorage() 5133 { 5134 state = UNDEFINED; 5135 } 5136 5137 FileStorage::FileStorage(const String& filename, int flags, const String& encoding) 5138 { 5139 state = UNDEFINED; 5140 open( filename, flags, encoding ); 5141 } 5142 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 5151 FileStorage::~FileStorage() 5152 { 5153 while( structs.size() > 0 ) 5154 { 5155 cvEndWriteStruct(fs); 5156 structs.pop_back(); 5157 } 5158 } 5159 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 5170 bool FileStorage::isOpened() const 5171 { 5172 return fs && fs->is_opened; 5173 } 5174 5175 void FileStorage::release() 5176 { 5177 fs.release(); 5178 structs.clear(); 5179 state = UNDEFINED; 5180 } 5181 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 5192 FileNode FileStorage::root(int streamidx) const 5193 { 5194 return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode(); 5195 } 5196 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 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 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 5275 FileNode FileStorage::operator[](const String& nodename) const 5276 { 5277 return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str())); 5278 } 5279 5280 FileNode FileStorage::operator[](const char* nodename) const 5281 { 5282 return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename)); 5283 } 5284 5285 FileNode FileNode::operator[](const String& nodename) const 5286 { 5287 return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str())); 5288 } 5289 5290 FileNode FileNode::operator[](const char* nodename) const 5291 { 5292 return FileNode(fs, cvGetFileNodeByName(fs, node, nodename)); 5293 } 5294 5295 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 5301 String FileNode::name() const 5302 { 5303 const char* str; 5304 return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str); 5305 } 5306 5307 void* FileNode::readObj() const 5308 { 5309 if( !fs || !node ) 5310 return 0; 5311 return cvRead( (CvFileStorage*)fs, (CvFileNode*)node ); 5312 } 5313 5314 FileNodeIterator::FileNodeIterator() 5315 { 5316 fs = 0; 5317 container = 0; 5318 reader.ptr = 0; 5319 remaining = 0; 5320 } 5321 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 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 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 5376 FileNodeIterator FileNodeIterator::operator ++(int) 5377 { 5378 FileNodeIterator it = *this; 5379 ++(*this); 5380 return it; 5381 } 5382 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 5399 FileNodeIterator FileNodeIterator::operator --(int) 5400 { 5401 FileNodeIterator it = *this; 5402 --(*this); 5403 return it; 5404 } 5405 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 5423 FileNodeIterator& FileNodeIterator::operator -= (int ofs) 5424 { 5425 return operator += (-ofs); 5426 } 5427 5428 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 5453 void write( FileStorage& fs, const String& name, int value ) 5454 { cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); } 5455 5456 void write( FileStorage& fs, const String& name, float value ) 5457 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); } 5458 5459 void write( FileStorage& fs, const String& name, double value ) 5460 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); } 5461 5462 void write( FileStorage& fs, const String& name, const String& value ) 5463 { cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); } 5464 5465 void writeScalar(FileStorage& fs, int value ) 5466 { cvWriteInt( *fs, 0, value ); } 5467 5468 void writeScalar(FileStorage& fs, float value ) 5469 { cvWriteReal( *fs, 0, value ); } 5470 5471 void writeScalar(FileStorage& fs, double value ) 5472 { cvWriteReal( *fs, 0, value ); } 5473 5474 void writeScalar(FileStorage& fs, const String& value ) 5475 { cvWriteString( *fs, 0, value.c_str() ); } 5476 5477 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 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 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 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 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 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 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 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 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 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 5626 int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); } 5627 bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; } 5628 5629 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 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 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 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 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