Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of gr-peach-opencv-project by
persistence.cpp
00001 /*M/////////////////////////////////////////////////////////////////////////////////////// 00002 // 00003 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 00004 // 00005 // By downloading, copying, installing or using the software you agree to this license. 00006 // If you do not agree to this license, do not download, install, 00007 // copy or use the software. 00008 // 00009 // 00010 // License Agreement 00011 // For Open Source Computer Vision Library 00012 // 00013 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 00014 // Copyright (C) 2009, Willow Garage Inc., all rights reserved. 00015 // Third party copyrights are property of their respective owners. 00016 // 00017 // Redistribution and use in source and binary forms, with or without modification, 00018 // are permitted provided that the following conditions are met: 00019 // 00020 // * Redistribution's of source code must retain the above copyright notice, 00021 // this list of conditions and the following disclaimer. 00022 // 00023 // * Redistribution's in binary form must reproduce the above copyright notice, 00024 // this list of conditions and the following disclaimer in the documentation 00025 // and/or other materials provided with the distribution. 00026 // 00027 // * The name of the copyright holders may not be used to endorse or promote products 00028 // derived from this software without specific prior written permission. 00029 // 00030 // This software is provided by the copyright holders and contributors "as is" and 00031 // any express or implied warranties, including, but not limited to, the implied 00032 // warranties of merchantability and fitness for a particular purpose are disclaimed. 00033 // In no event shall the Intel Corporation or contributors be liable for any direct, 00034 // indirect, incidental, special, exemplary, or consequential damages 00035 // (including, but not limited to, procurement of substitute goods or services; 00036 // loss of use, data, or profits; or business interruption) however caused 00037 // and on any theory of liability, whether in contract, strict liability, 00038 // or tort (including negligence or otherwise) arising in any way out of 00039 // the use of this software, even if advised of the possibility of such damage. 00040 // 00041 //M*/ 00042 00043 #include "precomp.hpp" 00044 00045 #include <ctype.h> 00046 #include <deque> 00047 #include <iterator> 00048 /* TODO */ //Add the common header file 00049 //#include "filesys.hpp" 00050 /* END TO-DO */ 00051 #define USE_ZLIB 1 00052 00053 #ifdef __APPLE__ 00054 # include "TargetConditionals.h" 00055 # if (defined TARGET_OS_IPHONE && TARGET_OS_IPHONE) || (defined TARGET_IPHONE_SIMULATOR && TARGET_IPHONE_SIMULATOR) 00056 # undef USE_ZLIB 00057 # define USE_ZLIB 0 00058 typedef void* gzFile; 00059 # endif 00060 #else 00061 /* TODO */ // Disable ZLib 00062 # undef USE_ZLIB 00063 # define USE_ZLIB 0 00064 typedef void* gzFile; 00065 #endif 00066 00067 #if USE_ZLIB 00068 # ifndef _LFS64_LARGEFILE 00069 # define _LFS64_LARGEFILE 0 00070 # endif 00071 # ifndef _FILE_OFFSET_BITS 00072 # define _FILE_OFFSET_BITS 0 00073 # endif 00074 # include <zlib.h> 00075 #endif 00076 00077 /****************************************************************************************\ 00078 * Common macros and type definitions * 00079 \****************************************************************************************/ 00080 00081 #define cv_isprint(c) ((uchar)(c) >= (uchar)' ') 00082 #define cv_isprint_or_tab(c) ((uchar)(c) >= (uchar)' ' || (c) == '\t') 00083 00084 static inline bool cv_isalnum(char c) 00085 { 00086 return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); 00087 } 00088 00089 static inline bool cv_isalpha(char c) 00090 { 00091 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); 00092 } 00093 00094 static inline bool cv_isdigit(char c) 00095 { 00096 return '0' <= c && c <= '9'; 00097 } 00098 00099 static inline bool cv_isspace(char c) 00100 { 00101 return (9 <= c && c <= 13) || c == ' '; 00102 } 00103 00104 static char* icv_itoa( int _val, char* buffer, int /*radix*/ ) 00105 { 00106 const int radix = 10; 00107 char* ptr=buffer + 23 /* enough even for 64-bit integers */; 00108 unsigned val = abs(_val); 00109 00110 *ptr = '\0'; 00111 do 00112 { 00113 unsigned r = val / radix; 00114 *--ptr = (char)(val - (r*radix) + '0'); 00115 val = r; 00116 } 00117 while( val != 0 ); 00118 00119 if( _val < 0 ) 00120 *--ptr = '-'; 00121 00122 return ptr; 00123 } 00124 00125 cv::String cv::FileStorage::getDefaultObjectName(const cv::String& _filename) 00126 { 00127 static const char* stubname = "unnamed"; 00128 const char* filename = _filename.c_str(); 00129 const char* ptr2 = filename + _filename.size(); 00130 const char* ptr = ptr2 - 1; 00131 cv::AutoBuffer<char> name_buf(_filename.size()+1); 00132 00133 while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' ) 00134 { 00135 if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) ) 00136 ptr2 = ptr; 00137 ptr--; 00138 } 00139 ptr++; 00140 if( ptr == ptr2 ) 00141 CV_Error( CV_StsBadArg, "Invalid filename" ); 00142 00143 char* name = name_buf; 00144 00145 // name must start with letter or '_' 00146 if( !cv_isalpha(*ptr) && *ptr!= '_' ){ 00147 *name++ = '_'; 00148 } 00149 00150 while( ptr < ptr2 ) 00151 { 00152 char c = *ptr++; 00153 if( !cv_isalnum(c) && c != '-' && c != '_' ) 00154 c = '_'; 00155 *name++ = c; 00156 } 00157 *name = '\0'; 00158 name = name_buf; 00159 if( strcmp( name, "_" ) == 0 ) 00160 strcpy( name, stubname ); 00161 return String(name); 00162 } 00163 00164 typedef struct CvGenericHash 00165 { 00166 CV_SET_FIELDS() 00167 int tab_size; 00168 void** table; 00169 } 00170 CvGenericHash; 00171 00172 typedef CvGenericHash CvStringHash; 00173 00174 typedef struct CvFileMapNode 00175 { 00176 CvFileNode value; 00177 const CvStringHashNode* key; 00178 struct CvFileMapNode* next; 00179 } 00180 CvFileMapNode; 00181 00182 typedef struct CvXMLStackRecord 00183 { 00184 CvMemStoragePos pos; 00185 CvString struct_tag; 00186 int struct_indent; 00187 int struct_flags; 00188 } 00189 CvXMLStackRecord; 00190 00191 #define CV_XML_OPENING_TAG 1 00192 #define CV_XML_CLOSING_TAG 2 00193 #define CV_XML_EMPTY_TAG 3 00194 #define CV_XML_HEADER_TAG 4 00195 #define CV_XML_DIRECTIVE_TAG 5 00196 00197 //typedef void (*CvParse)( struct CvFileStorage* fs ); 00198 typedef void (*CvStartWriteStruct)( struct CvFileStorage* fs, const char* key, 00199 int struct_flags, const char* type_name ); 00200 typedef void (*CvEndWriteStruct)( struct CvFileStorage* fs ); 00201 typedef void (*CvWriteInt)( struct CvFileStorage* fs, const char* key, int value ); 00202 typedef void (*CvWriteReal)( struct CvFileStorage* fs, const char* key, double value ); 00203 typedef void (*CvWriteString)( struct CvFileStorage* fs, const char* key, 00204 const char* value, int quote ); 00205 typedef void (*CvWriteComment)( struct CvFileStorage* fs, const char* comment, int eol_comment ); 00206 typedef void (*CvStartNextStream)( struct CvFileStorage* fs ); 00207 00208 typedef struct CvFileStorage 00209 { 00210 int flags; 00211 int fmt; 00212 int write_mode; 00213 int is_first; 00214 CvMemStorage* memstorage; 00215 CvMemStorage* dststorage; 00216 CvMemStorage* strstorage; 00217 CvStringHash* str_hash; 00218 CvSeq* roots; 00219 CvSeq* write_stack; 00220 int struct_indent; 00221 int struct_flags; 00222 CvString struct_tag; 00223 int space; 00224 char* filename; 00225 FILE* file; 00226 gzFile gzfile; 00227 char* buffer; 00228 char* buffer_start; 00229 char* buffer_end; 00230 int wrap_margin; 00231 int lineno; 00232 int dummy_eof; 00233 const char* errmsg; 00234 char errmsgbuf[128]; 00235 00236 CvStartWriteStruct start_write_struct; 00237 CvEndWriteStruct end_write_struct; 00238 CvWriteInt write_int; 00239 CvWriteReal write_real; 00240 CvWriteString write_string; 00241 CvWriteComment write_comment; 00242 CvStartNextStream start_next_stream; 00243 00244 const char* strbuf; 00245 size_t strbufsize, strbufpos; 00246 std::deque<char>* outbuf; 00247 00248 bool is_opened; 00249 } 00250 CvFileStorage; 00251 00252 static void icvPuts( CvFileStorage* fs, const char* str ) 00253 { 00254 if( fs->outbuf ) 00255 std::copy(str, str + strlen(str), std::back_inserter(*fs->outbuf)); 00256 else if( fs->file ) 00257 fputs( str, fs->file ); 00258 #if USE_ZLIB 00259 else if( fs->gzfile ) 00260 gzputs( fs->gzfile, str ); 00261 #endif 00262 else 00263 CV_Error( CV_StsError, "The storage is not opened" ); 00264 } 00265 00266 static char* icvGets( CvFileStorage* fs, char* str, int maxCount ) 00267 { 00268 if( fs->strbuf ) 00269 { 00270 size_t i = fs->strbufpos, len = fs->strbufsize; 00271 int j = 0; 00272 const char* instr = fs->strbuf; 00273 while( i < len && j < maxCount-1 ) 00274 { 00275 char c = instr[i++]; 00276 if( c == '\0' ) 00277 break; 00278 str[j++] = c; 00279 if( c == '\n' ) 00280 break; 00281 } 00282 str[j++] = '\0'; 00283 fs->strbufpos = i; 00284 return j > 1 ? str : 0; 00285 } 00286 if( fs->file ) 00287 /* TODO */ //User defined - get the string from file 00288 #ifdef USER_FILE 00289 return fgets_rzctm( str, maxCount, fs->file,fs->fmt ); 00290 #else 00291 return fgets( str, maxCount, fs->file ); 00292 #endif 00293 #if USE_ZLIB 00294 if( fs->gzfile ) 00295 return gzgets( fs->gzfile, str, maxCount ); 00296 #endif 00297 CV_Error( CV_StsError, "The storage is not opened" ); 00298 return 0; 00299 } 00300 00301 static int icvEof( CvFileStorage* fs ) 00302 { 00303 if( fs->strbuf ) 00304 return fs->strbufpos >= fs->strbufsize; 00305 if( fs->file ) 00306 return feof(fs->file); 00307 #if USE_ZLIB 00308 if( fs->gzfile ) 00309 return gzeof(fs->gzfile); 00310 #endif 00311 return false; 00312 } 00313 00314 static void icvCloseFile( CvFileStorage* fs ) 00315 { 00316 /* TODO */ //User defined - Close file 00317 if( fs->file ) 00318 #ifdef USER_FILE 00319 fclose_rzctm( fs->file ); 00320 #else 00321 fclose( fs->file ); 00322 #endif 00323 #if USE_ZLIB 00324 else if( fs->gzfile ) 00325 gzclose( fs->gzfile ); 00326 #endif 00327 fs->file = 0; 00328 fs->gzfile = 0; 00329 fs->strbuf = 0; 00330 fs->strbufpos = 0; 00331 fs->is_opened = false; 00332 } 00333 00334 static void icvRewind( CvFileStorage* fs ) 00335 { 00336 if( fs->file ) 00337 /* TODO */ //User defined - Pass through the character of file 00338 #ifdef USER_FILE 00339 fseek_rzctm(fs->file, 0, SEEK_SET); 00340 #else 00341 rewind(fs->file); 00342 #endif 00343 00344 #if USE_ZLIB 00345 else if( fs->gzfile ) 00346 gzrewind(fs->gzfile); 00347 #endif 00348 fs->strbufpos = 0; 00349 } 00350 00351 #define CV_YML_INDENT 3 00352 #define CV_XML_INDENT 2 00353 #define CV_YML_INDENT_FLOW 1 00354 #define CV_FS_MAX_LEN 4096 00355 00356 #define CV_FILE_STORAGE ('Y' + ('A' << 8) + ('M' << 16) + ('L' << 24)) 00357 #define CV_IS_FILE_STORAGE(fs) ((fs) != 0 && (fs)->flags == CV_FILE_STORAGE) 00358 00359 #define CV_CHECK_FILE_STORAGE(fs) \ 00360 { \ 00361 if( !CV_IS_FILE_STORAGE(fs) ) \ 00362 CV_Error( (fs) ? CV_StsBadArg : CV_StsNullPtr, \ 00363 "Invalid pointer to file storage" ); \ 00364 } 00365 00366 #define CV_CHECK_OUTPUT_FILE_STORAGE(fs) \ 00367 { \ 00368 CV_CHECK_FILE_STORAGE(fs); \ 00369 if( !fs->write_mode ) \ 00370 CV_Error( CV_StsError, "The file storage is opened for reading" ); \ 00371 } 00372 00373 CV_IMPL const char* 00374 cvAttrValue( const CvAttrList* attr, const char* attr_name ) 00375 { 00376 while( attr && attr->attr ) 00377 { 00378 int i; 00379 for( i = 0; attr->attr[i*2] != 0; i++ ) 00380 { 00381 if( strcmp( attr_name, attr->attr[i*2] ) == 0 ) 00382 return attr->attr[i*2+1]; 00383 } 00384 attr = attr->next; 00385 } 00386 00387 return 0; 00388 } 00389 00390 00391 static CvGenericHash* 00392 cvCreateMap( int flags, int header_size, int elem_size, 00393 CvMemStorage* storage, int start_tab_size ) 00394 { 00395 if( header_size < (int)sizeof(CvGenericHash) ) 00396 CV_Error( CV_StsBadSize, "Too small map header_size" ); 00397 00398 if( start_tab_size <= 0 ) 00399 start_tab_size = 16; 00400 00401 CvGenericHash* map = (CvGenericHash*)cvCreateSet( flags, header_size, elem_size, storage ); 00402 00403 map->tab_size = start_tab_size; 00404 start_tab_size *= sizeof(map->table[0]); 00405 map->table = (void**)cvMemStorageAlloc( storage, start_tab_size ); 00406 memset( map->table, 0, start_tab_size ); 00407 00408 return map; 00409 } 00410 00411 #define CV_PARSE_ERROR( errmsg ) \ 00412 icvParseError( fs, CV_Func, (errmsg), __FILE__, __LINE__ ) 00413 00414 static void 00415 icvParseError( CvFileStorage* fs, const char* func_name, 00416 const char* err_msg, const char* source_file, int source_line ) 00417 { 00418 char buf[1<<10]; 00419 sprintf( buf, "%s(%d): %s", fs->filename, fs->lineno, err_msg ); 00420 cvError( CV_StsParseError, func_name, buf, source_file, source_line ); 00421 } 00422 00423 00424 static void 00425 icvFSCreateCollection( CvFileStorage* fs, int tag, CvFileNode* collection ) 00426 { 00427 if( CV_NODE_IS_MAP(tag) ) 00428 { 00429 if( collection->tag != CV_NODE_NONE ) 00430 { 00431 assert( fs->fmt == CV_STORAGE_FORMAT_XML ); 00432 CV_PARSE_ERROR( "Sequence element should not have name (use <_></_>)" ); 00433 } 00434 00435 collection->data.map = cvCreateMap( 0, sizeof(CvFileNodeHash), 00436 sizeof(CvFileMapNode), fs->memstorage, 16 ); 00437 } 00438 else 00439 { 00440 CvSeq* seq; 00441 seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvFileNode), fs->memstorage ); 00442 00443 // if <collection> contains some scalar element, add it to the newly created collection 00444 if( CV_NODE_TYPE(collection->tag) != CV_NODE_NONE ) 00445 cvSeqPush( seq, collection ); 00446 00447 collection->data.seq = seq; 00448 } 00449 00450 collection->tag = tag; 00451 cvSetSeqBlockSize( collection->data.seq, 8 ); 00452 } 00453 00454 00455 /*static void 00456 icvFSReleaseCollection( CvSeq* seq ) 00457 { 00458 if( seq ) 00459 { 00460 int is_map = CV_IS_SET(seq); 00461 CvSeqReader reader; 00462 int i, total = seq->total; 00463 cvStartReadSeq( seq, &reader, 0 ); 00464 00465 for( i = 0; i < total; i++ ) 00466 { 00467 CvFileNode* node = (CvFileNode*)reader.ptr; 00468 00469 if( (!is_map || CV_IS_SET_ELEM( node )) && CV_NODE_IS_COLLECTION(node->tag) ) 00470 { 00471 if( CV_NODE_IS_USER(node->tag) && node->info && node->data.obj.decoded ) 00472 cvRelease( (void**)&node->data.obj.decoded ); 00473 if( !CV_NODE_SEQ_IS_SIMPLE( node->data.seq )) 00474 icvFSReleaseCollection( node->data.seq ); 00475 } 00476 CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); 00477 } 00478 } 00479 }*/ 00480 00481 00482 static char* 00483 icvFSDoResize( CvFileStorage* fs, char* ptr, int len ) 00484 { 00485 char* new_ptr = 0; 00486 int written_len = (int)(ptr - fs->buffer_start); 00487 int new_size = (int)((fs->buffer_end - fs->buffer_start)*3/2); 00488 new_size = MAX( written_len + len, new_size ); 00489 new_ptr = (char*)cvAlloc( new_size + 256 ); 00490 fs->buffer = new_ptr + (fs->buffer - fs->buffer_start); 00491 if( written_len > 0 ) 00492 memcpy( new_ptr, fs->buffer_start, written_len ); 00493 fs->buffer_start = new_ptr; 00494 fs->buffer_end = fs->buffer_start + new_size; 00495 new_ptr += written_len; 00496 return new_ptr; 00497 } 00498 00499 00500 inline char* icvFSResizeWriteBuffer( CvFileStorage* fs, char* ptr, int len ) 00501 { 00502 return ptr + len < fs->buffer_end ? ptr : icvFSDoResize( fs, ptr, len ); 00503 } 00504 00505 00506 static char* 00507 icvFSFlush( CvFileStorage* fs ) 00508 { 00509 char* ptr = fs->buffer; 00510 int indent; 00511 00512 if( ptr > fs->buffer_start + fs->space ) 00513 { 00514 ptr[0] = '\n'; 00515 ptr[1] = '\0'; 00516 icvPuts( fs, fs->buffer_start ); 00517 fs->buffer = fs->buffer_start; 00518 } 00519 00520 indent = fs->struct_indent; 00521 00522 if( fs->space != indent ) 00523 { 00524 if( fs->space < indent ) 00525 memset( fs->buffer_start + fs->space, ' ', indent - fs->space ); 00526 fs->space = indent; 00527 } 00528 00529 ptr = fs->buffer = fs->buffer_start + fs->space; 00530 00531 return ptr; 00532 } 00533 00534 00535 static void 00536 icvClose( CvFileStorage* fs, cv::String* out ) 00537 { 00538 if( out ) 00539 out->clear(); 00540 00541 if( !fs ) 00542 CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" ); 00543 00544 if( fs->is_opened ) 00545 { 00546 if( fs->write_mode && (fs->file || fs->gzfile || fs->outbuf) ) 00547 { 00548 if( fs->write_stack ) 00549 { 00550 while( fs->write_stack->total > 0 ) 00551 cvEndWriteStruct(fs); 00552 } 00553 icvFSFlush(fs); 00554 if( fs->fmt == CV_STORAGE_FORMAT_XML ) 00555 icvPuts( fs, "</opencv_storage>\n" ); 00556 } 00557 00558 icvCloseFile(fs); 00559 } 00560 00561 if( fs->outbuf && out ) 00562 { 00563 *out = cv::String(fs->outbuf->begin(), fs->outbuf->end()); 00564 } 00565 } 00566 00567 00568 /* closes file storage and deallocates buffers */ 00569 CV_IMPL void 00570 cvReleaseFileStorage( CvFileStorage** p_fs ) 00571 { 00572 if( !p_fs ) 00573 CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" ); 00574 00575 if( *p_fs ) 00576 { 00577 CvFileStorage* fs = *p_fs; 00578 *p_fs = 0; 00579 00580 icvClose(fs, 0); 00581 00582 cvReleaseMemStorage( &fs->strstorage ); 00583 cvFree( &fs->buffer_start ); 00584 cvReleaseMemStorage( &fs->memstorage ); 00585 00586 if( fs->outbuf ) 00587 delete fs->outbuf; 00588 00589 memset( fs, 0, sizeof(*fs) ); 00590 cvFree( &fs ); 00591 } 00592 } 00593 00594 00595 #define CV_HASHVAL_SCALE 33 00596 00597 CV_IMPL CvStringHashNode* 00598 cvGetHashedKey( CvFileStorage* fs, const char* str, int len, int create_missing ) 00599 { 00600 CvStringHashNode* node = 0; 00601 unsigned hashval = 0; 00602 int i, tab_size; 00603 00604 if( !fs ) 00605 return 0; 00606 00607 CvStringHash* map = fs->str_hash; 00608 00609 if( len < 0 ) 00610 { 00611 for( i = 0; str[i] != '\0'; i++ ) 00612 hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i]; 00613 len = i; 00614 } 00615 else for( i = 0; i < len; i++ ) 00616 hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i]; 00617 00618 hashval &= INT_MAX; 00619 tab_size = map->tab_size; 00620 if( (tab_size & (tab_size - 1)) == 0 ) 00621 i = (int)(hashval & (tab_size - 1)); 00622 else 00623 i = (int)(hashval % tab_size); 00624 00625 for( node = (CvStringHashNode*)(map->table[i]); node != 0; node = node->next ) 00626 { 00627 if( node->hashval == hashval && 00628 node->str.len == len && 00629 memcmp( node->str.ptr, str, len ) == 0 ) 00630 break; 00631 } 00632 00633 if( !node && create_missing ) 00634 { 00635 node = (CvStringHashNode*)cvSetNew( (CvSet*)map ); 00636 node->hashval = hashval; 00637 node->str = cvMemStorageAllocString( map->storage, str, len ); 00638 node->next = (CvStringHashNode*)(map->table[i]); 00639 map->table[i] = node; 00640 } 00641 00642 return node; 00643 } 00644 00645 00646 CV_IMPL CvFileNode* 00647 cvGetFileNode( CvFileStorage* fs, CvFileNode* _map_node, 00648 const CvStringHashNode* key, 00649 int create_missing ) 00650 { 00651 CvFileNode* value = 0; 00652 int k = 0, attempts = 1; 00653 00654 if( !fs ) 00655 return 0; 00656 00657 CV_CHECK_FILE_STORAGE(fs); 00658 00659 if( !key ) 00660 CV_Error( CV_StsNullPtr, "Null key element" ); 00661 00662 if( _map_node ) 00663 { 00664 if( !fs->roots ) 00665 return 0; 00666 attempts = fs->roots->total; 00667 } 00668 00669 for( k = 0; k < attempts; k++ ) 00670 { 00671 int i, tab_size; 00672 CvFileNode* map_node = _map_node; 00673 CvFileMapNode* another; 00674 CvFileNodeHash* map; 00675 00676 if( !map_node ) 00677 map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k ); 00678 00679 if( !CV_NODE_IS_MAP(map_node->tag) ) 00680 { 00681 if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) && 00682 CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE ) 00683 CV_Error( CV_StsError, "The node is neither a map nor an empty collection" ); 00684 return 0; 00685 } 00686 00687 map = map_node->data.map; 00688 tab_size = map->tab_size; 00689 00690 if( (tab_size & (tab_size - 1)) == 0 ) 00691 i = (int)(key->hashval & (tab_size - 1)); 00692 else 00693 i = (int)(key->hashval % tab_size); 00694 00695 for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next ) 00696 if( another->key == key ) 00697 { 00698 if( !create_missing ) 00699 { 00700 value = &another->value; 00701 return value; 00702 } 00703 CV_PARSE_ERROR( "Duplicated key" ); 00704 } 00705 00706 if( k == attempts - 1 && create_missing ) 00707 { 00708 CvFileMapNode* node = (CvFileMapNode*)cvSetNew( (CvSet*)map ); 00709 node->key = key; 00710 00711 node->next = (CvFileMapNode*)(map->table[i]); 00712 map->table[i] = node; 00713 value = (CvFileNode*)node; 00714 } 00715 } 00716 00717 return value; 00718 } 00719 00720 00721 CV_IMPL CvFileNode* 00722 cvGetFileNodeByName( const CvFileStorage* fs, const CvFileNode* _map_node, const char* str ) 00723 { 00724 CvFileNode* value = 0; 00725 int i, len, tab_size; 00726 unsigned hashval = 0; 00727 int k = 0, attempts = 1; 00728 00729 if( !fs ) 00730 return 0; 00731 00732 CV_CHECK_FILE_STORAGE(fs); 00733 00734 if( !str ) 00735 CV_Error( CV_StsNullPtr, "Null element name" ); 00736 00737 for( i = 0; str[i] != '\0'; i++ ) 00738 hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i]; 00739 hashval &= INT_MAX; 00740 len = i; 00741 00742 if( !_map_node ) 00743 { 00744 if( !fs->roots ) 00745 return 0; 00746 attempts = fs->roots->total; 00747 } 00748 00749 for( k = 0; k < attempts; k++ ) 00750 { 00751 CvFileNodeHash* map; 00752 const CvFileNode* map_node = _map_node; 00753 CvFileMapNode* another; 00754 00755 if( !map_node ) 00756 map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k ); 00757 00758 if( !CV_NODE_IS_MAP(map_node->tag) ) 00759 { 00760 if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) && 00761 CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE ) 00762 CV_Error( CV_StsError, "The node is neither a map nor an empty collection" ); 00763 return 0; 00764 } 00765 00766 map = map_node->data.map; 00767 tab_size = map->tab_size; 00768 00769 if( (tab_size & (tab_size - 1)) == 0 ) 00770 i = (int)(hashval & (tab_size - 1)); 00771 else 00772 i = (int)(hashval % tab_size); 00773 00774 for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next ) 00775 { 00776 const CvStringHashNode* key = another->key; 00777 00778 if( key->hashval == hashval && 00779 key->str.len == len && 00780 memcmp( key->str.ptr, str, len ) == 0 ) 00781 { 00782 value = &another->value; 00783 return value; 00784 } 00785 } 00786 } 00787 00788 return value; 00789 } 00790 00791 00792 CV_IMPL CvFileNode* 00793 cvGetRootFileNode( const CvFileStorage* fs, int stream_index ) 00794 { 00795 CV_CHECK_FILE_STORAGE(fs); 00796 00797 if( !fs->roots || (unsigned)stream_index >= (unsigned)fs->roots->total ) 00798 return 0; 00799 00800 return (CvFileNode*)cvGetSeqElem( fs->roots, stream_index ); 00801 } 00802 00803 00804 /* returns the sequence element by its index */ 00805 /*CV_IMPL CvFileNode* 00806 cvGetFileNodeFromSeq( CvFileStorage* fs, 00807 CvFileNode* seq_node, int index ) 00808 { 00809 CvFileNode* value = 0; 00810 CvSeq* seq; 00811 00812 if( !seq_node ) 00813 seq = fs->roots; 00814 else if( !CV_NODE_IS_SEQ(seq_node->tag) ) 00815 { 00816 if( CV_NODE_IS_MAP(seq_node->tag) ) 00817 CV_Error( CV_StsError, "The node is map. Use cvGetFileNodeFromMap()." ); 00818 if( CV_NODE_TYPE(seq_node->tag) == CV_NODE_NONE ) 00819 CV_Error( CV_StsError, "The node is an empty object (None)." ); 00820 if( index != 0 && index != -1 ) 00821 CV_Error( CV_StsOutOfRange, "" ); 00822 value = seq_node; 00823 EXIT; 00824 } 00825 else 00826 seq = seq_node->data.seq; 00827 00828 if( !seq ) 00829 CV_Error( CV_StsNullPtr, "The file storage is empty" ); 00830 00831 value = (CvFileNode*)cvGetSeqElem( seq, index, 0 ); 00832 00833 00834 00835 return value; 00836 }*/ 00837 00838 00839 static char* 00840 icvDoubleToString( char* buf, double value ) 00841 { 00842 Cv64suf val; 00843 unsigned ieee754_hi; 00844 00845 val.f = value; 00846 ieee754_hi = (unsigned)(val.u >> 32); 00847 00848 if( (ieee754_hi & 0x7ff00000) != 0x7ff00000 ) 00849 { 00850 int ivalue = cvRound(value); 00851 if( ivalue == value ) 00852 sprintf( buf, "%d.", ivalue ); 00853 else 00854 { 00855 static const char* fmt = "%.16e"; 00856 char* ptr = buf; 00857 sprintf( buf, fmt, value ); 00858 if( *ptr == '+' || *ptr == '-' ) 00859 ptr++; 00860 for( ; cv_isdigit(*ptr); ptr++ ) 00861 ; 00862 if( *ptr == ',' ) 00863 *ptr = '.'; 00864 } 00865 } 00866 else 00867 { 00868 unsigned ieee754_lo = (unsigned)val.u; 00869 if( (ieee754_hi & 0x7fffffff) + (ieee754_lo != 0) > 0x7ff00000 ) 00870 strcpy( buf, ".Nan" ); 00871 else 00872 strcpy( buf, (int)ieee754_hi < 0 ? "-.Inf" : ".Inf" ); 00873 } 00874 00875 return buf; 00876 } 00877 00878 00879 static char* 00880 icvFloatToString( char* buf, float value ) 00881 { 00882 Cv32suf val; 00883 unsigned ieee754; 00884 val.f = value; 00885 ieee754 = val.u; 00886 00887 if( (ieee754 & 0x7f800000) != 0x7f800000 ) 00888 { 00889 int ivalue = cvRound(value); 00890 if( ivalue == value ) 00891 sprintf( buf, "%d.", ivalue ); 00892 else 00893 { 00894 static const char* fmt = "%.8e"; 00895 char* ptr = buf; 00896 sprintf( buf, fmt, value ); 00897 if( *ptr == '+' || *ptr == '-' ) 00898 ptr++; 00899 for( ; cv_isdigit(*ptr); ptr++ ) 00900 ; 00901 if( *ptr == ',' ) 00902 *ptr = '.'; 00903 } 00904 } 00905 else 00906 { 00907 if( (ieee754 & 0x7fffffff) != 0x7f800000 ) 00908 strcpy( buf, ".Nan" ); 00909 else 00910 strcpy( buf, (int)ieee754 < 0 ? "-.Inf" : ".Inf" ); 00911 } 00912 00913 return buf; 00914 } 00915 00916 00917 static void 00918 icvProcessSpecialDouble( CvFileStorage* fs, char* buf, double* value, char** endptr ) 00919 { 00920 char c = buf[0]; 00921 int inf_hi = 0x7ff00000; 00922 00923 if( c == '-' || c == '+' ) 00924 { 00925 inf_hi = c == '-' ? 0xfff00000 : 0x7ff00000; 00926 c = *++buf; 00927 } 00928 00929 if( c != '.' ) 00930 CV_PARSE_ERROR( "Bad format of floating-point constant" ); 00931 00932 union{double d; uint64 i;} v; 00933 v.d = 0.; 00934 if( toupper(buf[1]) == 'I' && toupper(buf[2]) == 'N' && toupper(buf[3]) == 'F' ) 00935 v.i = (uint64)inf_hi << 32; 00936 else if( toupper(buf[1]) == 'N' && toupper(buf[2]) == 'A' && toupper(buf[3]) == 'N' ) 00937 v.i = (uint64)-1; 00938 else 00939 CV_PARSE_ERROR( "Bad format of floating-point constant" ); 00940 *value = v.d; 00941 00942 *endptr = buf + 4; 00943 } 00944 00945 00946 static double icv_strtod( CvFileStorage* fs, char* ptr, char** endptr ) 00947 { 00948 double fval = strtod( ptr, endptr ); 00949 if( **endptr == '.' ) 00950 { 00951 char* dot_pos = *endptr; 00952 *dot_pos = ','; 00953 double fval2 = strtod( ptr, endptr ); 00954 *dot_pos = '.'; 00955 if( *endptr > dot_pos ) 00956 fval = fval2; 00957 else 00958 *endptr = dot_pos; 00959 } 00960 00961 if( *endptr == ptr || cv_isalpha(**endptr) ) 00962 icvProcessSpecialDouble( fs, ptr, &fval, endptr ); 00963 00964 return fval; 00965 } 00966 00967 00968 /****************************************************************************************\ 00969 * YAML Parser * 00970 \****************************************************************************************/ 00971 00972 static char* 00973 icvYMLSkipSpaces( CvFileStorage* fs, char* ptr, int min_indent, int max_comment_indent ) 00974 { 00975 for(;;) 00976 { 00977 while( *ptr == ' ' ) 00978 ptr++; 00979 if( *ptr == '#' ) 00980 { 00981 if( ptr - fs->buffer_start > max_comment_indent ) 00982 return ptr; 00983 *ptr = '\0'; 00984 } 00985 else if( cv_isprint(*ptr) ) 00986 { 00987 if( ptr - fs->buffer_start < min_indent ) 00988 CV_PARSE_ERROR( "Incorrect indentation" ); 00989 break; 00990 } 00991 else if( *ptr == '\0' || *ptr == '\n' || *ptr == '\r' ) 00992 { 00993 int max_size = (int)(fs->buffer_end - fs->buffer_start); 00994 ptr = icvGets( fs, fs->buffer_start, max_size ); 00995 if( !ptr ) 00996 { 00997 // emulate end of stream 00998 ptr = fs->buffer_start; 00999 ptr[0] = ptr[1] = ptr[2] = '.'; 01000 ptr[3] = '\0'; 01001 fs->dummy_eof = 1; 01002 break; 01003 } 01004 else 01005 { 01006 int l = (int)strlen(ptr); 01007 if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) ) 01008 CV_PARSE_ERROR( "Too long string or a last string w/o newline" ); 01009 } 01010 01011 fs->lineno++; 01012 } 01013 else 01014 CV_PARSE_ERROR( *ptr == '\t' ? "Tabs are prohibited in YAML!" : "Invalid character" ); 01015 } 01016 01017 return ptr; 01018 } 01019 01020 01021 static char* 01022 icvYMLParseKey( CvFileStorage* fs, char* ptr, 01023 CvFileNode* map_node, CvFileNode** value_placeholder ) 01024 { 01025 char c; 01026 char *endptr = ptr - 1, *saveptr; 01027 CvStringHashNode* str_hash_node; 01028 01029 if( *ptr == '-' ) 01030 CV_PARSE_ERROR( "Key may not start with \'-\'" ); 01031 01032 do c = *++endptr; 01033 while( cv_isprint(c) && c != ':' ); 01034 01035 if( c != ':' ) 01036 CV_PARSE_ERROR( "Missing \':\'" ); 01037 01038 saveptr = endptr + 1; 01039 do c = *--endptr; 01040 while( c == ' ' ); 01041 01042 ++endptr; 01043 if( endptr == ptr ) 01044 CV_PARSE_ERROR( "An empty key" ); 01045 01046 str_hash_node = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 ); 01047 *value_placeholder = cvGetFileNode( fs, map_node, str_hash_node, 1 ); 01048 ptr = saveptr; 01049 01050 return ptr; 01051 } 01052 01053 01054 static char* 01055 icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node, 01056 int parent_flags, int min_indent ) 01057 { 01058 char buf[CV_FS_MAX_LEN + 1024]; 01059 char* endptr = 0; 01060 char c = ptr[0], d = ptr[1]; 01061 int is_parent_flow = CV_NODE_IS_FLOW(parent_flags); 01062 int value_type = CV_NODE_NONE; 01063 int len; 01064 01065 memset( node, 0, sizeof(*node) ); 01066 01067 if( c == '!' ) // handle explicit type specification 01068 { 01069 if( d == '!' || d == '^' ) 01070 { 01071 ptr++; 01072 value_type |= CV_NODE_USER; 01073 } 01074 01075 endptr = ptr++; 01076 do d = *++endptr; 01077 while( cv_isprint(d) && d != ' ' ); 01078 len = (int)(endptr - ptr); 01079 if( len == 0 ) 01080 CV_PARSE_ERROR( "Empty type name" ); 01081 d = *endptr; 01082 *endptr = '\0'; 01083 01084 if( len == 3 && !CV_NODE_IS_USER(value_type) ) 01085 { 01086 if( memcmp( ptr, "str", 3 ) == 0 ) 01087 value_type = CV_NODE_STRING; 01088 else if( memcmp( ptr, "int", 3 ) == 0 ) 01089 value_type = CV_NODE_INT; 01090 else if( memcmp( ptr, "seq", 3 ) == 0 ) 01091 value_type = CV_NODE_SEQ; 01092 else if( memcmp( ptr, "map", 3 ) == 0 ) 01093 value_type = CV_NODE_MAP; 01094 } 01095 else if( len == 5 && !CV_NODE_IS_USER(value_type) ) 01096 { 01097 if( memcmp( ptr, "float", 5 ) == 0 ) 01098 value_type = CV_NODE_REAL; 01099 } 01100 else if( CV_NODE_IS_USER(value_type) ) 01101 { 01102 node->info = cvFindType( ptr ); 01103 if( !node->info ) 01104 node->tag &= ~CV_NODE_USER; 01105 } 01106 01107 *endptr = d; 01108 ptr = icvYMLSkipSpaces( fs, endptr, min_indent, INT_MAX ); 01109 01110 c = *ptr; 01111 01112 if( !CV_NODE_IS_USER(value_type) ) 01113 { 01114 if( value_type == CV_NODE_STRING && c != '\'' && c != '\"' ) 01115 goto force_string; 01116 if( value_type == CV_NODE_INT ) 01117 goto force_int; 01118 if( value_type == CV_NODE_REAL ) 01119 goto force_real; 01120 } 01121 } 01122 01123 if( cv_isdigit(c) || 01124 ((c == '-' || c == '+') && (cv_isdigit(d) || d == '.')) || 01125 (c == '.' && cv_isalnum(d))) // a number 01126 { 01127 double fval; 01128 int ival; 01129 endptr = ptr + (c == '-' || c == '+'); 01130 while( cv_isdigit(*endptr) ) 01131 endptr++; 01132 if( *endptr == '.' || *endptr == 'e' ) 01133 { 01134 force_real: 01135 fval = icv_strtod( fs, ptr, &endptr ); 01136 /*if( endptr == ptr || cv_isalpha(*endptr) ) 01137 icvProcessSpecialDouble( fs, endptr, &fval, &endptr ));*/ 01138 01139 node->tag = CV_NODE_REAL; 01140 node->data.f = fval; 01141 } 01142 else 01143 { 01144 force_int: 01145 ival = (int)strtol( ptr, &endptr, 0 ); 01146 node->tag = CV_NODE_INT; 01147 node->data.i = ival; 01148 } 01149 01150 if( !endptr || endptr == ptr ) 01151 CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" ); 01152 01153 ptr = endptr; 01154 } 01155 else if( c == '\'' || c == '\"' ) // an explicit string 01156 { 01157 node->tag = CV_NODE_STRING; 01158 if( c == '\'' ) 01159 for( len = 0; len < CV_FS_MAX_LEN; ) 01160 { 01161 c = *++ptr; 01162 if( cv_isalnum(c) || (c != '\'' && cv_isprint(c))) 01163 buf[len++] = c; 01164 else if( c == '\'' ) 01165 { 01166 c = *++ptr; 01167 if( c != '\'' ) 01168 break; 01169 buf[len++] = c; 01170 } 01171 else 01172 CV_PARSE_ERROR( "Invalid character" ); 01173 } 01174 else 01175 for( len = 0; len < CV_FS_MAX_LEN; ) 01176 { 01177 c = *++ptr; 01178 if( cv_isalnum(c) || (c != '\\' && c != '\"' && cv_isprint(c))) 01179 buf[len++] = c; 01180 else if( c == '\"' ) 01181 { 01182 ++ptr; 01183 break; 01184 } 01185 else if( c == '\\' ) 01186 { 01187 d = *++ptr; 01188 if( d == '\'' ) 01189 buf[len++] = d; 01190 else if( d == '\"' || d == '\\' || d == '\'' ) 01191 buf[len++] = d; 01192 else if( d == 'n' ) 01193 buf[len++] = '\n'; 01194 else if( d == 'r' ) 01195 buf[len++] = '\r'; 01196 else if( d == 't' ) 01197 buf[len++] = '\t'; 01198 else if( d == 'x' || (cv_isdigit(d) && d < '8') ) 01199 { 01200 int val, is_hex = d == 'x'; 01201 c = ptr[3]; 01202 ptr[3] = '\0'; 01203 val = (int)strtol( ptr + is_hex, &endptr, is_hex ? 8 : 16 ); 01204 ptr[3] = c; 01205 if( endptr == ptr + is_hex ) 01206 buf[len++] = 'x'; 01207 else 01208 { 01209 buf[len++] = (char)val; 01210 ptr = endptr; 01211 } 01212 } 01213 } 01214 else 01215 CV_PARSE_ERROR( "Invalid character" ); 01216 } 01217 01218 if( len >= CV_FS_MAX_LEN ) 01219 CV_PARSE_ERROR( "Too long string literal" ); 01220 01221 node->data.str = cvMemStorageAllocString( fs->memstorage, buf, len ); 01222 } 01223 else if( c == '[' || c == '{' ) // collection as a flow 01224 { 01225 int new_min_indent = min_indent + !is_parent_flow; 01226 int struct_flags = CV_NODE_FLOW + (c == '{' ? CV_NODE_MAP : CV_NODE_SEQ); 01227 int is_simple = 1; 01228 01229 icvFSCreateCollection( fs, CV_NODE_TYPE(struct_flags) + 01230 (node->info ? CV_NODE_USER : 0), node ); 01231 01232 d = c == '[' ? ']' : '}'; 01233 01234 for( ++ptr ;;) 01235 { 01236 CvFileNode* elem = 0; 01237 01238 ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX ); 01239 if( *ptr == '}' || *ptr == ']' ) 01240 { 01241 if( *ptr != d ) 01242 CV_PARSE_ERROR( "The wrong closing bracket" ); 01243 ptr++; 01244 break; 01245 } 01246 01247 if( node->data.seq->total != 0 ) 01248 { 01249 if( *ptr != ',' ) 01250 CV_PARSE_ERROR( "Missing , between the elements" ); 01251 ptr = icvYMLSkipSpaces( fs, ptr + 1, new_min_indent, INT_MAX ); 01252 } 01253 01254 if( CV_NODE_IS_MAP(struct_flags) ) 01255 { 01256 ptr = icvYMLParseKey( fs, ptr, node, &elem ); 01257 ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX ); 01258 } 01259 else 01260 { 01261 if( *ptr == ']' ) 01262 break; 01263 elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ); 01264 } 01265 ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, new_min_indent ); 01266 if( CV_NODE_IS_MAP(struct_flags) ) 01267 elem->tag |= CV_NODE_NAMED; 01268 is_simple &= !CV_NODE_IS_COLLECTION(elem->tag); 01269 } 01270 node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0; 01271 } 01272 else 01273 { 01274 int indent, struct_flags, is_simple; 01275 01276 if( is_parent_flow || c != '-' ) 01277 { 01278 // implicit (one-line) string or nested block-style collection 01279 if( !is_parent_flow ) 01280 { 01281 if( c == '?' ) 01282 CV_PARSE_ERROR( "Complex keys are not supported" ); 01283 if( c == '|' || c == '>' ) 01284 CV_PARSE_ERROR( "Multi-line text literals are not supported" ); 01285 } 01286 01287 force_string: 01288 endptr = ptr - 1; 01289 01290 do c = *++endptr; 01291 while( cv_isprint(c) && 01292 (!is_parent_flow || (c != ',' && c != '}' && c != ']')) && 01293 (is_parent_flow || c != ':' || value_type == CV_NODE_STRING)); 01294 01295 if( endptr == ptr ) 01296 CV_PARSE_ERROR( "Invalid character" ); 01297 01298 if( is_parent_flow || c != ':' ) 01299 { 01300 char* str_end = endptr; 01301 node->tag = CV_NODE_STRING; 01302 // strip spaces in the end of string 01303 do c = *--str_end; 01304 while( str_end > ptr && c == ' ' ); 01305 str_end++; 01306 node->data.str = cvMemStorageAllocString( fs->memstorage, ptr, (int)(str_end - ptr) ); 01307 ptr = endptr; 01308 return ptr; 01309 } 01310 struct_flags = CV_NODE_MAP; 01311 } 01312 else 01313 struct_flags = CV_NODE_SEQ; 01314 01315 icvFSCreateCollection( fs, struct_flags + 01316 (node->info ? CV_NODE_USER : 0), node ); 01317 01318 indent = (int)(ptr - fs->buffer_start); 01319 is_simple = 1; 01320 01321 for(;;) 01322 { 01323 CvFileNode* elem = 0; 01324 01325 if( CV_NODE_IS_MAP(struct_flags) ) 01326 { 01327 ptr = icvYMLParseKey( fs, ptr, node, &elem ); 01328 } 01329 else 01330 { 01331 c = *ptr++; 01332 if( c != '-' ) 01333 CV_PARSE_ERROR( "Block sequence elements must be preceded with \'-\'" ); 01334 01335 elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ); 01336 } 01337 01338 ptr = icvYMLSkipSpaces( fs, ptr, indent + 1, INT_MAX ); 01339 ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, indent + 1 ); 01340 if( CV_NODE_IS_MAP(struct_flags) ) 01341 elem->tag |= CV_NODE_NAMED; 01342 is_simple &= !CV_NODE_IS_COLLECTION(elem->tag); 01343 01344 ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ); 01345 if( ptr - fs->buffer_start != indent ) 01346 { 01347 if( ptr - fs->buffer_start < indent ) 01348 break; 01349 else 01350 CV_PARSE_ERROR( "Incorrect indentation" ); 01351 } 01352 if( memcmp( ptr, "...", 3 ) == 0 ) 01353 break; 01354 } 01355 01356 node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0; 01357 } 01358 01359 return ptr; 01360 } 01361 01362 01363 static void 01364 icvYMLParse( CvFileStorage* fs ) 01365 { 01366 char* ptr = fs->buffer_start; 01367 int is_first = 1; 01368 01369 for(;;) 01370 { 01371 // 0. skip leading comments and directives and ... 01372 // 1. reach the first item 01373 for(;;) 01374 { 01375 ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ); 01376 if( !ptr ) 01377 return; 01378 01379 if( *ptr == '%' ) 01380 { 01381 if( memcmp( ptr, "%YAML:", 6 ) == 0 && 01382 memcmp( ptr, "%YAML:1.", 8 ) != 0 ) 01383 CV_PARSE_ERROR( "Unsupported YAML version (it must be 1.x)" ); 01384 *ptr = '\0'; 01385 } 01386 else if( *ptr == '-' ) 01387 { 01388 if( memcmp(ptr, "---", 3) == 0 ) 01389 { 01390 ptr += 3; 01391 break; 01392 } 01393 else if( is_first ) 01394 break; 01395 } 01396 else if( cv_isalnum(*ptr) || *ptr=='_') 01397 { 01398 if( !is_first ) 01399 CV_PARSE_ERROR( "The YAML streams must start with '---', except the first one" ); 01400 break; 01401 } 01402 else if( fs->dummy_eof ) 01403 break; 01404 else 01405 CV_PARSE_ERROR( "Invalid or unsupported syntax" ); 01406 } 01407 01408 ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ); 01409 if( memcmp( ptr, "...", 3 ) != 0 ) 01410 { 01411 // 2. parse the collection 01412 CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 ); 01413 01414 ptr = icvYMLParseValue( fs, ptr, root_node, CV_NODE_NONE, 0 ); 01415 if( !CV_NODE_IS_COLLECTION(root_node->tag) ) 01416 CV_PARSE_ERROR( "Only collections as YAML streams are supported by this parser" ); 01417 01418 // 3. parse until the end of file or next collection 01419 ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX ); 01420 if( !ptr ) 01421 return; 01422 } 01423 01424 if( fs->dummy_eof ) 01425 break; 01426 ptr += 3; 01427 is_first = 0; 01428 } 01429 } 01430 01431 01432 /****************************************************************************************\ 01433 * YAML Emitter * 01434 \****************************************************************************************/ 01435 01436 static void 01437 icvYMLWrite( CvFileStorage* fs, const char* key, const char* data ) 01438 { 01439 int i, keylen = 0; 01440 int datalen = 0; 01441 int struct_flags; 01442 char* ptr; 01443 01444 struct_flags = fs->struct_flags; 01445 01446 if( key && key[0] == '\0' ) 01447 key = 0; 01448 01449 if( CV_NODE_IS_COLLECTION(struct_flags) ) 01450 { 01451 if( (CV_NODE_IS_MAP(struct_flags) ^ (key != 0)) ) 01452 CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, " 01453 "or add element with key to sequence" ); 01454 } 01455 else 01456 { 01457 fs->is_first = 0; 01458 struct_flags = CV_NODE_EMPTY | (key ? CV_NODE_MAP : CV_NODE_SEQ); 01459 } 01460 01461 if( key ) 01462 { 01463 keylen = (int)strlen(key); 01464 if( keylen == 0 ) 01465 CV_Error( CV_StsBadArg, "The key is an empty" ); 01466 01467 if( keylen > CV_FS_MAX_LEN ) 01468 CV_Error( CV_StsBadArg, "The key is too long" ); 01469 } 01470 01471 if( data ) 01472 datalen = (int)strlen(data); 01473 01474 if( CV_NODE_IS_FLOW(struct_flags) ) 01475 { 01476 int new_offset; 01477 ptr = fs->buffer; 01478 if( !CV_NODE_IS_EMPTY(struct_flags) ) 01479 *ptr++ = ','; 01480 new_offset = (int)(ptr - fs->buffer_start) + keylen + datalen; 01481 if( new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10 ) 01482 { 01483 fs->buffer = ptr; 01484 ptr = icvFSFlush(fs); 01485 } 01486 else 01487 *ptr++ = ' '; 01488 } 01489 else 01490 { 01491 ptr = icvFSFlush(fs); 01492 if( !CV_NODE_IS_MAP(struct_flags) ) 01493 { 01494 *ptr++ = '-'; 01495 if( data ) 01496 *ptr++ = ' '; 01497 } 01498 } 01499 01500 if( key ) 01501 { 01502 if( !cv_isalpha(key[0]) && key[0] != '_' ) 01503 CV_Error( CV_StsBadArg, "Key must start with a letter or _" ); 01504 01505 ptr = icvFSResizeWriteBuffer( fs, ptr, keylen ); 01506 01507 for( i = 0; i < keylen; i++ ) 01508 { 01509 char c = key[i]; 01510 01511 ptr[i] = c; 01512 if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' ) 01513 CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" ); 01514 } 01515 01516 ptr += keylen; 01517 *ptr++ = ':'; 01518 if( !CV_NODE_IS_FLOW(struct_flags) && data ) 01519 *ptr++ = ' '; 01520 } 01521 01522 if( data ) 01523 { 01524 ptr = icvFSResizeWriteBuffer( fs, ptr, datalen ); 01525 memcpy( ptr, data, datalen ); 01526 ptr += datalen; 01527 } 01528 01529 fs->buffer = ptr; 01530 fs->struct_flags = struct_flags & ~CV_NODE_EMPTY; 01531 } 01532 01533 01534 static void 01535 icvYMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags, 01536 const char* type_name CV_DEFAULT(0)) 01537 { 01538 int parent_flags; 01539 char buf[CV_FS_MAX_LEN + 1024]; 01540 const char* data = 0; 01541 01542 struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY; 01543 if( !CV_NODE_IS_COLLECTION(struct_flags)) 01544 CV_Error( CV_StsBadArg, 01545 "Some collection type - CV_NODE_SEQ or CV_NODE_MAP, must be specified" ); 01546 01547 if( CV_NODE_IS_FLOW(struct_flags) ) 01548 { 01549 char c = CV_NODE_IS_MAP(struct_flags) ? '{' : '['; 01550 struct_flags |= CV_NODE_FLOW; 01551 01552 if( type_name ) 01553 sprintf( buf, "!!%s %c", type_name, c ); 01554 else 01555 { 01556 buf[0] = c; 01557 buf[1] = '\0'; 01558 } 01559 data = buf; 01560 } 01561 else if( type_name ) 01562 { 01563 sprintf( buf, "!!%s", type_name ); 01564 data = buf; 01565 } 01566 01567 icvYMLWrite( fs, key, data ); 01568 01569 parent_flags = fs->struct_flags; 01570 cvSeqPush( fs->write_stack, &parent_flags ); 01571 fs->struct_flags = struct_flags; 01572 01573 if( !CV_NODE_IS_FLOW(parent_flags) ) 01574 fs->struct_indent += CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags); 01575 } 01576 01577 01578 static void 01579 icvYMLEndWriteStruct( CvFileStorage* fs ) 01580 { 01581 int parent_flags = 0, struct_flags; 01582 char* ptr; 01583 01584 struct_flags = fs->struct_flags; 01585 if( fs->write_stack->total == 0 ) 01586 CV_Error( CV_StsError, "EndWriteStruct w/o matching StartWriteStruct" ); 01587 01588 cvSeqPop( fs->write_stack, &parent_flags ); 01589 01590 if( CV_NODE_IS_FLOW(struct_flags) ) 01591 { 01592 ptr = fs->buffer; 01593 if( ptr > fs->buffer_start + fs->struct_indent && !CV_NODE_IS_EMPTY(struct_flags) ) 01594 *ptr++ = ' '; 01595 *ptr++ = CV_NODE_IS_MAP(struct_flags) ? '}' : ']'; 01596 fs->buffer = ptr; 01597 } 01598 else if( CV_NODE_IS_EMPTY(struct_flags) ) 01599 { 01600 ptr = icvFSFlush(fs); 01601 memcpy( ptr, CV_NODE_IS_MAP(struct_flags) ? "{}" : "[]", 2 ); 01602 fs->buffer = ptr + 2; 01603 } 01604 01605 if( !CV_NODE_IS_FLOW(parent_flags) ) 01606 fs->struct_indent -= CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags); 01607 assert( fs->struct_indent >= 0 ); 01608 01609 fs->struct_flags = parent_flags; 01610 } 01611 01612 01613 static void 01614 icvYMLStartNextStream( CvFileStorage* fs ) 01615 { 01616 if( !fs->is_first ) 01617 { 01618 while( fs->write_stack->total > 0 ) 01619 icvYMLEndWriteStruct(fs); 01620 01621 fs->struct_indent = 0; 01622 icvFSFlush(fs); 01623 icvPuts( fs, "...\n" ); 01624 icvPuts( fs, "---\n" ); 01625 fs->buffer = fs->buffer_start; 01626 } 01627 } 01628 01629 01630 static void 01631 icvYMLWriteInt( CvFileStorage* fs, const char* key, int value ) 01632 { 01633 char buf[128]; 01634 icvYMLWrite( fs, key, icv_itoa( value, buf, 10 )); 01635 } 01636 01637 01638 static void 01639 icvYMLWriteReal( CvFileStorage* fs, const char* key, double value ) 01640 { 01641 char buf[128]; 01642 icvYMLWrite( fs, key, icvDoubleToString( buf, value )); 01643 } 01644 01645 01646 static void 01647 icvYMLWriteString( CvFileStorage* fs, const char* key, 01648 const char* str, int quote CV_DEFAULT(0)) 01649 { 01650 char buf[CV_FS_MAX_LEN*4+16]; 01651 char* data = (char*)str; 01652 int i, len; 01653 01654 if( !str ) 01655 CV_Error( CV_StsNullPtr, "Null string pointer" ); 01656 01657 len = (int)strlen(str); 01658 if( len > CV_FS_MAX_LEN ) 01659 CV_Error( CV_StsBadArg, "The written string is too long" ); 01660 01661 if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') ) 01662 { 01663 int need_quote = quote || len == 0; 01664 data = buf; 01665 *data++ = '\"'; 01666 for( i = 0; i < len; i++ ) 01667 { 01668 char c = str[i]; 01669 01670 if( !need_quote && !cv_isalnum(c) && c != '_' && c != ' ' && c != '-' && 01671 c != '(' && c != ')' && c != '/' && c != '+' && c != ';' ) 01672 need_quote = 1; 01673 01674 if( !cv_isalnum(c) && (!cv_isprint(c) || c == '\\' || c == '\'' || c == '\"') ) 01675 { 01676 *data++ = '\\'; 01677 if( cv_isprint(c) ) 01678 *data++ = c; 01679 else if( c == '\n' ) 01680 *data++ = 'n'; 01681 else if( c == '\r' ) 01682 *data++ = 'r'; 01683 else if( c == '\t' ) 01684 *data++ = 't'; 01685 else 01686 { 01687 sprintf( data, "x%02x", c ); 01688 data += 3; 01689 } 01690 } 01691 else 01692 *data++ = c; 01693 } 01694 if( !need_quote && (cv_isdigit(str[0]) || 01695 str[0] == '+' || str[0] == '-' || str[0] == '.' )) 01696 need_quote = 1; 01697 01698 if( need_quote ) 01699 *data++ = '\"'; 01700 *data++ = '\0'; 01701 data = buf + !need_quote; 01702 } 01703 01704 icvYMLWrite( fs, key, data ); 01705 } 01706 01707 01708 static void 01709 icvYMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment ) 01710 { 01711 int len; //, indent; 01712 int multiline; 01713 const char* eol; 01714 char* ptr; 01715 01716 if( !comment ) 01717 CV_Error( CV_StsNullPtr, "Null comment" ); 01718 01719 len = (int)strlen(comment); 01720 eol = strchr(comment, '\n'); 01721 multiline = eol != 0; 01722 ptr = fs->buffer; 01723 01724 if( !eol_comment || multiline || 01725 fs->buffer_end - ptr < len || ptr == fs->buffer_start ) 01726 ptr = icvFSFlush( fs ); 01727 else 01728 *ptr++ = ' '; 01729 01730 while( comment ) 01731 { 01732 *ptr++ = '#'; 01733 *ptr++ = ' '; 01734 if( eol ) 01735 { 01736 ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 ); 01737 memcpy( ptr, comment, eol - comment + 1 ); 01738 fs->buffer = ptr + (eol - comment); 01739 comment = eol + 1; 01740 eol = strchr( comment, '\n' ); 01741 } 01742 else 01743 { 01744 len = (int)strlen(comment); 01745 ptr = icvFSResizeWriteBuffer( fs, ptr, len ); 01746 memcpy( ptr, comment, len ); 01747 fs->buffer = ptr + len; 01748 comment = 0; 01749 } 01750 ptr = icvFSFlush( fs ); 01751 } 01752 } 01753 01754 01755 /****************************************************************************************\ 01756 * XML Parser * 01757 \****************************************************************************************/ 01758 01759 #define CV_XML_INSIDE_COMMENT 1 01760 #define CV_XML_INSIDE_TAG 2 01761 #define CV_XML_INSIDE_DIRECTIVE 3 01762 01763 static char* 01764 icvXMLSkipSpaces( CvFileStorage* fs, char* ptr, int mode ) 01765 { 01766 int level = 0; 01767 01768 for(;;) 01769 { 01770 char c; 01771 ptr--; 01772 01773 if( mode == CV_XML_INSIDE_COMMENT ) 01774 { 01775 do c = *++ptr; 01776 while( cv_isprint_or_tab(c) && (c != '-' || ptr[1] != '-' || ptr[2] != '>') ); 01777 01778 if( c == '-' ) 01779 { 01780 assert( ptr[1] == '-' && ptr[2] == '>' ); 01781 mode = 0; 01782 ptr += 3; 01783 } 01784 } 01785 else if( mode == CV_XML_INSIDE_DIRECTIVE ) 01786 { 01787 // !!!NOTE!!! This is not quite correct, but should work in most cases 01788 do 01789 { 01790 c = *++ptr; 01791 level += c == '<'; 01792 level -= c == '>'; 01793 if( level < 0 ) 01794 return ptr; 01795 } while( cv_isprint_or_tab(c) ); 01796 } 01797 else 01798 { 01799 do c = *++ptr; 01800 while( c == ' ' || c == '\t' ); 01801 01802 if( c == '<' && ptr[1] == '!' && ptr[2] == '-' && ptr[3] == '-' ) 01803 { 01804 if( mode != 0 ) 01805 CV_PARSE_ERROR( "Comments are not allowed here" ); 01806 mode = CV_XML_INSIDE_COMMENT; 01807 ptr += 4; 01808 } 01809 else if( cv_isprint(c) ) 01810 break; 01811 } 01812 01813 if( !cv_isprint(*ptr) ) 01814 { 01815 int max_size = (int)(fs->buffer_end - fs->buffer_start); 01816 if( *ptr != '\0' && *ptr != '\n' && *ptr != '\r' ) 01817 CV_PARSE_ERROR( "Invalid character in the stream" ); 01818 ptr = icvGets( fs, fs->buffer_start, max_size ); 01819 if( !ptr ) 01820 { 01821 ptr = fs->buffer_start; 01822 *ptr = '\0'; 01823 fs->dummy_eof = 1; 01824 break; 01825 } 01826 else 01827 { 01828 int l = (int)strlen(ptr); 01829 if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) ) 01830 CV_PARSE_ERROR( "Too long string or a last string w/o newline" ); 01831 } 01832 fs->lineno++; 01833 } 01834 } 01835 return ptr; 01836 } 01837 01838 01839 static char* 01840 icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag, 01841 CvAttrList** _list, int* _tag_type ); 01842 01843 static char* 01844 icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node, 01845 int value_type CV_DEFAULT(CV_NODE_NONE)) 01846 { 01847 CvFileNode *elem = node; 01848 int have_space = 1, is_simple = 1; 01849 int is_user_type = CV_NODE_IS_USER(value_type); 01850 memset( node, 0, sizeof(*node) ); 01851 01852 value_type = CV_NODE_TYPE(value_type); 01853 01854 for(;;) 01855 { 01856 char c = *ptr, d; 01857 char* endptr; 01858 01859 if( cv_isspace(c) || c == '\0' || (c == '<' && ptr[1] == '!' && ptr[2] == '-') ) 01860 { 01861 ptr = icvXMLSkipSpaces( fs, ptr, 0 ); 01862 have_space = 1; 01863 c = *ptr; 01864 } 01865 01866 d = ptr[1]; 01867 01868 if( c =='<' || c == '\0' ) 01869 { 01870 CvStringHashNode *key = 0, *key2 = 0; 01871 CvAttrList* list = 0; 01872 CvTypeInfo* info = 0; 01873 int tag_type = 0; 01874 int is_noname = 0; 01875 const char* type_name = 0; 01876 int elem_type = CV_NODE_NONE; 01877 01878 if( d == '/' || c == '\0' ) 01879 break; 01880 01881 ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ); 01882 01883 if( tag_type == CV_XML_DIRECTIVE_TAG ) 01884 CV_PARSE_ERROR( "Directive tags are not allowed here" ); 01885 if( tag_type == CV_XML_EMPTY_TAG ) 01886 CV_PARSE_ERROR( "Empty tags are not supported" ); 01887 01888 assert( tag_type == CV_XML_OPENING_TAG ); 01889 01890 type_name = list ? cvAttrValue( list, "type_id" ) : 0; 01891 if( type_name ) 01892 { 01893 if( strcmp( type_name, "str" ) == 0 ) 01894 elem_type = CV_NODE_STRING; 01895 else if( strcmp( type_name, "map" ) == 0 ) 01896 elem_type = CV_NODE_MAP; 01897 else if( strcmp( type_name, "seq" ) == 0 ) 01898 elem_type = CV_NODE_SEQ; 01899 else 01900 { 01901 info = cvFindType( type_name ); 01902 if( info ) 01903 elem_type = CV_NODE_USER; 01904 } 01905 } 01906 01907 is_noname = key->str.len == 1 && key->str.ptr[0] == '_'; 01908 if( !CV_NODE_IS_COLLECTION(node->tag) ) 01909 { 01910 icvFSCreateCollection( fs, is_noname ? CV_NODE_SEQ : CV_NODE_MAP, node ); 01911 } 01912 else if( is_noname ^ CV_NODE_IS_SEQ(node->tag) ) 01913 CV_PARSE_ERROR( is_noname ? "Map element should have a name" : 01914 "Sequence element should not have name (use <_></_>)" ); 01915 01916 if( is_noname ) 01917 elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ); 01918 else 01919 elem = cvGetFileNode( fs, node, key, 1 ); 01920 01921 ptr = icvXMLParseValue( fs, ptr, elem, elem_type); 01922 if( !is_noname ) 01923 elem->tag |= CV_NODE_NAMED; 01924 is_simple &= !CV_NODE_IS_COLLECTION(elem->tag); 01925 elem->info = info; 01926 ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type ); 01927 if( tag_type != CV_XML_CLOSING_TAG || key2 != key ) 01928 CV_PARSE_ERROR( "Mismatched closing tag" ); 01929 have_space = 1; 01930 } 01931 else 01932 { 01933 if( !have_space ) 01934 CV_PARSE_ERROR( "There should be space between literals" ); 01935 01936 elem = node; 01937 if( node->tag != CV_NODE_NONE ) 01938 { 01939 if( !CV_NODE_IS_COLLECTION(node->tag) ) 01940 icvFSCreateCollection( fs, CV_NODE_SEQ, node ); 01941 01942 elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 ); 01943 elem->info = 0; 01944 } 01945 01946 if( value_type != CV_NODE_STRING && 01947 (cv_isdigit(c) || ((c == '-' || c == '+') && 01948 (cv_isdigit(d) || d == '.')) || (c == '.' && cv_isalnum(d))) ) // a number 01949 { 01950 double fval; 01951 int ival; 01952 endptr = ptr + (c == '-' || c == '+'); 01953 while( cv_isdigit(*endptr) ) 01954 endptr++; 01955 if( *endptr == '.' || *endptr == 'e' ) 01956 { 01957 fval = icv_strtod( fs, ptr, &endptr ); 01958 /*if( endptr == ptr || cv_isalpha(*endptr) ) 01959 icvProcessSpecialDouble( fs, ptr, &fval, &endptr ));*/ 01960 elem->tag = CV_NODE_REAL; 01961 elem->data.f = fval; 01962 } 01963 else 01964 { 01965 ival = (int)strtol( ptr, &endptr, 0 ); 01966 elem->tag = CV_NODE_INT; 01967 elem->data.i = ival; 01968 } 01969 01970 if( endptr == ptr ) 01971 CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" ); 01972 01973 ptr = endptr; 01974 } 01975 else 01976 { 01977 // string 01978 char buf[CV_FS_MAX_LEN+16]; 01979 int i = 0, len, is_quoted = 0; 01980 elem->tag = CV_NODE_STRING; 01981 if( c == '\"' ) 01982 is_quoted = 1; 01983 else 01984 --ptr; 01985 01986 for( ;; ) 01987 { 01988 c = *++ptr; 01989 if( !cv_isalnum(c) ) 01990 { 01991 if( c == '\"' ) 01992 { 01993 if( !is_quoted ) 01994 CV_PARSE_ERROR( "Literal \" is not allowed within a string. Use "" ); 01995 ++ptr; 01996 break; 01997 } 01998 else if( !cv_isprint(c) || c == '<' || (!is_quoted && cv_isspace(c))) 01999 { 02000 if( is_quoted ) 02001 CV_PARSE_ERROR( "Closing \" is expected" ); 02002 break; 02003 } 02004 else if( c == '\'' || c == '>' ) 02005 { 02006 CV_PARSE_ERROR( "Literal \' or > are not allowed. Use ' or >" ); 02007 } 02008 else if( c == '&' ) 02009 { 02010 if( *++ptr == '#' ) 02011 { 02012 int val, base = 10; 02013 ptr++; 02014 if( *ptr == 'x' ) 02015 { 02016 base = 16; 02017 ptr++; 02018 } 02019 val = (int)strtol( ptr, &endptr, base ); 02020 if( (unsigned)val > (unsigned)255 || 02021 !endptr || *endptr != ';' ) 02022 CV_PARSE_ERROR( "Invalid numeric value in the string" ); 02023 c = (char)val; 02024 } 02025 else 02026 { 02027 endptr = ptr; 02028 do c = *++endptr; 02029 while( cv_isalnum(c) ); 02030 if( c != ';' ) 02031 CV_PARSE_ERROR( "Invalid character in the symbol entity name" ); 02032 len = (int)(endptr - ptr); 02033 if( len == 2 && memcmp( ptr, "lt", len ) == 0 ) 02034 c = '<'; 02035 else if( len == 2 && memcmp( ptr, "gt", len ) == 0 ) 02036 c = '>'; 02037 else if( len == 3 && memcmp( ptr, "amp", len ) == 0 ) 02038 c = '&'; 02039 else if( len == 4 && memcmp( ptr, "apos", len ) == 0 ) 02040 c = '\''; 02041 else if( len == 4 && memcmp( ptr, "quot", len ) == 0 ) 02042 c = '\"'; 02043 else 02044 { 02045 memcpy( buf + i, ptr-1, len + 2 ); 02046 i += len + 2; 02047 } 02048 } 02049 ptr = endptr; 02050 } 02051 } 02052 buf[i++] = c; 02053 if( i >= CV_FS_MAX_LEN ) 02054 CV_PARSE_ERROR( "Too long string literal" ); 02055 } 02056 elem->data.str = cvMemStorageAllocString( fs->memstorage, buf, i ); 02057 } 02058 02059 if( !CV_NODE_IS_COLLECTION(value_type) && value_type != CV_NODE_NONE ) 02060 break; 02061 have_space = 0; 02062 } 02063 } 02064 02065 if( (CV_NODE_TYPE(node->tag) == CV_NODE_NONE || 02066 (CV_NODE_TYPE(node->tag) != value_type && 02067 !CV_NODE_IS_COLLECTION(node->tag))) && 02068 CV_NODE_IS_COLLECTION(value_type) ) 02069 { 02070 icvFSCreateCollection( fs, CV_NODE_IS_MAP(value_type) ? 02071 CV_NODE_MAP : CV_NODE_SEQ, node ); 02072 } 02073 02074 if( value_type != CV_NODE_NONE && 02075 value_type != CV_NODE_TYPE(node->tag) ) 02076 CV_PARSE_ERROR( "The actual type is different from the specified type" ); 02077 02078 if( CV_NODE_IS_COLLECTION(node->tag) && is_simple ) 02079 node->data.seq->flags |= CV_NODE_SEQ_SIMPLE; 02080 02081 node->tag |= is_user_type ? CV_NODE_USER : 0; 02082 return ptr; 02083 } 02084 02085 02086 static char* 02087 icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag, 02088 CvAttrList** _list, int* _tag_type ) 02089 { 02090 int tag_type = 0; 02091 CvStringHashNode* tagname = 0; 02092 CvAttrList *first = 0, *last = 0; 02093 int count = 0, max_count = 4; 02094 int attr_buf_size = (max_count*2 + 1)*sizeof(char*) + sizeof(CvAttrList); 02095 char* endptr; 02096 char c; 02097 int have_space; 02098 02099 if( *ptr == '\0' ) 02100 CV_PARSE_ERROR( "Preliminary end of the stream" ); 02101 02102 if( *ptr != '<' ) 02103 CV_PARSE_ERROR( "Tag should start with \'<\'" ); 02104 02105 ptr++; 02106 if( cv_isalnum(*ptr) || *ptr == '_' ) 02107 tag_type = CV_XML_OPENING_TAG; 02108 else if( *ptr == '/' ) 02109 { 02110 tag_type = CV_XML_CLOSING_TAG; 02111 ptr++; 02112 } 02113 else if( *ptr == '?' ) 02114 { 02115 tag_type = CV_XML_HEADER_TAG; 02116 ptr++; 02117 } 02118 else if( *ptr == '!' ) 02119 { 02120 tag_type = CV_XML_DIRECTIVE_TAG; 02121 assert( ptr[1] != '-' || ptr[2] != '-' ); 02122 ptr++; 02123 } 02124 else 02125 CV_PARSE_ERROR( "Unknown tag type" ); 02126 02127 for(;;) 02128 { 02129 CvStringHashNode* attrname; 02130 02131 if( !cv_isalpha(*ptr) && *ptr != '_' ) 02132 CV_PARSE_ERROR( "Name should start with a letter or underscore" ); 02133 02134 endptr = ptr - 1; 02135 do c = *++endptr; 02136 while( cv_isalnum(c) || c == '_' || c == '-' ); 02137 02138 attrname = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 ); 02139 ptr = endptr; 02140 02141 if( !tagname ) 02142 tagname = attrname; 02143 else 02144 { 02145 if( tag_type == CV_XML_CLOSING_TAG ) 02146 CV_PARSE_ERROR( "Closing tag should not contain any attributes" ); 02147 02148 if( !last || count >= max_count ) 02149 { 02150 CvAttrList* chunk; 02151 02152 chunk = (CvAttrList*)cvMemStorageAlloc( fs->memstorage, attr_buf_size ); 02153 memset( chunk, 0, attr_buf_size ); 02154 chunk->attr = (const char**)(chunk + 1); 02155 count = 0; 02156 if( !last ) 02157 first = last = chunk; 02158 else 02159 last = last->next = chunk; 02160 } 02161 last->attr[count*2] = attrname->str.ptr; 02162 } 02163 02164 if( last ) 02165 { 02166 CvFileNode stub; 02167 02168 if( *ptr != '=' ) 02169 { 02170 ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ); 02171 if( *ptr != '=' ) 02172 CV_PARSE_ERROR( "Attribute name should be followed by \'=\'" ); 02173 } 02174 02175 c = *++ptr; 02176 if( c != '\"' && c != '\'' ) 02177 { 02178 ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ); 02179 if( *ptr != '\"' && *ptr != '\'' ) 02180 CV_PARSE_ERROR( "Attribute value should be put into single or double quotes" ); 02181 } 02182 02183 ptr = icvXMLParseValue( fs, ptr, &stub, CV_NODE_STRING ); 02184 assert( stub.tag == CV_NODE_STRING ); 02185 last->attr[count*2+1] = stub.data.str.ptr; 02186 count++; 02187 } 02188 02189 c = *ptr; 02190 have_space = cv_isspace(c) || c == '\0'; 02191 02192 if( c != '>' ) 02193 { 02194 ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ); 02195 c = *ptr; 02196 } 02197 02198 if( c == '>' ) 02199 { 02200 if( tag_type == CV_XML_HEADER_TAG ) 02201 CV_PARSE_ERROR( "Invalid closing tag for <?xml ..." ); 02202 ptr++; 02203 break; 02204 } 02205 else if( c == '?' && tag_type == CV_XML_HEADER_TAG ) 02206 { 02207 if( ptr[1] != '>' ) 02208 CV_PARSE_ERROR( "Invalid closing tag for <?xml ..." ); 02209 ptr += 2; 02210 break; 02211 } 02212 else if( c == '/' && ptr[1] == '>' && tag_type == CV_XML_OPENING_TAG ) 02213 { 02214 tag_type = CV_XML_EMPTY_TAG; 02215 ptr += 2; 02216 break; 02217 } 02218 02219 if( !have_space ) 02220 CV_PARSE_ERROR( "There should be space between attributes" ); 02221 } 02222 02223 *_tag = tagname; 02224 *_tag_type = tag_type; 02225 *_list = first; 02226 02227 return ptr; 02228 } 02229 02230 02231 static void 02232 icvXMLParse( CvFileStorage* fs ) 02233 { 02234 char* ptr = fs->buffer_start; 02235 CvStringHashNode *key = 0, *key2 = 0; 02236 CvAttrList* list = 0; 02237 int tag_type = 0; 02238 02239 // CV_XML_INSIDE_TAG is used to prohibit leading comments 02240 ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG ); 02241 02242 if( memcmp( ptr, "<?xml", 5 ) != 0 ) 02243 CV_PARSE_ERROR( "Valid XML should start with \'<?xml ...?>\'" ); 02244 02245 ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ); 02246 02247 /*{ 02248 const char* version = cvAttrValue( list, "version" ); 02249 if( version && strncmp( version, "1.", 2 ) != 0 ) 02250 CV_Error( CV_StsParseError, "Unsupported version of XML" ); 02251 }*/ 02252 // we support any 8-bit encoding, so we do not need to check the actual encoding. 02253 // we do not support utf-16, but in the case of utf-16 we will not get here anyway. 02254 /*{ 02255 const char* encoding = cvAttrValue( list, "encoding" ); 02256 if( encoding && strcmp( encoding, "ASCII" ) != 0 && 02257 strcmp( encoding, "UTF-8" ) != 0 && 02258 strcmp( encoding, "utf-8" ) != 0 ) 02259 CV_PARSE_ERROR( "Unsupported encoding" ); 02260 }*/ 02261 02262 while( *ptr != '\0' ) 02263 { 02264 ptr = icvXMLSkipSpaces( fs, ptr, 0 ); 02265 02266 if( *ptr != '\0' ) 02267 { 02268 CvFileNode* root_node; 02269 ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type ); 02270 if( tag_type != CV_XML_OPENING_TAG || 02271 strcmp(key->str.ptr,"opencv_storage") != 0 ) 02272 CV_PARSE_ERROR( "<opencv_storage> tag is missing" ); 02273 02274 root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 ); 02275 ptr = icvXMLParseValue( fs, ptr, root_node, CV_NODE_NONE ); 02276 ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type ); 02277 if( tag_type != CV_XML_CLOSING_TAG || key != key2 ) 02278 CV_PARSE_ERROR( "</opencv_storage> tag is missing" ); 02279 ptr = icvXMLSkipSpaces( fs, ptr, 0 ); 02280 } 02281 } 02282 02283 assert( fs->dummy_eof != 0 ); 02284 } 02285 02286 02287 /****************************************************************************************\ 02288 * XML Emitter * 02289 \****************************************************************************************/ 02290 02291 #define icvXMLFlush icvFSFlush 02292 02293 static void 02294 icvXMLWriteTag( CvFileStorage* fs, const char* key, int tag_type, CvAttrList list ) 02295 { 02296 char* ptr = fs->buffer; 02297 int i, len = 0; 02298 int struct_flags = fs->struct_flags; 02299 02300 if( key && key[0] == '\0' ) 02301 key = 0; 02302 02303 if( tag_type == CV_XML_OPENING_TAG || tag_type == CV_XML_EMPTY_TAG ) 02304 { 02305 if( CV_NODE_IS_COLLECTION(struct_flags) ) 02306 { 02307 if( CV_NODE_IS_MAP(struct_flags) ^ (key != 0) ) 02308 CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, " 02309 "or add element with key to sequence" ); 02310 } 02311 else 02312 { 02313 struct_flags = CV_NODE_EMPTY + (key ? CV_NODE_MAP : CV_NODE_SEQ); 02314 fs->is_first = 0; 02315 } 02316 02317 if( !CV_NODE_IS_EMPTY(struct_flags) ) 02318 ptr = icvXMLFlush(fs); 02319 } 02320 02321 if( !key ) 02322 key = "_"; 02323 else if( key[0] == '_' && key[1] == '\0' ) 02324 CV_Error( CV_StsBadArg, "A single _ is a reserved tag name" ); 02325 02326 len = (int)strlen( key ); 02327 *ptr++ = '<'; 02328 if( tag_type == CV_XML_CLOSING_TAG ) 02329 { 02330 if( list.attr ) 02331 CV_Error( CV_StsBadArg, "Closing tag should not include any attributes" ); 02332 *ptr++ = '/'; 02333 } 02334 02335 if( !cv_isalpha(key[0]) && key[0] != '_' ) 02336 CV_Error( CV_StsBadArg, "Key should start with a letter or _" ); 02337 02338 ptr = icvFSResizeWriteBuffer( fs, ptr, len ); 02339 for( i = 0; i < len; i++ ) 02340 { 02341 char c = key[i]; 02342 if( !cv_isalnum(c) && c != '_' && c != '-' ) 02343 CV_Error( CV_StsBadArg, "Key name may only contain alphanumeric characters [a-zA-Z0-9], '-' and '_'" ); 02344 ptr[i] = c; 02345 } 02346 ptr += len; 02347 02348 for(;;) 02349 { 02350 const char** attr = list.attr; 02351 02352 for( ; attr && attr[0] != 0; attr += 2 ) 02353 { 02354 int len0 = (int)strlen(attr[0]); 02355 int len1 = (int)strlen(attr[1]); 02356 02357 ptr = icvFSResizeWriteBuffer( fs, ptr, len0 + len1 + 4 ); 02358 *ptr++ = ' '; 02359 memcpy( ptr, attr[0], len0 ); 02360 ptr += len0; 02361 *ptr++ = '='; 02362 *ptr++ = '\"'; 02363 memcpy( ptr, attr[1], len1 ); 02364 ptr += len1; 02365 *ptr++ = '\"'; 02366 } 02367 if( !list.next ) 02368 break; 02369 list = *list.next; 02370 } 02371 02372 if( tag_type == CV_XML_EMPTY_TAG ) 02373 *ptr++ = '/'; 02374 *ptr++ = '>'; 02375 fs->buffer = ptr; 02376 fs->struct_flags = struct_flags & ~CV_NODE_EMPTY; 02377 } 02378 02379 02380 static void 02381 icvXMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags, 02382 const char* type_name CV_DEFAULT(0)) 02383 { 02384 CvXMLStackRecord parent; 02385 const char* attr[10]; 02386 int idx = 0; 02387 02388 struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY; 02389 if( !CV_NODE_IS_COLLECTION(struct_flags)) 02390 CV_Error( CV_StsBadArg, 02391 "Some collection type: CV_NODE_SEQ or CV_NODE_MAP must be specified" ); 02392 02393 if( type_name ) 02394 { 02395 attr[idx++] = "type_id"; 02396 attr[idx++] = type_name; 02397 } 02398 attr[idx++] = 0; 02399 02400 icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(attr,0) ); 02401 02402 parent.struct_flags = fs->struct_flags & ~CV_NODE_EMPTY; 02403 parent.struct_indent = fs->struct_indent; 02404 parent.struct_tag = fs->struct_tag; 02405 cvSaveMemStoragePos( fs->strstorage, &parent.pos ); 02406 cvSeqPush( fs->write_stack, &parent ); 02407 02408 fs->struct_indent += CV_XML_INDENT; 02409 if( !CV_NODE_IS_FLOW(struct_flags) ) 02410 icvXMLFlush( fs ); 02411 02412 fs->struct_flags = struct_flags; 02413 if( key ) 02414 { 02415 fs->struct_tag = cvMemStorageAllocString( fs->strstorage, (char*)key, -1 ); 02416 } 02417 else 02418 { 02419 fs->struct_tag.ptr = 0; 02420 fs->struct_tag.len = 0; 02421 } 02422 } 02423 02424 02425 static void 02426 icvXMLEndWriteStruct( CvFileStorage* fs ) 02427 { 02428 CvXMLStackRecord parent; 02429 02430 if( fs->write_stack->total == 0 ) 02431 CV_Error( CV_StsError, "An extra closing tag" ); 02432 02433 icvXMLWriteTag( fs, fs->struct_tag.ptr, CV_XML_CLOSING_TAG, cvAttrList(0,0) ); 02434 cvSeqPop( fs->write_stack, &parent ); 02435 02436 fs->struct_indent = parent.struct_indent; 02437 fs->struct_flags = parent.struct_flags; 02438 fs->struct_tag = parent.struct_tag; 02439 cvRestoreMemStoragePos( fs->strstorage, &parent.pos ); 02440 } 02441 02442 02443 static void 02444 icvXMLStartNextStream( CvFileStorage* fs ) 02445 { 02446 if( !fs->is_first ) 02447 { 02448 while( fs->write_stack->total > 0 ) 02449 icvXMLEndWriteStruct(fs); 02450 02451 fs->struct_indent = 0; 02452 icvXMLFlush(fs); 02453 /* XML does not allow multiple top-level elements, 02454 so we just put a comment and continue 02455 the current (and the only) "stream" */ 02456 icvPuts( fs, "\n<!-- next stream -->\n" ); 02457 /*fputs( "</opencv_storage>\n", fs->file ); 02458 fputs( "<opencv_storage>\n", fs->file );*/ 02459 fs->buffer = fs->buffer_start; 02460 } 02461 } 02462 02463 02464 static void 02465 icvXMLWriteScalar( CvFileStorage* fs, const char* key, const char* data, int len ) 02466 { 02467 if( CV_NODE_IS_MAP(fs->struct_flags) || 02468 (!CV_NODE_IS_COLLECTION(fs->struct_flags) && key) ) 02469 { 02470 icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(0,0) ); 02471 char* ptr = icvFSResizeWriteBuffer( fs, fs->buffer, len ); 02472 memcpy( ptr, data, len ); 02473 fs->buffer = ptr + len; 02474 icvXMLWriteTag( fs, key, CV_XML_CLOSING_TAG, cvAttrList(0,0) ); 02475 } 02476 else 02477 { 02478 char* ptr = fs->buffer; 02479 int new_offset = (int)(ptr - fs->buffer_start) + len; 02480 02481 if( key ) 02482 CV_Error( CV_StsBadArg, "elements with keys can not be written to sequence" ); 02483 02484 fs->struct_flags = CV_NODE_SEQ; 02485 02486 if( (new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10) || 02487 (ptr > fs->buffer_start && ptr[-1] == '>' && !CV_NODE_IS_EMPTY(fs->struct_flags)) ) 02488 { 02489 ptr = icvXMLFlush(fs); 02490 } 02491 else if( ptr > fs->buffer_start + fs->struct_indent && ptr[-1] != '>' ) 02492 *ptr++ = ' '; 02493 02494 memcpy( ptr, data, len ); 02495 fs->buffer = ptr + len; 02496 } 02497 } 02498 02499 02500 static void 02501 icvXMLWriteInt( CvFileStorage* fs, const char* key, int value ) 02502 { 02503 char buf[128], *ptr = icv_itoa( value, buf, 10 ); 02504 int len = (int)strlen(ptr); 02505 icvXMLWriteScalar( fs, key, ptr, len ); 02506 } 02507 02508 02509 static void 02510 icvXMLWriteReal( CvFileStorage* fs, const char* key, double value ) 02511 { 02512 char buf[128]; 02513 int len = (int)strlen( icvDoubleToString( buf, value )); 02514 icvXMLWriteScalar( fs, key, buf, len ); 02515 } 02516 02517 02518 static void 02519 icvXMLWriteString( CvFileStorage* fs, const char* key, const char* str, int quote ) 02520 { 02521 char buf[CV_FS_MAX_LEN*6+16]; 02522 char* data = (char*)str; 02523 int i, len; 02524 02525 if( !str ) 02526 CV_Error( CV_StsNullPtr, "Null string pointer" ); 02527 02528 len = (int)strlen(str); 02529 if( len > CV_FS_MAX_LEN ) 02530 CV_Error( CV_StsBadArg, "The written string is too long" ); 02531 02532 if( quote || len == 0 || str[0] != '\"' || str[0] != str[len-1] ) 02533 { 02534 int need_quote = quote || len == 0; 02535 data = buf; 02536 *data++ = '\"'; 02537 for( i = 0; i < len; i++ ) 02538 { 02539 char c = str[i]; 02540 02541 if( (uchar)c >= 128 || c == ' ' ) 02542 { 02543 *data++ = c; 02544 need_quote = 1; 02545 } 02546 else if( !cv_isprint(c) || c == '<' || c == '>' || c == '&' || c == '\'' || c == '\"' ) 02547 { 02548 *data++ = '&'; 02549 if( c == '<' ) 02550 { 02551 memcpy(data, "lt", 2); 02552 data += 2; 02553 } 02554 else if( c == '>' ) 02555 { 02556 memcpy(data, "gt", 2); 02557 data += 2; 02558 } 02559 else if( c == '&' ) 02560 { 02561 memcpy(data, "amp", 3); 02562 data += 3; 02563 } 02564 else if( c == '\'' ) 02565 { 02566 memcpy(data, "apos", 4); 02567 data += 4; 02568 } 02569 else if( c == '\"' ) 02570 { 02571 memcpy( data, "quot", 4); 02572 data += 4; 02573 } 02574 else 02575 { 02576 sprintf( data, "#x%02x", (uchar)c ); 02577 data += 4; 02578 } 02579 *data++ = ';'; 02580 need_quote = 1; 02581 } 02582 else 02583 *data++ = c; 02584 } 02585 if( !need_quote && (cv_isdigit(str[0]) || 02586 str[0] == '+' || str[0] == '-' || str[0] == '.' )) 02587 need_quote = 1; 02588 02589 if( need_quote ) 02590 *data++ = '\"'; 02591 len = (int)(data - buf) - !need_quote; 02592 *data++ = '\0'; 02593 data = buf + !need_quote; 02594 } 02595 02596 icvXMLWriteScalar( fs, key, data, len ); 02597 } 02598 02599 02600 static void 02601 icvXMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment ) 02602 { 02603 int len; 02604 int multiline; 02605 const char* eol; 02606 char* ptr; 02607 02608 if( !comment ) 02609 CV_Error( CV_StsNullPtr, "Null comment" ); 02610 02611 if( strstr(comment, "--") != 0 ) 02612 CV_Error( CV_StsBadArg, "Double hyphen \'--\' is not allowed in the comments" ); 02613 02614 len = (int)strlen(comment); 02615 eol = strchr(comment, '\n'); 02616 multiline = eol != 0; 02617 ptr = fs->buffer; 02618 02619 if( multiline || !eol_comment || fs->buffer_end - ptr < len + 5 ) 02620 ptr = icvXMLFlush( fs ); 02621 else if( ptr > fs->buffer_start + fs->struct_indent ) 02622 *ptr++ = ' '; 02623 02624 if( !multiline ) 02625 { 02626 ptr = icvFSResizeWriteBuffer( fs, ptr, len + 9 ); 02627 sprintf( ptr, "<!-- %s -->", comment ); 02628 len = (int)strlen(ptr); 02629 } 02630 else 02631 { 02632 strcpy( ptr, "<!--" ); 02633 len = 4; 02634 } 02635 02636 fs->buffer = ptr + len; 02637 ptr = icvXMLFlush(fs); 02638 02639 if( multiline ) 02640 { 02641 while( comment ) 02642 { 02643 if( eol ) 02644 { 02645 ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 ); 02646 memcpy( ptr, comment, eol - comment + 1 ); 02647 ptr += eol - comment; 02648 comment = eol + 1; 02649 eol = strchr( comment, '\n' ); 02650 } 02651 else 02652 { 02653 len = (int)strlen(comment); 02654 ptr = icvFSResizeWriteBuffer( fs, ptr, len ); 02655 memcpy( ptr, comment, len ); 02656 ptr += len; 02657 comment = 0; 02658 } 02659 fs->buffer = ptr; 02660 ptr = icvXMLFlush( fs ); 02661 } 02662 sprintf( ptr, "-->" ); 02663 fs->buffer = ptr + 3; 02664 icvXMLFlush( fs ); 02665 } 02666 } 02667 02668 02669 /****************************************************************************************\ 02670 * Common High-Level Functions * 02671 \****************************************************************************************/ 02672 02673 CV_IMPL CvFileStorage* 02674 cvOpenFileStorage( const char* filename, CvMemStorage* dststorage, int flags, const char* encoding ) 02675 { 02676 CvFileStorage* fs = 0; 02677 int default_block_size = 1 << 18; 02678 bool append = (flags & 3) == CV_STORAGE_APPEND; 02679 bool mem = (flags & CV_STORAGE_MEMORY) != 0; 02680 bool write_mode = (flags & 3) != 0; 02681 bool isGZ = false; 02682 size_t fnamelen = 0; 02683 02684 if( !filename || filename[0] == '\0' ) 02685 { 02686 if( !write_mode ) 02687 CV_Error( CV_StsNullPtr, mem ? "NULL or empty filename" : "NULL or empty buffer" ); 02688 mem = true; 02689 } 02690 else 02691 fnamelen = strlen(filename); 02692 02693 if( mem && append ) 02694 CV_Error( CV_StsBadFlag, "CV_STORAGE_APPEND and CV_STORAGE_MEMORY are not currently compatible" ); 02695 02696 fs = (CvFileStorage*)cvAlloc( sizeof(*fs) ); 02697 memset( fs, 0, sizeof(*fs)); 02698 02699 fs->memstorage = cvCreateMemStorage( default_block_size ); 02700 fs->dststorage = dststorage ? dststorage : fs->memstorage; 02701 02702 fs->flags = CV_FILE_STORAGE; 02703 fs->write_mode = write_mode; 02704 02705 if( !mem ) 02706 { 02707 fs->filename = (char*)cvMemStorageAlloc( fs->memstorage, fnamelen+1 ); 02708 strcpy( fs->filename, filename ); 02709 02710 char* dot_pos = strrchr(fs->filename, '.'); 02711 char compression = '\0'; 02712 02713 if( dot_pos && dot_pos[1] == 'g' && dot_pos[2] == 'z' && 02714 (dot_pos[3] == '\0' || (cv_isdigit(dot_pos[3]) && dot_pos[4] == '\0')) ) 02715 { 02716 if( append ) 02717 { 02718 cvReleaseFileStorage( &fs ); 02719 CV_Error(CV_StsNotImplemented, "Appending data to compressed file is not implemented" ); 02720 } 02721 isGZ = true; 02722 compression = dot_pos[3]; 02723 if( compression ) 02724 dot_pos[3] = '\0', fnamelen--; 02725 } 02726 02727 if( !isGZ ) 02728 { 02729 /* TODO */ //User defined - Open File 02730 #ifdef USER_FILE 02731 fs->file = fopen_rzctm( fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" ); 02732 #else 02733 fs->file = fopen(fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" ); 02734 #endif 02735 02736 /* END TO-DO */ 02737 if( !fs->file ) 02738 goto _exit_; 02739 } 02740 else 02741 { 02742 #if USE_ZLIB 02743 char mode[] = { fs->write_mode ? 'w' : 'r', 'b', compression ? compression : '3', '\0' }; 02744 fs->gzfile = gzopen(fs->filename, mode); 02745 if( !fs->gzfile ) 02746 goto _exit_; 02747 #else 02748 cvReleaseFileStorage( &fs ); 02749 CV_Error(CV_StsNotImplemented, "There is no compressed file storage support in this configuration"); 02750 #endif 02751 } 02752 } 02753 02754 fs->roots = 0; 02755 fs->struct_indent = 0; 02756 fs->struct_flags = 0; 02757 fs->wrap_margin = 71; 02758 02759 if( fs->write_mode ) 02760 { 02761 int fmt = flags & CV_STORAGE_FORMAT_MASK; 02762 02763 if( mem ) 02764 fs->outbuf = new std::deque<char>; 02765 02766 if( fmt == CV_STORAGE_FORMAT_AUTO && filename ) 02767 { 02768 const char* dot_pos = filename + fnamelen - (isGZ ? 7 : 4); 02769 fs->fmt = (dot_pos >= filename && (memcmp( dot_pos, ".xml", 4) == 0 || 02770 memcmp(dot_pos, ".XML", 4) == 0 || memcmp(dot_pos, ".Xml", 4) == 0)) ? 02771 CV_STORAGE_FORMAT_XML : CV_STORAGE_FORMAT_YAML; 02772 } 02773 else 02774 fs->fmt = fmt != CV_STORAGE_FORMAT_AUTO ? fmt : CV_STORAGE_FORMAT_XML; 02775 02776 // we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (' and ") 02777 // and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB)) 02778 int buf_size = CV_FS_MAX_LEN*(fs->fmt == CV_STORAGE_FORMAT_XML ? 6 : 4) + 1024; 02779 02780 if( append ) 02781 /* TODO */ //User defined - Pass through the character of file 02782 #ifdef USER_FILE 02783 fseek_rzctm( fs->file, 0, SEEK_END ); 02784 #else 02785 fseek( fs->file, 0, SEEK_END ); 02786 #endif 02787 02788 /* END TO-DO */ 02789 02790 fs->write_stack = cvCreateSeq( 0, sizeof(CvSeq), fs->fmt == CV_STORAGE_FORMAT_XML ? 02791 sizeof(CvXMLStackRecord) : sizeof(int), fs->memstorage ); 02792 fs->is_first = 1; 02793 fs->struct_indent = 0; 02794 fs->struct_flags = CV_NODE_EMPTY; 02795 fs->buffer_start = fs->buffer = (char*)cvAlloc( buf_size + 1024 ); 02796 fs->buffer_end = fs->buffer_start + buf_size; 02797 if( fs->fmt == CV_STORAGE_FORMAT_XML ) 02798 { 02799 size_t file_size = fs->file ? (size_t)ftell( fs->file ) : (size_t)0; 02800 fs->strstorage = cvCreateChildMemStorage( fs->memstorage ); 02801 if( !append || file_size == 0 ) 02802 { 02803 if( encoding ) 02804 { 02805 if( strcmp( encoding, "UTF-16" ) == 0 || 02806 strcmp( encoding, "utf-16" ) == 0 || 02807 strcmp( encoding, "Utf-16" ) == 0 ) 02808 { 02809 cvReleaseFileStorage( &fs ); 02810 CV_Error( CV_StsBadArg, "UTF-16 XML encoding is not supported! Use 8-bit encoding\n"); 02811 } 02812 02813 CV_Assert( strlen(encoding) < 1000 ); 02814 char buf[1100]; 02815 sprintf(buf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding); 02816 icvPuts( fs, buf ); 02817 } 02818 else 02819 icvPuts( fs, "<?xml version=\"1.0\"?>\n" ); 02820 icvPuts( fs, "<opencv_storage>\n" ); 02821 } 02822 else 02823 { 02824 int xml_buf_size = 1 << 10; 02825 char substr[] = "</opencv_storage>"; 02826 int last_occurence = -1; 02827 xml_buf_size = MIN(xml_buf_size, int(file_size)); 02828 /* TODO */ //User defined - Pass through the character of file 02829 #ifdef USER_FILE 02830 fseek_rzctm( fs->file, -xml_buf_size, SEEK_END ); 02831 #else 02832 fseek( fs->file, -xml_buf_size, SEEK_END ); 02833 #endif 02834 02835 /* END TO-DO */ 02836 char* xml_buf = (char*)cvAlloc( xml_buf_size+2 ); 02837 // find the last occurence of </opencv_storage> 02838 for(;;) 02839 { 02840 int line_offset = (int)ftell( fs->file ); 02841 char* ptr0 = icvGets( fs, xml_buf, xml_buf_size ), *ptr; 02842 if( !ptr0 ) 02843 break; 02844 ptr = ptr0; 02845 for(;;) 02846 { 02847 ptr = strstr( ptr, substr ); 02848 if( !ptr ) 02849 break; 02850 last_occurence = line_offset + (int)(ptr - ptr0); 02851 ptr += strlen(substr); 02852 } 02853 } 02854 cvFree( &xml_buf ); 02855 if( last_occurence < 0 ) 02856 { 02857 cvReleaseFileStorage( &fs ); 02858 CV_Error( CV_StsError, "Could not find </opencv_storage> in the end of file.\n" ); 02859 } 02860 icvCloseFile( fs ); 02861 /* TODO */ //User defined - Open the File 02862 02863 #ifdef USER_FILE 02864 fs->file = fopen_rzctm( fs->filename, "r+t" ); 02865 #else 02866 fs->file = fopen( fs->filename, "r+t" ); 02867 #endif 02868 02869 #ifdef USER_FILE 02870 fseek_rzctm( fs->file, last_occurence, SEEK_SET ); 02871 #else 02872 fseek( fs->file, last_occurence, SEEK_SET ); 02873 #endif 02874 02875 02876 /* END TO-DO */ 02877 // replace the last "</opencv_storage>" with " <!-- resumed -->", which has the same length 02878 icvPuts( fs, " <!-- resumed -->" ); 02879 /* TODO */ //User defined - Pass through the character of file 02880 #ifdef USER_FILE 02881 fseek_rzctm( fs->file, 0, SEEK_END ); 02882 #else 02883 fseek( fs->file, 0, SEEK_END ); 02884 #endif 02885 /* END TO-DO */ 02886 icvPuts( fs, "\n" ); 02887 } 02888 fs->start_write_struct = icvXMLStartWriteStruct; 02889 fs->end_write_struct = icvXMLEndWriteStruct; 02890 fs->write_int = icvXMLWriteInt; 02891 fs->write_real = icvXMLWriteReal; 02892 fs->write_string = icvXMLWriteString; 02893 fs->write_comment = icvXMLWriteComment; 02894 fs->start_next_stream = icvXMLStartNextStream; 02895 } 02896 else 02897 { 02898 if( !append ) 02899 icvPuts( fs, "%YAML:1.0\n" ); 02900 else 02901 icvPuts( fs, "...\n---\n" ); 02902 fs->start_write_struct = icvYMLStartWriteStruct; 02903 fs->end_write_struct = icvYMLEndWriteStruct; 02904 fs->write_int = icvYMLWriteInt; 02905 fs->write_real = icvYMLWriteReal; 02906 fs->write_string = icvYMLWriteString; 02907 fs->write_comment = icvYMLWriteComment; 02908 fs->start_next_stream = icvYMLStartNextStream; 02909 } 02910 } 02911 else 02912 { 02913 if( mem ) 02914 { 02915 fs->strbuf = filename; 02916 fs->strbufsize = fnamelen; 02917 } 02918 02919 size_t buf_size = 1 << 20; 02920 const char* yaml_signature = "%YAML:"; 02921 char buf[16]; 02922 icvGets( fs, buf, sizeof(buf)-2 ); 02923 fs->fmt = strncmp( buf, yaml_signature, strlen(yaml_signature) ) == 0 ? 02924 CV_STORAGE_FORMAT_YAML : CV_STORAGE_FORMAT_XML; 02925 02926 if( !isGZ ) 02927 { 02928 if( !mem ) 02929 { 02930 /* TODO */ //User defined - Pass through the character of file 02931 #ifdef USER_FILE 02932 fseek_rzctm(fs->file, 0, SEEK_END); 02933 if (fs->fmt == CV_STORAGE_FORMAT_XML) 02934 { 02935 buf_size = FACE_CASCADE_SIZE; 02936 } 02937 else 02938 { 02939 buf_size = FS_TRAIN_SIZE; 02940 } 02941 #else 02942 fseek( fs->file, 0, SEEK_END ); 02943 buf_size = ftell( fs->file ); 02944 #endif 02945 /* END TO-DO */ 02946 } 02947 else 02948 buf_size = fs->strbufsize; 02949 buf_size = MIN( buf_size, (size_t)(1 << 20) ); 02950 buf_size = MAX( buf_size, (size_t)(CV_FS_MAX_LEN*2 + 1024) ); 02951 } 02952 icvRewind(fs); 02953 02954 fs->str_hash = cvCreateMap( 0, sizeof(CvStringHash), 02955 sizeof(CvStringHashNode), fs->memstorage, 256 ); 02956 02957 fs->roots = cvCreateSeq( 0, sizeof(CvSeq), 02958 sizeof(CvFileNode), fs->memstorage ); 02959 02960 fs->buffer = fs->buffer_start = (char*)cvAlloc( buf_size + 256 ); 02961 fs->buffer_end = fs->buffer_start + buf_size; 02962 fs->buffer[0] = '\n'; 02963 fs->buffer[1] = '\0'; 02964 02965 //mode = cvGetErrMode(); 02966 //cvSetErrMode( CV_ErrModeSilent ); 02967 //try 02968 // { 02969 if( fs->fmt == CV_STORAGE_FORMAT_XML ) 02970 icvXMLParse( fs ); 02971 else 02972 icvYMLParse( fs ); 02973 //} 02974 // catch (...) 02975 // { 02976 // cvReleaseFileStorage( &fs ); 02977 // throw; 02978 // } 02979 //cvSetErrMode( mode ); 02980 02981 // release resources that we do not need anymore 02982 cvFree( &fs->buffer_start ); 02983 fs->buffer = fs->buffer_end = 0; 02984 } 02985 fs->is_opened = true; 02986 02987 _exit_: 02988 if( fs ) 02989 { 02990 if( cvGetErrStatus() < 0 || (!fs->file && !fs->gzfile && !fs->outbuf && !fs->strbuf) ) 02991 { 02992 cvReleaseFileStorage( &fs ); 02993 } 02994 else if( !fs->write_mode ) 02995 { 02996 icvCloseFile(fs); 02997 // we close the file since it's not needed anymore. But icvCloseFile() resets is_opened, 02998 // which may be misleading. Since we restore the value of is_opened. 02999 fs->is_opened = true; 03000 } 03001 } 03002 03003 return fs; 03004 } 03005 03006 03007 CV_IMPL void 03008 cvStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags, 03009 const char* type_name, CvAttrList /*attributes*/ ) 03010 { 03011 CV_CHECK_OUTPUT_FILE_STORAGE(fs); 03012 fs->start_write_struct( fs, key, struct_flags, type_name ); 03013 } 03014 03015 03016 CV_IMPL void 03017 cvEndWriteStruct( CvFileStorage* fs ) 03018 { 03019 CV_CHECK_OUTPUT_FILE_STORAGE(fs); 03020 fs->end_write_struct( fs ); 03021 } 03022 03023 03024 CV_IMPL void 03025 cvWriteInt( CvFileStorage* fs, const char* key, int value ) 03026 { 03027 CV_CHECK_OUTPUT_FILE_STORAGE(fs); 03028 fs->write_int( fs, key, value ); 03029 } 03030 03031 03032 CV_IMPL void 03033 cvWriteReal( CvFileStorage* fs, const char* key, double value ) 03034 { 03035 CV_CHECK_OUTPUT_FILE_STORAGE(fs); 03036 fs->write_real( fs, key, value ); 03037 } 03038 03039 03040 CV_IMPL void 03041 cvWriteString( CvFileStorage* fs, const char* key, const char* value, int quote ) 03042 { 03043 CV_CHECK_OUTPUT_FILE_STORAGE(fs); 03044 fs->write_string( fs, key, value, quote ); 03045 } 03046 03047 03048 CV_IMPL void 03049 cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment ) 03050 { 03051 CV_CHECK_OUTPUT_FILE_STORAGE(fs); 03052 fs->write_comment( fs, comment, eol_comment ); 03053 } 03054 03055 03056 CV_IMPL void 03057 cvStartNextStream( CvFileStorage* fs ) 03058 { 03059 CV_CHECK_OUTPUT_FILE_STORAGE(fs); 03060 fs->start_next_stream( fs ); 03061 } 03062 03063 03064 static const char icvTypeSymbol[] = "ucwsifdr"; 03065 #define CV_FS_MAX_FMT_PAIRS 128 03066 03067 static char* 03068 icvEncodeFormat( int elem_type, char* dt ) 03069 { 03070 sprintf( dt, "%d%c", CV_MAT_CN(elem_type), icvTypeSymbol[CV_MAT_DEPTH(elem_type)] ); 03071 return dt + ( dt[2] == '\0' && dt[0] == '1' ); 03072 } 03073 03074 static int 03075 icvDecodeFormat( const char* dt, int* fmt_pairs, int max_len ) 03076 { 03077 int fmt_pair_count = 0; 03078 int i = 0, k = 0, len = dt ? (int)strlen(dt) : 0; 03079 03080 if( !dt || !len ) 03081 return 0; 03082 03083 assert( fmt_pairs != 0 && max_len > 0 ); 03084 fmt_pairs[0] = 0; 03085 max_len *= 2; 03086 03087 for( ; k < len; k++ ) 03088 { 03089 char c = dt[k]; 03090 03091 if( cv_isdigit(c) ) 03092 { 03093 int count = c - '0'; 03094 if( cv_isdigit(dt[k+1]) ) 03095 { 03096 char* endptr = 0; 03097 count = (int)strtol( dt+k, &endptr, 10 ); 03098 k = (int)(endptr - dt) - 1; 03099 } 03100 03101 if( count <= 0 ) 03102 CV_Error( CV_StsBadArg, "Invalid data type specification" ); 03103 03104 fmt_pairs[i] = count; 03105 } 03106 else 03107 { 03108 const char* pos = strchr( icvTypeSymbol, c ); 03109 if( !pos ) 03110 CV_Error( CV_StsBadArg, "Invalid data type specification" ); 03111 if( fmt_pairs[i] == 0 ) 03112 fmt_pairs[i] = 1; 03113 fmt_pairs[i+1] = (int)(pos - icvTypeSymbol); 03114 if( i > 0 && fmt_pairs[i+1] == fmt_pairs[i-1] ) 03115 fmt_pairs[i-2] += fmt_pairs[i]; 03116 else 03117 { 03118 i += 2; 03119 if( i >= max_len ) 03120 CV_Error( CV_StsBadArg, "Too long data type specification" ); 03121 } 03122 fmt_pairs[i] = 0; 03123 } 03124 } 03125 03126 fmt_pair_count = i/2; 03127 return fmt_pair_count; 03128 } 03129 03130 03131 static int 03132 icvCalcElemSize( const char* dt, int initial_size ) 03133 { 03134 int size = 0; 03135 int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count; 03136 int comp_size; 03137 03138 fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); 03139 fmt_pair_count *= 2; 03140 for( i = 0, size = initial_size; i < fmt_pair_count; i += 2 ) 03141 { 03142 comp_size = CV_ELEM_SIZE(fmt_pairs[i+1]); 03143 size = cvAlign( size, comp_size ); 03144 size += comp_size * fmt_pairs[i]; 03145 } 03146 if( initial_size == 0 ) 03147 { 03148 comp_size = CV_ELEM_SIZE(fmt_pairs[1]); 03149 size = cvAlign( size, comp_size ); 03150 } 03151 return size; 03152 } 03153 03154 03155 static int 03156 icvDecodeSimpleFormat( const char* dt ) 03157 { 03158 int elem_type = -1; 03159 int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count; 03160 03161 fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); 03162 if( fmt_pair_count != 1 || fmt_pairs[0] > 4 ) 03163 CV_Error( CV_StsError, "Too complex format for the matrix" ); 03164 03165 elem_type = CV_MAKETYPE( fmt_pairs[1], fmt_pairs[0] ); 03166 03167 return elem_type; 03168 } 03169 03170 03171 CV_IMPL void 03172 cvWriteRawData( CvFileStorage* fs, const void* _data, int len, const char* dt ) 03173 { 03174 const char* data0 = (const char*)_data; 03175 int offset = 0; 03176 int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k, fmt_pair_count; 03177 char buf[256] = ""; 03178 03179 CV_CHECK_OUTPUT_FILE_STORAGE( fs ); 03180 03181 if( len < 0 ) 03182 CV_Error( CV_StsOutOfRange, "Negative number of elements" ); 03183 03184 fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); 03185 03186 if( !len ) 03187 return; 03188 03189 if( !data0 ) 03190 CV_Error( CV_StsNullPtr, "Null data pointer" ); 03191 03192 if( fmt_pair_count == 1 ) 03193 { 03194 fmt_pairs[0] *= len; 03195 len = 1; 03196 } 03197 03198 for(;len--;) 03199 { 03200 for( k = 0; k < fmt_pair_count; k++ ) 03201 { 03202 int i, count = fmt_pairs[k*2]; 03203 int elem_type = fmt_pairs[k*2+1]; 03204 int elem_size = CV_ELEM_SIZE(elem_type); 03205 const char* data, *ptr; 03206 03207 offset = cvAlign( offset, elem_size ); 03208 data = data0 + offset; 03209 03210 for( i = 0; i < count; i++ ) 03211 { 03212 switch( elem_type ) 03213 { 03214 case CV_8U: 03215 ptr = icv_itoa( *(uchar*)data, buf, 10 ); 03216 data++; 03217 break; 03218 case CV_8S: 03219 ptr = icv_itoa( *(char*)data, buf, 10 ); 03220 data++; 03221 break; 03222 case CV_16U: 03223 ptr = icv_itoa( *(ushort*)data, buf, 10 ); 03224 data += sizeof(ushort); 03225 break; 03226 case CV_16S: 03227 ptr = icv_itoa( *(short*)data, buf, 10 ); 03228 data += sizeof(short); 03229 break; 03230 case CV_32S: 03231 ptr = icv_itoa( *(int*)data, buf, 10 ); 03232 data += sizeof(int); 03233 break; 03234 case CV_32F: 03235 ptr = icvFloatToString( buf, *(float*)data ); 03236 data += sizeof(float); 03237 break; 03238 case CV_64F: 03239 ptr = icvDoubleToString( buf, *(double*)data ); 03240 data += sizeof(double); 03241 break; 03242 case CV_USRTYPE1: /* reference */ 03243 ptr = icv_itoa( (int)*(size_t*)data, buf, 10 ); 03244 data += sizeof(size_t); 03245 break; 03246 default: 03247 assert(0); 03248 return; 03249 } 03250 03251 if( fs->fmt == CV_STORAGE_FORMAT_XML ) 03252 { 03253 int buf_len = (int)strlen(ptr); 03254 icvXMLWriteScalar( fs, 0, ptr, buf_len ); 03255 } 03256 else 03257 icvYMLWrite( fs, 0, ptr ); 03258 } 03259 03260 offset = (int)(data - data0); 03261 } 03262 } 03263 } 03264 03265 03266 CV_IMPL void 03267 cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, CvSeqReader* reader ) 03268 { 03269 int node_type; 03270 CV_CHECK_FILE_STORAGE( fs ); 03271 03272 if( !src || !reader ) 03273 CV_Error( CV_StsNullPtr, "Null pointer to source file node or reader" ); 03274 03275 node_type = CV_NODE_TYPE(src->tag); 03276 if( node_type == CV_NODE_INT || node_type == CV_NODE_REAL ) 03277 { 03278 // emulate reading from 1-element sequence 03279 reader->ptr = (schar*)src; 03280 reader->block_max = reader->ptr + sizeof(*src)*2; 03281 reader->block_min = reader->ptr; 03282 reader->seq = 0; 03283 } 03284 else if( node_type == CV_NODE_SEQ ) 03285 { 03286 cvStartReadSeq( src->data.seq, reader, 0 ); 03287 } 03288 else if( node_type == CV_NODE_NONE ) 03289 { 03290 memset( reader, 0, sizeof(*reader) ); 03291 } 03292 else 03293 CV_Error( CV_StsBadArg, "The file node should be a numerical scalar or a sequence" ); 03294 } 03295 03296 03297 CV_IMPL void 03298 cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader, 03299 int len, void* _data, const char* dt ) 03300 { 03301 char* data0 = (char*)_data; 03302 int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k = 0, fmt_pair_count; 03303 int i = 0, offset = 0, count = 0; 03304 03305 CV_CHECK_FILE_STORAGE( fs ); 03306 03307 if( !reader || !data0 ) 03308 CV_Error( CV_StsNullPtr, "Null pointer to reader or destination array" ); 03309 03310 if( !reader->seq && len != 1 ) 03311 CV_Error( CV_StsBadSize, "The readed sequence is a scalar, thus len must be 1" ); 03312 03313 fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); 03314 03315 for(;;) 03316 { 03317 for( k = 0; k < fmt_pair_count; k++ ) 03318 { 03319 int elem_type = fmt_pairs[k*2+1]; 03320 int elem_size = CV_ELEM_SIZE(elem_type); 03321 char* data; 03322 03323 count = fmt_pairs[k*2]; 03324 offset = cvAlign( offset, elem_size ); 03325 data = data0 + offset; 03326 03327 for( i = 0; i < count; i++ ) 03328 { 03329 CvFileNode* node = (CvFileNode*)reader->ptr; 03330 if( CV_NODE_IS_INT(node->tag) ) 03331 { 03332 int ival = node->data.i; 03333 03334 switch( elem_type ) 03335 { 03336 case CV_8U: 03337 *(uchar*)data = cv::saturate_cast<uchar>(ival); 03338 data++; 03339 break; 03340 case CV_8S: 03341 *(char*)data = cv::saturate_cast<schar>(ival); 03342 data++; 03343 break; 03344 case CV_16U: 03345 *(ushort*)data = cv::saturate_cast<ushort>(ival); 03346 data += sizeof(ushort); 03347 break; 03348 case CV_16S: 03349 *(short*)data = cv::saturate_cast<short>(ival); 03350 data += sizeof(short); 03351 break; 03352 case CV_32S: 03353 *(int*)data = ival; 03354 data += sizeof(int); 03355 break; 03356 case CV_32F: 03357 *(float*)data = (float)ival; 03358 data += sizeof(float); 03359 break; 03360 case CV_64F: 03361 *(double*)data = (double)ival; 03362 data += sizeof(double); 03363 break; 03364 case CV_USRTYPE1: /* reference */ 03365 *(size_t*)data = ival; 03366 data += sizeof(size_t); 03367 break; 03368 default: 03369 assert(0); 03370 return; 03371 } 03372 } 03373 else if( CV_NODE_IS_REAL(node->tag) ) 03374 { 03375 double fval = node->data.f; 03376 int ival; 03377 03378 switch( elem_type ) 03379 { 03380 case CV_8U: 03381 ival = cvRound(fval); 03382 *(uchar*)data = cv::saturate_cast<uchar>(ival); 03383 data++; 03384 break; 03385 case CV_8S: 03386 ival = cvRound(fval); 03387 *(char*)data = cv::saturate_cast<schar>(ival); 03388 data++; 03389 break; 03390 case CV_16U: 03391 ival = cvRound(fval); 03392 *(ushort*)data = cv::saturate_cast<ushort>(ival); 03393 data += sizeof(ushort); 03394 break; 03395 case CV_16S: 03396 ival = cvRound(fval); 03397 *(short*)data = cv::saturate_cast<short>(ival); 03398 data += sizeof(short); 03399 break; 03400 case CV_32S: 03401 ival = cvRound(fval); 03402 *(int*)data = ival; 03403 data += sizeof(int); 03404 break; 03405 case CV_32F: 03406 *(float*)data = (float)fval; 03407 data += sizeof(float); 03408 break; 03409 case CV_64F: 03410 *(double*)data = fval; 03411 data += sizeof(double); 03412 break; 03413 case CV_USRTYPE1: /* reference */ 03414 ival = cvRound(fval); 03415 *(size_t*)data = ival; 03416 data += sizeof(size_t); 03417 break; 03418 default: 03419 assert(0); 03420 return; 03421 } 03422 } 03423 else 03424 CV_Error( CV_StsError, 03425 "The sequence element is not a numerical scalar" ); 03426 03427 CV_NEXT_SEQ_ELEM( sizeof(CvFileNode), *reader ); 03428 if( !--len ) 03429 goto end_loop; 03430 } 03431 03432 offset = (int)(data - data0); 03433 } 03434 } 03435 03436 end_loop: 03437 if( i != count - 1 || k != fmt_pair_count - 1 ) 03438 CV_Error( CV_StsBadSize, 03439 "The sequence slice does not fit an integer number of records" ); 03440 03441 if( !reader->seq ) 03442 reader->ptr -= sizeof(CvFileNode); 03443 } 03444 03445 03446 CV_IMPL void 03447 cvReadRawData( const CvFileStorage* fs, const CvFileNode* src, 03448 void* data, const char* dt ) 03449 { 03450 CvSeqReader reader; 03451 03452 if( !src || !data ) 03453 CV_Error( CV_StsNullPtr, "Null pointers to source file node or destination array" ); 03454 03455 cvStartReadRawData( fs, src, &reader ); 03456 cvReadRawDataSlice( fs, &reader, CV_NODE_IS_SEQ(src->tag) ? 03457 src->data.seq->total : 1, data, dt ); 03458 } 03459 03460 03461 static void 03462 icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node ); 03463 03464 static void 03465 icvWriteCollection( CvFileStorage* fs, const CvFileNode* node ) 03466 { 03467 int i, total = node->data.seq->total; 03468 int elem_size = node->data.seq->elem_size; 03469 int is_map = CV_NODE_IS_MAP(node->tag); 03470 CvSeqReader reader; 03471 03472 cvStartReadSeq( node->data.seq, &reader, 0 ); 03473 03474 for( i = 0; i < total; i++ ) 03475 { 03476 CvFileMapNode* elem = (CvFileMapNode*)reader.ptr; 03477 if( !is_map || CV_IS_SET_ELEM(elem) ) 03478 { 03479 const char* name = is_map ? elem->key->str.ptr : 0; 03480 icvWriteFileNode( fs, name, &elem->value ); 03481 } 03482 CV_NEXT_SEQ_ELEM( elem_size, reader ); 03483 } 03484 } 03485 03486 static void 03487 icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node ) 03488 { 03489 switch( CV_NODE_TYPE(node->tag) ) 03490 { 03491 case CV_NODE_INT: 03492 fs->write_int( fs, name, node->data.i ); 03493 break; 03494 case CV_NODE_REAL: 03495 fs->write_real( fs, name, node->data.f ); 03496 break; 03497 case CV_NODE_STR: 03498 fs->write_string( fs, name, node->data.str.ptr, 0 ); 03499 break; 03500 case CV_NODE_SEQ: 03501 case CV_NODE_MAP: 03502 fs->start_write_struct( fs, name, CV_NODE_TYPE(node->tag) + 03503 (CV_NODE_SEQ_IS_SIMPLE(node->data.seq) ? CV_NODE_FLOW : 0), 03504 node->info ? node->info->type_name : 0 ); 03505 icvWriteCollection( fs, node ); 03506 fs->end_write_struct( fs ); 03507 break; 03508 case CV_NODE_NONE: 03509 fs->start_write_struct( fs, name, CV_NODE_SEQ, 0 ); 03510 fs->end_write_struct( fs ); 03511 break; 03512 default: 03513 CV_Error( CV_StsBadFlag, "Unknown type of file node" ); 03514 } 03515 } 03516 03517 03518 CV_IMPL void 03519 cvWriteFileNode( CvFileStorage* fs, const char* new_node_name, 03520 const CvFileNode* node, int embed ) 03521 { 03522 CvFileStorage* dst = 0; 03523 CV_CHECK_OUTPUT_FILE_STORAGE(fs); 03524 03525 if( !node ) 03526 return; 03527 03528 if( CV_NODE_IS_COLLECTION(node->tag) && embed ) 03529 { 03530 icvWriteCollection( fs, node ); 03531 } 03532 else 03533 { 03534 icvWriteFileNode( fs, new_node_name, node ); 03535 } 03536 /* 03537 int i, stream_count; 03538 stream_count = fs->roots->total; 03539 for( i = 0; i < stream_count; i++ ) 03540 { 03541 CvFileNode* node = (CvFileNode*)cvGetSeqElem( fs->roots, i, 0 ); 03542 icvDumpCollection( dst, node ); 03543 if( i < stream_count - 1 ) 03544 dst->start_next_stream( dst ); 03545 }*/ 03546 cvReleaseFileStorage( &dst ); 03547 } 03548 03549 03550 CV_IMPL const char* 03551 cvGetFileNodeName( const CvFileNode* file_node ) 03552 { 03553 return file_node && CV_NODE_HAS_NAME(file_node->tag) ? 03554 ((CvFileMapNode*)file_node)->key->str.ptr : 0; 03555 } 03556 03557 /****************************************************************************************\ 03558 * Reading/Writing etc. for standard types * 03559 \****************************************************************************************/ 03560 03561 /*#define CV_TYPE_NAME_MAT "opencv-matrix" 03562 #define CV_TYPE_NAME_MATND "opencv-nd-matrix" 03563 #define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix" 03564 #define CV_TYPE_NAME_IMAGE "opencv-image" 03565 #define CV_TYPE_NAME_SEQ "opencv-sequence" 03566 #define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree" 03567 #define CV_TYPE_NAME_GRAPH "opencv-graph"*/ 03568 03569 /******************************* CvMat ******************************/ 03570 03571 static int 03572 icvIsMat( const void* ptr ) 03573 { 03574 return CV_IS_MAT_HDR_Z(ptr); 03575 } 03576 03577 static void 03578 icvWriteMat( CvFileStorage* fs, const char* name, 03579 const void* struct_ptr, CvAttrList /*attr*/ ) 03580 { 03581 const CvMat* mat = (const CvMat*)struct_ptr; 03582 char dt[16]; 03583 CvSize size; 03584 int y; 03585 03586 assert( CV_IS_MAT_HDR_Z(mat) ); 03587 03588 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MAT ); 03589 cvWriteInt( fs, "rows", mat->rows ); 03590 cvWriteInt( fs, "cols", mat->cols ); 03591 cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 ); 03592 cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); 03593 03594 size = cvGetSize(mat); 03595 if( size.height > 0 && size.width > 0 && mat->data.ptr ) 03596 { 03597 if( CV_IS_MAT_CONT(mat->type) ) 03598 { 03599 size.width *= size.height; 03600 size.height = 1; 03601 } 03602 03603 for( y = 0; y < size.height; y++ ) 03604 cvWriteRawData( fs, mat->data.ptr + (size_t)y*mat->step, size.width, dt ); 03605 } 03606 cvEndWriteStruct( fs ); 03607 cvEndWriteStruct( fs ); 03608 } 03609 03610 03611 static int 03612 icvFileNodeSeqLen( CvFileNode* node ) 03613 { 03614 return CV_NODE_IS_COLLECTION(node->tag) ? node->data.seq->total : 03615 CV_NODE_TYPE(node->tag) != CV_NODE_NONE; 03616 } 03617 03618 03619 static void* 03620 icvReadMat( CvFileStorage* fs, CvFileNode* node ) 03621 { 03622 void* ptr = 0; 03623 CvMat* mat; 03624 const char* dt; 03625 CvFileNode* data; 03626 int rows, cols, elem_type; 03627 03628 rows = cvReadIntByName( fs, node, "rows", -1 ); 03629 cols = cvReadIntByName( fs, node, "cols", -1 ); 03630 dt = cvReadStringByName( fs, node, "dt", 0 ); 03631 03632 if( rows < 0 || cols < 0 || !dt ) 03633 CV_Error( CV_StsError, "Some of essential matrix attributes are absent" ); 03634 03635 elem_type = icvDecodeSimpleFormat( dt ); 03636 03637 data = cvGetFileNodeByName( fs, node, "data" ); 03638 if( !data ) 03639 CV_Error( CV_StsError, "The matrix data is not found in file storage" ); 03640 03641 int nelems = icvFileNodeSeqLen( data ); 03642 if( nelems > 0 && nelems != rows*cols*CV_MAT_CN(elem_type) ) 03643 CV_Error( CV_StsUnmatchedSizes, 03644 "The matrix size does not match to the number of stored elements" ); 03645 03646 if( nelems > 0 ) 03647 { 03648 mat = cvCreateMat( rows, cols, elem_type ); 03649 cvReadRawData( fs, data, mat->data.ptr, dt ); 03650 } 03651 else if( rows == 0 && cols == 0 ) 03652 mat = cvCreateMatHeader( 0, 1, elem_type ); 03653 else 03654 mat = cvCreateMatHeader( rows, cols, elem_type ); 03655 03656 ptr = mat; 03657 return ptr; 03658 } 03659 03660 03661 /******************************* CvMatND ******************************/ 03662 03663 static int 03664 icvIsMatND( const void* ptr ) 03665 { 03666 return CV_IS_MATND_HDR(ptr); 03667 } 03668 03669 03670 static void 03671 icvWriteMatND( CvFileStorage* fs, const char* name, 03672 const void* struct_ptr, CvAttrList /*attr*/ ) 03673 { 03674 CvMatND * mat = (CvMatND *)struct_ptr; 03675 CvMatND stub; 03676 CvNArrayIterator iterator; 03677 int dims, sizes[CV_MAX_DIM]; 03678 char dt[16]; 03679 03680 assert( CV_IS_MATND_HDR(mat) ); 03681 03682 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MATND ); 03683 dims = cvGetDims( mat, sizes ); 03684 cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW ); 03685 cvWriteRawData( fs, sizes, dims, "i" ); 03686 cvEndWriteStruct( fs ); 03687 cvWriteString( fs, "dt", icvEncodeFormat( cvGetElemType(mat), dt ), 0 ); 03688 cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); 03689 03690 if( mat->dim[0].size > 0 && mat->data.ptr ) 03691 { 03692 cvInitNArrayIterator( 1, (CvArr**)&mat, 0, &stub, &iterator ); 03693 03694 do 03695 cvWriteRawData( fs, iterator.ptr[0], iterator.size.width, dt ); 03696 while( cvNextNArraySlice( &iterator )); 03697 } 03698 cvEndWriteStruct( fs ); 03699 cvEndWriteStruct( fs ); 03700 } 03701 03702 03703 static void* 03704 icvReadMatND( CvFileStorage* fs, CvFileNode* node ) 03705 { 03706 void* ptr = 0; 03707 CvMatND * mat; 03708 const char* dt; 03709 CvFileNode* data; 03710 CvFileNode* sizes_node; 03711 int sizes[CV_MAX_DIM], dims, elem_type; 03712 int i, total_size; 03713 03714 sizes_node = cvGetFileNodeByName( fs, node, "sizes" ); 03715 dt = cvReadStringByName( fs, node, "dt", 0 ); 03716 03717 if( !sizes_node || !dt ) 03718 CV_Error( CV_StsError, "Some of essential matrix attributes are absent" ); 03719 03720 dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total : 03721 CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1; 03722 03723 if( dims <= 0 || dims > CV_MAX_DIM ) 03724 CV_Error( CV_StsParseError, "Could not determine the matrix dimensionality" ); 03725 03726 cvReadRawData( fs, sizes_node, sizes, "i" ); 03727 elem_type = icvDecodeSimpleFormat( dt ); 03728 03729 data = cvGetFileNodeByName( fs, node, "data" ); 03730 if( !data ) 03731 CV_Error( CV_StsError, "The matrix data is not found in file storage" ); 03732 03733 03734 03735 for( total_size = CV_MAT_CN(elem_type), i = 0; i < dims; i++ ) 03736 total_size *= sizes[i]; 03737 03738 int nelems = icvFileNodeSeqLen( data ); 03739 03740 if( nelems > 0 && nelems != total_size ) 03741 CV_Error( CV_StsUnmatchedSizes, 03742 "The matrix size does not match to the number of stored elements" ); 03743 03744 if( nelems > 0 ) 03745 { 03746 mat = cvCreateMatND( dims, sizes, elem_type ); 03747 cvReadRawData( fs, data, mat->data.ptr, dt ); 03748 } 03749 else 03750 mat = cvCreateMatNDHeader( dims, sizes, elem_type ); 03751 03752 ptr = mat; 03753 return ptr; 03754 } 03755 03756 03757 /******************************* CvSparseMat ******************************/ 03758 03759 static int 03760 icvIsSparseMat( const void* ptr ) 03761 { 03762 return CV_IS_SPARSE_MAT(ptr); 03763 } 03764 03765 03766 static int 03767 icvSortIdxCmpFunc( const void* _a, const void* _b, void* userdata ) 03768 { 03769 int i, dims = *(int*)userdata; 03770 const int* a = *(const int**)_a; 03771 const int* b = *(const int**)_b; 03772 03773 for( i = 0; i < dims; i++ ) 03774 { 03775 int delta = a[i] - b[i]; 03776 if( delta ) 03777 return delta; 03778 } 03779 03780 return 0; 03781 } 03782 03783 03784 static void 03785 icvWriteSparseMat( CvFileStorage* fs, const char* name, 03786 const void* struct_ptr, CvAttrList /*attr*/ ) 03787 { 03788 CvMemStorage* memstorage = 0; 03789 const CvSparseMat* mat = (const CvSparseMat*)struct_ptr; 03790 CvSparseMatIterator iterator; 03791 CvSparseNode* node; 03792 CvSeq* elements; 03793 CvSeqReader reader; 03794 int i, dims; 03795 int *prev_idx = 0; 03796 char dt[16]; 03797 03798 assert( CV_IS_SPARSE_MAT(mat) ); 03799 03800 memstorage = cvCreateMemStorage(); 03801 03802 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SPARSE_MAT ); 03803 dims = cvGetDims( mat, 0 ); 03804 03805 cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW ); 03806 cvWriteRawData( fs, mat->size, dims, "i" ); 03807 cvEndWriteStruct( fs ); 03808 cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 ); 03809 cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); 03810 03811 elements = cvCreateSeq( CV_SEQ_ELTYPE_PTR, sizeof(CvSeq), sizeof(int*), memstorage ); 03812 03813 node = cvInitSparseMatIterator( mat, &iterator ); 03814 while( node ) 03815 { 03816 int* idx = CV_NODE_IDX( mat, node ); 03817 cvSeqPush( elements, &idx ); 03818 node = cvGetNextSparseNode( &iterator ); 03819 } 03820 03821 cvSeqSort( elements, icvSortIdxCmpFunc, &dims ); 03822 cvStartReadSeq( elements, &reader, 0 ); 03823 03824 for( i = 0; i < elements->total; i++ ) 03825 { 03826 int* idx; 03827 void* val; 03828 int k = 0; 03829 03830 CV_READ_SEQ_ELEM( idx, reader ); 03831 if( i > 0 ) 03832 { 03833 for( ; idx[k] == prev_idx[k]; k++ ) 03834 assert( k < dims ); 03835 if( k < dims - 1 ) 03836 fs->write_int( fs, 0, k - dims + 1 ); 03837 } 03838 for( ; k < dims; k++ ) 03839 fs->write_int( fs, 0, idx[k] ); 03840 prev_idx = idx; 03841 03842 node = (CvSparseNode*)((uchar*)idx - mat->idxoffset ); 03843 val = CV_NODE_VAL( mat, node ); 03844 03845 cvWriteRawData( fs, val, 1, dt ); 03846 } 03847 03848 cvEndWriteStruct( fs ); 03849 cvEndWriteStruct( fs ); 03850 cvReleaseMemStorage( &memstorage ); 03851 } 03852 03853 03854 static void* 03855 icvReadSparseMat( CvFileStorage* fs, CvFileNode* node ) 03856 { 03857 void* ptr = 0; 03858 CvSparseMat* mat; 03859 const char* dt; 03860 CvFileNode* data; 03861 CvFileNode* sizes_node; 03862 CvSeqReader reader; 03863 CvSeq* elements; 03864 int sizes[CV_MAX_DIM_HEAP], dims, elem_type, cn; 03865 int i; 03866 03867 sizes_node = cvGetFileNodeByName( fs, node, "sizes" ); 03868 dt = cvReadStringByName( fs, node, "dt", 0 ); 03869 03870 if( !sizes_node || !dt ) 03871 CV_Error( CV_StsError, "Some of essential matrix attributes are absent" ); 03872 03873 dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total : 03874 CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1; 03875 03876 if( dims <= 0 || dims > CV_MAX_DIM_HEAP ) 03877 CV_Error( CV_StsParseError, "Could not determine sparse matrix dimensionality" ); 03878 03879 cvReadRawData( fs, sizes_node, sizes, "i" ); 03880 elem_type = icvDecodeSimpleFormat( dt ); 03881 03882 data = cvGetFileNodeByName( fs, node, "data" ); 03883 if( !data || !CV_NODE_IS_SEQ(data->tag) ) 03884 CV_Error( CV_StsError, "The matrix data is not found in file storage" ); 03885 03886 mat = cvCreateSparseMat( dims, sizes, elem_type ); 03887 03888 cn = CV_MAT_CN(elem_type); 03889 int idx[CV_MAX_DIM_HEAP]; 03890 elements = data->data.seq; 03891 cvStartReadRawData( fs, data, &reader ); 03892 03893 for( i = 0; i < elements->total; ) 03894 { 03895 CvFileNode* elem = (CvFileNode*)reader.ptr; 03896 uchar* val; 03897 int k; 03898 if( !CV_NODE_IS_INT(elem->tag )) 03899 CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" ); 03900 k = elem->data.i; 03901 if( i > 0 && k >= 0 ) 03902 idx[dims-1] = k; 03903 else 03904 { 03905 if( i > 0 ) 03906 k = dims + k - 1; 03907 else 03908 idx[0] = k, k = 1; 03909 for( ; k < dims; k++ ) 03910 { 03911 CV_NEXT_SEQ_ELEM( elements->elem_size, reader ); 03912 i++; 03913 elem = (CvFileNode*)reader.ptr; 03914 if( !CV_NODE_IS_INT(elem->tag ) || elem->data.i < 0 ) 03915 CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" ); 03916 idx[k] = elem->data.i; 03917 } 03918 } 03919 CV_NEXT_SEQ_ELEM( elements->elem_size, reader ); 03920 i++; 03921 val = cvPtrND( mat, idx, 0, 1, 0 ); 03922 cvReadRawDataSlice( fs, &reader, cn, val, dt ); 03923 i += cn; 03924 } 03925 03926 ptr = mat; 03927 return ptr; 03928 } 03929 03930 03931 /******************************* IplImage ******************************/ 03932 03933 static int 03934 icvIsImage( const void* ptr ) 03935 { 03936 return CV_IS_IMAGE_HDR(ptr); 03937 } 03938 03939 static void 03940 icvWriteImage( CvFileStorage* fs, const char* name, 03941 const void* struct_ptr, CvAttrList /*attr*/ ) 03942 { 03943 const IplImage* image = (const IplImage*)struct_ptr; 03944 char dt_buf[16], *dt; 03945 CvSize size; 03946 int y, depth; 03947 03948 assert( CV_IS_IMAGE(image) ); 03949 03950 if( image->dataOrder == IPL_DATA_ORDER_PLANE ) 03951 CV_Error( CV_StsUnsupportedFormat, 03952 "Images with planar data layout are not supported" ); 03953 03954 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_IMAGE ); 03955 cvWriteInt( fs, "width", image->width ); 03956 cvWriteInt( fs, "height", image->height ); 03957 cvWriteString( fs, "origin", image->origin == IPL_ORIGIN_TL 03958 ? "top-left" : "bottom-left", 0 ); 03959 cvWriteString( fs, "layout", image->dataOrder == IPL_DATA_ORDER_PLANE 03960 ? "planar" : "interleaved", 0 ); 03961 if( image->roi ) 03962 { 03963 cvStartWriteStruct( fs, "roi", CV_NODE_MAP + CV_NODE_FLOW ); 03964 cvWriteInt( fs, "x", image->roi->xOffset ); 03965 cvWriteInt( fs, "y", image->roi->yOffset ); 03966 cvWriteInt( fs, "width", image->roi->width ); 03967 cvWriteInt( fs, "height", image->roi->height ); 03968 cvWriteInt( fs, "coi", image->roi->coi ); 03969 cvEndWriteStruct( fs ); 03970 } 03971 03972 depth = IPL2CV_DEPTH(image->depth); 03973 sprintf( dt_buf, "%d%c", image->nChannels, icvTypeSymbol[depth] ); 03974 dt = dt_buf + (dt_buf[2] == '\0' && dt_buf[0] == '1'); 03975 cvWriteString( fs, "dt", dt, 0 ); 03976 03977 size = cvSize(image->width, image->height); 03978 if( size.width*image->nChannels*CV_ELEM_SIZE(depth) == image->widthStep ) 03979 { 03980 size.width *= size.height; 03981 size.height = 1; 03982 } 03983 03984 cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); 03985 for( y = 0; y < size.height; y++ ) 03986 cvWriteRawData( fs, image->imageData + y*image->widthStep, size.width, dt ); 03987 cvEndWriteStruct( fs ); 03988 cvEndWriteStruct( fs ); 03989 } 03990 03991 03992 static void* 03993 icvReadImage( CvFileStorage* fs, CvFileNode* node ) 03994 { 03995 void* ptr = 0; 03996 IplImage* image; 03997 const char* dt; 03998 CvFileNode* data; 03999 CvFileNode* roi_node; 04000 CvSeqReader reader; 04001 CvRect roi; 04002 int y, width, height, elem_type, coi, depth; 04003 const char* origin, *data_order; 04004 04005 width = cvReadIntByName( fs, node, "width", 0 ); 04006 height = cvReadIntByName( fs, node, "height", 0 ); 04007 dt = cvReadStringByName( fs, node, "dt", 0 ); 04008 origin = cvReadStringByName( fs, node, "origin", 0 ); 04009 04010 if( width == 0 || height == 0 || dt == 0 || origin == 0 ) 04011 CV_Error( CV_StsError, "Some of essential image attributes are absent" ); 04012 04013 elem_type = icvDecodeSimpleFormat( dt ); 04014 data_order = cvReadStringByName( fs, node, "layout", "interleaved" ); 04015 if( strcmp( data_order, "interleaved" ) != 0 ) 04016 CV_Error( CV_StsError, "Only interleaved images can be read" ); 04017 04018 data = cvGetFileNodeByName( fs, node, "data" ); 04019 if( !data ) 04020 CV_Error( CV_StsError, "The image data is not found in file storage" ); 04021 04022 if( icvFileNodeSeqLen( data ) != width*height*CV_MAT_CN(elem_type) ) 04023 CV_Error( CV_StsUnmatchedSizes, 04024 "The matrix size does not match to the number of stored elements" ); 04025 04026 depth = cvIplDepth(elem_type); 04027 image = cvCreateImage( cvSize(width,height), depth, CV_MAT_CN(elem_type) ); 04028 04029 roi_node = cvGetFileNodeByName( fs, node, "roi" ); 04030 if( roi_node ) 04031 { 04032 roi.x = cvReadIntByName( fs, roi_node, "x", 0 ); 04033 roi.y = cvReadIntByName( fs, roi_node, "y", 0 ); 04034 roi.width = cvReadIntByName( fs, roi_node, "width", 0 ); 04035 roi.height = cvReadIntByName( fs, roi_node, "height", 0 ); 04036 coi = cvReadIntByName( fs, roi_node, "coi", 0 ); 04037 04038 cvSetImageROI( image, roi ); 04039 cvSetImageCOI( image, coi ); 04040 } 04041 04042 if( width*CV_ELEM_SIZE(elem_type) == image->widthStep ) 04043 { 04044 width *= height; 04045 height = 1; 04046 } 04047 04048 width *= CV_MAT_CN(elem_type); 04049 cvStartReadRawData( fs, data, &reader ); 04050 for( y = 0; y < height; y++ ) 04051 { 04052 cvReadRawDataSlice( fs, &reader, width, 04053 image->imageData + y*image->widthStep, dt ); 04054 } 04055 04056 ptr = image; 04057 return ptr; 04058 } 04059 04060 04061 /******************************* CvSeq ******************************/ 04062 04063 static int 04064 icvIsSeq( const void* ptr ) 04065 { 04066 return CV_IS_SEQ(ptr); 04067 } 04068 04069 04070 static void 04071 icvReleaseSeq( void** ptr ) 04072 { 04073 if( !ptr ) 04074 CV_Error( CV_StsNullPtr, "NULL double pointer" ); 04075 *ptr = 0; // it's impossible now to release seq, so just clear the pointer 04076 } 04077 04078 04079 static void* 04080 icvCloneSeq( const void* ptr ) 04081 { 04082 return cvSeqSlice( (CvSeq*)ptr, CV_WHOLE_SEQ, 04083 0 /* use the same storage as for the original sequence */, 1 ); 04084 } 04085 04086 04087 static void 04088 icvWriteHeaderData( CvFileStorage* fs, const CvSeq* seq, 04089 CvAttrList* attr, int initial_header_size ) 04090 { 04091 char header_dt_buf[128]; 04092 const char* header_dt = cvAttrValue( attr, "header_dt" ); 04093 04094 if( header_dt ) 04095 { 04096 int dt_header_size; 04097 dt_header_size = icvCalcElemSize( header_dt, initial_header_size ); 04098 if( dt_header_size > seq->header_size ) 04099 CV_Error( CV_StsUnmatchedSizes, 04100 "The size of header calculated from \"header_dt\" is greater than header_size" ); 04101 } 04102 else if( seq->header_size > initial_header_size ) 04103 { 04104 if( CV_IS_SEQ(seq) && CV_IS_SEQ_POINT_SET(seq) && 04105 seq->header_size == sizeof(CvPoint2DSeq) && 04106 seq->elem_size == sizeof(int)*2 ) 04107 { 04108 CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq; 04109 04110 cvStartWriteStruct( fs, "rect", CV_NODE_MAP + CV_NODE_FLOW ); 04111 cvWriteInt( fs, "x", point_seq->rect.x ); 04112 cvWriteInt( fs, "y", point_seq->rect.y ); 04113 cvWriteInt( fs, "width", point_seq->rect.width ); 04114 cvWriteInt( fs, "height", point_seq->rect.height ); 04115 cvEndWriteStruct( fs ); 04116 cvWriteInt( fs, "color", point_seq->color ); 04117 } 04118 else if( CV_IS_SEQ(seq) && CV_IS_SEQ_CHAIN(seq) && 04119 CV_MAT_TYPE(seq->flags) == CV_8UC1 ) 04120 { 04121 CvChain* chain = (CvChain*)seq; 04122 04123 cvStartWriteStruct( fs, "origin", CV_NODE_MAP + CV_NODE_FLOW ); 04124 cvWriteInt( fs, "x", chain->origin.x ); 04125 cvWriteInt( fs, "y", chain->origin.y ); 04126 cvEndWriteStruct( fs ); 04127 } 04128 else 04129 { 04130 unsigned extra_size = seq->header_size - initial_header_size; 04131 // a heuristic to provide nice defaults for sequences of int's & float's 04132 if( extra_size % sizeof(int) == 0 ) 04133 sprintf( header_dt_buf, "%ui", (unsigned)(extra_size/sizeof(int)) ); 04134 else 04135 sprintf( header_dt_buf, "%uu", extra_size ); 04136 header_dt = header_dt_buf; 04137 } 04138 } 04139 04140 if( header_dt ) 04141 { 04142 cvWriteString( fs, "header_dt", header_dt, 0 ); 04143 cvStartWriteStruct( fs, "header_user_data", CV_NODE_SEQ + CV_NODE_FLOW ); 04144 cvWriteRawData( fs, (uchar*)seq + sizeof(CvSeq), 1, header_dt ); 04145 cvEndWriteStruct( fs ); 04146 } 04147 } 04148 04149 04150 static char* 04151 icvGetFormat( const CvSeq* seq, const char* dt_key, CvAttrList* attr, 04152 int initial_elem_size, char* dt_buf ) 04153 { 04154 char* dt = 0; 04155 dt = (char*)cvAttrValue( attr, dt_key ); 04156 04157 if( dt ) 04158 { 04159 int dt_elem_size; 04160 dt_elem_size = icvCalcElemSize( dt, initial_elem_size ); 04161 if( dt_elem_size != seq->elem_size ) 04162 CV_Error( CV_StsUnmatchedSizes, 04163 "The size of element calculated from \"dt\" and " 04164 "the elem_size do not match" ); 04165 } 04166 else if( CV_MAT_TYPE(seq->flags) != 0 || seq->elem_size == 1 ) 04167 { 04168 if( CV_ELEM_SIZE(seq->flags) != seq->elem_size ) 04169 CV_Error( CV_StsUnmatchedSizes, 04170 "Size of sequence element (elem_size) is inconsistent with seq->flags" ); 04171 dt = icvEncodeFormat( CV_MAT_TYPE(seq->flags), dt_buf ); 04172 } 04173 else if( seq->elem_size > initial_elem_size ) 04174 { 04175 unsigned extra_elem_size = seq->elem_size - initial_elem_size; 04176 // a heuristic to provide nice defaults for sequences of int's & float's 04177 if( extra_elem_size % sizeof(int) == 0 ) 04178 sprintf( dt_buf, "%ui", (unsigned)(extra_elem_size/sizeof(int)) ); 04179 else 04180 sprintf( dt_buf, "%uu", extra_elem_size ); 04181 dt = dt_buf; 04182 } 04183 04184 return dt; 04185 } 04186 04187 04188 static void 04189 icvWriteSeq( CvFileStorage* fs, const char* name, 04190 const void* struct_ptr, 04191 CvAttrList attr, int level ) 04192 { 04193 const CvSeq* seq = (CvSeq*)struct_ptr; 04194 CvSeqBlock* block; 04195 char buf[128]; 04196 char dt_buf[128], *dt; 04197 04198 assert( CV_IS_SEQ( seq )); 04199 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ ); 04200 04201 if( level >= 0 ) 04202 cvWriteInt( fs, "level", level ); 04203 04204 dt = icvGetFormat( seq, "dt", &attr, 0, dt_buf ); 04205 04206 strcpy(buf, ""); 04207 if( CV_IS_SEQ_CLOSED(seq) ) 04208 strcat(buf, " closed"); 04209 if( CV_IS_SEQ_HOLE(seq) ) 04210 strcat(buf, " hole"); 04211 if( CV_IS_SEQ_CURVE(seq) ) 04212 strcat(buf, " curve"); 04213 if( CV_SEQ_ELTYPE(seq) == 0 && seq->elem_size != 1 ) 04214 strcat(buf, " untyped"); 04215 04216 cvWriteString( fs, "flags", buf + (buf[0] ? 1 : 0), 1 ); 04217 04218 cvWriteInt( fs, "count", seq->total ); 04219 04220 cvWriteString( fs, "dt", dt, 0 ); 04221 04222 icvWriteHeaderData( fs, seq, &attr, sizeof(CvSeq) ); 04223 cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW ); 04224 04225 for( block = seq->first; block; block = block->next ) 04226 { 04227 cvWriteRawData( fs, block->data, block->count, dt ); 04228 if( block == seq->first->prev ) 04229 break; 04230 } 04231 cvEndWriteStruct( fs ); 04232 cvEndWriteStruct( fs ); 04233 } 04234 04235 04236 static void 04237 icvWriteSeqTree( CvFileStorage* fs, const char* name, 04238 const void* struct_ptr, CvAttrList attr ) 04239 { 04240 const CvSeq* seq = (CvSeq*)struct_ptr; 04241 const char* recursive_value = cvAttrValue( &attr, "recursive" ); 04242 int is_recursive = recursive_value && 04243 strcmp(recursive_value,"0") != 0 && 04244 strcmp(recursive_value,"false") != 0 && 04245 strcmp(recursive_value,"False") != 0 && 04246 strcmp(recursive_value,"FALSE") != 0; 04247 04248 assert( CV_IS_SEQ( seq )); 04249 04250 if( !is_recursive ) 04251 { 04252 icvWriteSeq( fs, name, seq, attr, -1 ); 04253 } 04254 else 04255 { 04256 CvTreeNodeIterator tree_iterator; 04257 04258 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ_TREE ); 04259 cvStartWriteStruct( fs, "sequences", CV_NODE_SEQ ); 04260 cvInitTreeNodeIterator( &tree_iterator, seq, INT_MAX ); 04261 04262 for(;;) 04263 { 04264 if( !tree_iterator.node ) 04265 break; 04266 icvWriteSeq( fs, 0, tree_iterator.node, attr, tree_iterator.level ); 04267 cvNextTreeNode( &tree_iterator ); 04268 } 04269 04270 cvEndWriteStruct( fs ); 04271 cvEndWriteStruct( fs ); 04272 } 04273 } 04274 04275 04276 static void* 04277 icvReadSeq( CvFileStorage* fs, CvFileNode* node ) 04278 { 04279 void* ptr = 0; 04280 CvSeq* seq; 04281 CvSeqBlock* block; 04282 CvFileNode *data, *header_node, *rect_node, *origin_node; 04283 CvSeqReader reader; 04284 int total, flags; 04285 int elem_size, header_size = sizeof(CvSeq); 04286 int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count; 04287 int items_per_elem = 0; 04288 const char* flags_str; 04289 const char* header_dt; 04290 const char* dt; 04291 char* endptr = 0; 04292 04293 flags_str = cvReadStringByName( fs, node, "flags", 0 ); 04294 total = cvReadIntByName( fs, node, "count", -1 ); 04295 dt = cvReadStringByName( fs, node, "dt", 0 ); 04296 04297 if( !flags_str || total == -1 || !dt ) 04298 CV_Error( CV_StsError, "Some of essential sequence attributes are absent" ); 04299 04300 flags = CV_SEQ_MAGIC_VAL; 04301 04302 if( cv_isdigit(flags_str[0]) ) 04303 { 04304 const int OLD_SEQ_ELTYPE_BITS = 9; 04305 const int OLD_SEQ_ELTYPE_MASK = (1 << OLD_SEQ_ELTYPE_BITS) - 1; 04306 const int OLD_SEQ_KIND_BITS = 3; 04307 const int OLD_SEQ_KIND_MASK = ((1 << OLD_SEQ_KIND_BITS) - 1) << OLD_SEQ_ELTYPE_BITS; 04308 const int OLD_SEQ_KIND_CURVE = 1 << OLD_SEQ_ELTYPE_BITS; 04309 const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS; 04310 const int OLD_SEQ_FLAG_CLOSED = 1 << OLD_SEQ_FLAG_SHIFT; 04311 const int OLD_SEQ_FLAG_HOLE = 8 << OLD_SEQ_FLAG_SHIFT; 04312 04313 int flags0 = (int)strtol( flags_str, &endptr, 16 ); 04314 if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SEQ_MAGIC_VAL ) 04315 CV_Error( CV_StsError, "The sequence flags are invalid" ); 04316 if( (flags0 & OLD_SEQ_KIND_MASK) == OLD_SEQ_KIND_CURVE ) 04317 flags |= CV_SEQ_KIND_CURVE; 04318 if( flags0 & OLD_SEQ_FLAG_CLOSED ) 04319 flags |= CV_SEQ_FLAG_CLOSED; 04320 if( flags0 & OLD_SEQ_FLAG_HOLE ) 04321 flags |= CV_SEQ_FLAG_HOLE; 04322 flags |= flags0 & OLD_SEQ_ELTYPE_MASK; 04323 } 04324 else 04325 { 04326 if( strstr(flags_str, "curve") ) 04327 flags |= CV_SEQ_KIND_CURVE; 04328 if( strstr(flags_str, "closed") ) 04329 flags |= CV_SEQ_FLAG_CLOSED; 04330 if( strstr(flags_str, "hole") ) 04331 flags |= CV_SEQ_FLAG_HOLE; 04332 if( !strstr(flags_str, "untyped") ) 04333 { 04334 //try 04335 // { 04336 flags |= icvDecodeSimpleFormat(dt); 04337 //} 04338 // catch(...) 04339 // { 04340 // } 04341 } 04342 } 04343 04344 header_dt = cvReadStringByName( fs, node, "header_dt", 0 ); 04345 header_node = cvGetFileNodeByName( fs, node, "header_user_data" ); 04346 04347 if( (header_dt != 0) ^ (header_node != 0) ) 04348 CV_Error( CV_StsError, 04349 "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" ); 04350 04351 rect_node = cvGetFileNodeByName( fs, node, "rect" ); 04352 origin_node = cvGetFileNodeByName( fs, node, "origin" ); 04353 04354 if( (header_node != 0) + (rect_node != 0) + (origin_node != 0) > 1 ) 04355 CV_Error( CV_StsError, "Only one of \"header_user_data\", \"rect\" and \"origin\" tags may occur" ); 04356 04357 if( header_dt ) 04358 { 04359 header_size = icvCalcElemSize( header_dt, header_size ); 04360 } 04361 else if( rect_node ) 04362 header_size = sizeof(CvPoint2DSeq); 04363 else if( origin_node ) 04364 header_size = sizeof(CvChain); 04365 04366 elem_size = icvCalcElemSize( dt, 0 ); 04367 seq = cvCreateSeq( flags, header_size, elem_size, fs->dststorage ); 04368 04369 if( header_node ) 04370 { 04371 cvReadRawData( fs, header_node, (char*)seq + sizeof(CvSeq), header_dt ); 04372 } 04373 else if( rect_node ) 04374 { 04375 CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq; 04376 point_seq->rect.x = cvReadIntByName( fs, rect_node, "x", 0 ); 04377 point_seq->rect.y = cvReadIntByName( fs, rect_node, "y", 0 ); 04378 point_seq->rect.width = cvReadIntByName( fs, rect_node, "width", 0 ); 04379 point_seq->rect.height = cvReadIntByName( fs, rect_node, "height", 0 ); 04380 point_seq->color = cvReadIntByName( fs, node, "color", 0 ); 04381 } 04382 else if( origin_node ) 04383 { 04384 CvChain* chain = (CvChain*)seq; 04385 chain->origin.x = cvReadIntByName( fs, origin_node, "x", 0 ); 04386 chain->origin.y = cvReadIntByName( fs, origin_node, "y", 0 ); 04387 } 04388 04389 cvSeqPushMulti( seq, 0, total, 0 ); 04390 fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); 04391 fmt_pair_count *= 2; 04392 for( i = 0; i < fmt_pair_count; i += 2 ) 04393 items_per_elem += fmt_pairs[i]; 04394 04395 data = cvGetFileNodeByName( fs, node, "data" ); 04396 if( !data ) 04397 CV_Error( CV_StsError, "The image data is not found in file storage" ); 04398 04399 if( icvFileNodeSeqLen( data ) != total*items_per_elem ) 04400 CV_Error( CV_StsError, "The number of stored elements does not match to \"count\"" ); 04401 04402 cvStartReadRawData( fs, data, &reader ); 04403 for( block = seq->first; block; block = block->next ) 04404 { 04405 int delta = block->count*items_per_elem; 04406 cvReadRawDataSlice( fs, &reader, delta, block->data, dt ); 04407 if( block == seq->first->prev ) 04408 break; 04409 } 04410 04411 ptr = seq; 04412 return ptr; 04413 } 04414 04415 04416 static void* 04417 icvReadSeqTree( CvFileStorage* fs, CvFileNode* node ) 04418 { 04419 void* ptr = 0; 04420 CvFileNode *sequences_node = cvGetFileNodeByName( fs, node, "sequences" ); 04421 CvSeq* sequences; 04422 CvSeq* root = 0; 04423 CvSeq* parent = 0; 04424 CvSeq* prev_seq = 0; 04425 CvSeqReader reader; 04426 int i, total; 04427 int prev_level = 0; 04428 04429 if( !sequences_node || !CV_NODE_IS_SEQ(sequences_node->tag) ) 04430 CV_Error( CV_StsParseError, 04431 "opencv-sequence-tree instance should contain a field \"sequences\" that should be a sequence" ); 04432 04433 sequences = sequences_node->data.seq; 04434 total = sequences->total; 04435 04436 cvStartReadSeq( sequences, &reader, 0 ); 04437 for( i = 0; i < total; i++ ) 04438 { 04439 CvFileNode* elem = (CvFileNode*)reader.ptr; 04440 CvSeq* seq; 04441 int level; 04442 seq = (CvSeq*)cvRead( fs, elem ); 04443 level = cvReadIntByName( fs, elem, "level", -1 ); 04444 if( level < 0 ) 04445 CV_Error( CV_StsParseError, "All the sequence tree nodes should contain \"level\" field" ); 04446 if( !root ) 04447 root = seq; 04448 if( level > prev_level ) 04449 { 04450 assert( level == prev_level + 1 ); 04451 parent = prev_seq; 04452 prev_seq = 0; 04453 if( parent ) 04454 parent->v_next = seq; 04455 } 04456 else if( level < prev_level ) 04457 { 04458 for( ; prev_level > level; prev_level-- ) 04459 prev_seq = prev_seq->v_prev; 04460 parent = prev_seq->v_prev; 04461 } 04462 seq->h_prev = prev_seq; 04463 if( prev_seq ) 04464 prev_seq->h_next = seq; 04465 seq->v_prev = parent; 04466 prev_seq = seq; 04467 prev_level = level; 04468 CV_NEXT_SEQ_ELEM( sequences->elem_size, reader ); 04469 } 04470 04471 ptr = root; 04472 return ptr; 04473 } 04474 04475 /******************************* CvGraph ******************************/ 04476 04477 static int 04478 icvIsGraph( const void* ptr ) 04479 { 04480 return CV_IS_GRAPH(ptr); 04481 } 04482 04483 04484 static void 04485 icvReleaseGraph( void** ptr ) 04486 { 04487 if( !ptr ) 04488 CV_Error( CV_StsNullPtr, "NULL double pointer" ); 04489 04490 *ptr = 0; // it's impossible now to release graph, so just clear the pointer 04491 } 04492 04493 04494 static void* 04495 icvCloneGraph( const void* ptr ) 04496 { 04497 return cvCloneGraph( (const CvGraph*)ptr, 0 ); 04498 } 04499 04500 04501 static void 04502 icvWriteGraph( CvFileStorage* fs, const char* name, 04503 const void* struct_ptr, CvAttrList attr ) 04504 { 04505 int* flag_buf = 0; 04506 char* write_buf = 0; 04507 const CvGraph* graph = (const CvGraph*)struct_ptr; 04508 CvSeqReader reader; 04509 char buf[128]; 04510 int i, k, vtx_count, edge_count; 04511 char vtx_dt_buf[128], *vtx_dt; 04512 char edge_dt_buf[128], *edge_dt; 04513 int write_buf_size; 04514 04515 assert( CV_IS_GRAPH(graph) ); 04516 vtx_count = cvGraphGetVtxCount( graph ); 04517 edge_count = cvGraphGetEdgeCount( graph ); 04518 flag_buf = (int*)cvAlloc( vtx_count*sizeof(flag_buf[0])); 04519 04520 // count vertices 04521 cvStartReadSeq( (CvSeq*)graph, &reader ); 04522 for( i = 0, k = 0; i < graph->total; i++ ) 04523 { 04524 if( CV_IS_SET_ELEM( reader.ptr )) 04525 { 04526 CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr; 04527 flag_buf[k] = vtx->flags; 04528 vtx->flags = k++; 04529 } 04530 CV_NEXT_SEQ_ELEM( graph->elem_size, reader ); 04531 } 04532 04533 // write header 04534 cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_GRAPH ); 04535 04536 cvWriteString(fs, "flags", CV_IS_GRAPH_ORIENTED(graph) ? "oriented" : "", 1); 04537 04538 cvWriteInt( fs, "vertex_count", vtx_count ); 04539 vtx_dt = icvGetFormat( (CvSeq*)graph, "vertex_dt", 04540 &attr, sizeof(CvGraphVtx), vtx_dt_buf ); 04541 if( vtx_dt ) 04542 cvWriteString( fs, "vertex_dt", vtx_dt, 0 ); 04543 04544 cvWriteInt( fs, "edge_count", edge_count ); 04545 edge_dt = icvGetFormat( (CvSeq*)graph->edges, "edge_dt", 04546 &attr, sizeof(CvGraphEdge), buf ); 04547 sprintf( edge_dt_buf, "2if%s", edge_dt ? edge_dt : "" ); 04548 edge_dt = edge_dt_buf; 04549 cvWriteString( fs, "edge_dt", edge_dt, 0 ); 04550 04551 icvWriteHeaderData( fs, (CvSeq*)graph, &attr, sizeof(CvGraph) ); 04552 04553 write_buf_size = MAX( 3*graph->elem_size, 1 << 16 ); 04554 write_buf_size = MAX( 3*graph->edges->elem_size, write_buf_size ); 04555 write_buf = (char*)cvAlloc( write_buf_size ); 04556 04557 // as vertices and edges are written in similar way, 04558 // do it as a parametrized 2-iteration loop 04559 for( k = 0; k < 2; k++ ) 04560 { 04561 const char* dt = k == 0 ? vtx_dt : edge_dt; 04562 if( dt ) 04563 { 04564 CvSet* data = k == 0 ? (CvSet*)graph : graph->edges; 04565 int elem_size = data->elem_size; 04566 int write_elem_size = icvCalcElemSize( dt, 0 ); 04567 char* src_ptr = write_buf; 04568 int write_max = write_buf_size / write_elem_size, write_count = 0; 04569 04570 // alignment of user part of the edge data following 2if 04571 int edge_user_align = sizeof(float); 04572 04573 if( k == 1 ) 04574 { 04575 int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count; 04576 fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS ); 04577 if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[2*2+1]) >= (int)sizeof(double)) 04578 edge_user_align = sizeof(double); 04579 } 04580 04581 cvStartWriteStruct( fs, k == 0 ? "vertices" : "edges", 04582 CV_NODE_SEQ + CV_NODE_FLOW ); 04583 cvStartReadSeq( (CvSeq*)data, &reader ); 04584 for( i = 0; i < data->total; i++ ) 04585 { 04586 if( CV_IS_SET_ELEM( reader.ptr )) 04587 { 04588 if( k == 0 ) // vertices 04589 memcpy( src_ptr, reader.ptr + sizeof(CvGraphVtx), write_elem_size ); 04590 else 04591 { 04592 CvGraphEdge* edge = (CvGraphEdge*)reader.ptr; 04593 src_ptr = (char*)cvAlignPtr( src_ptr, sizeof(int) ); 04594 ((int*)src_ptr)[0] = edge->vtx[0]->flags; 04595 ((int*)src_ptr)[1] = edge->vtx[1]->flags; 04596 *(float*)(src_ptr + sizeof(int)*2) = edge->weight; 04597 if( elem_size > (int)sizeof(CvGraphEdge) ) 04598 { 04599 char* src_ptr2 = (char*)cvAlignPtr( src_ptr + 2*sizeof(int) 04600 + sizeof(float), edge_user_align ); 04601 memcpy( src_ptr2, edge + 1, elem_size - sizeof(CvGraphEdge) ); 04602 } 04603 } 04604 src_ptr += write_elem_size; 04605 if( ++write_count >= write_max ) 04606 { 04607 cvWriteRawData( fs, write_buf, write_count, dt ); 04608 write_count = 0; 04609 src_ptr = write_buf; 04610 } 04611 } 04612 CV_NEXT_SEQ_ELEM( data->elem_size, reader ); 04613 } 04614 04615 if( write_count > 0 ) 04616 cvWriteRawData( fs, write_buf, write_count, dt ); 04617 cvEndWriteStruct( fs ); 04618 } 04619 } 04620 04621 cvEndWriteStruct( fs ); 04622 04623 // final stage. restore the graph flags 04624 cvStartReadSeq( (CvSeq*)graph, &reader ); 04625 vtx_count = 0; 04626 for( i = 0; i < graph->total; i++ ) 04627 { 04628 if( CV_IS_SET_ELEM( reader.ptr )) 04629 ((CvGraphVtx*)reader.ptr)->flags = flag_buf[vtx_count++]; 04630 CV_NEXT_SEQ_ELEM( graph->elem_size, reader ); 04631 } 04632 04633 cvFree( &write_buf ); 04634 cvFree( &flag_buf ); 04635 } 04636 04637 04638 static void* 04639 icvReadGraph( CvFileStorage* fs, CvFileNode* node ) 04640 { 04641 void* ptr = 0; 04642 char* read_buf = 0; 04643 CvGraphVtx** vtx_buf = 0; 04644 CvGraph* graph; 04645 CvFileNode *header_node, *vtx_node, *edge_node; 04646 int flags, vtx_count, edge_count; 04647 int vtx_size = sizeof(CvGraphVtx), edge_size, header_size = sizeof(CvGraph); 04648 int src_vtx_size = 0, src_edge_size; 04649 int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count; 04650 int vtx_items_per_elem = 0, edge_items_per_elem = 0; 04651 int edge_user_align = sizeof(float); 04652 int read_buf_size; 04653 int i, k; 04654 const char* flags_str; 04655 const char* header_dt; 04656 const char* vtx_dt; 04657 const char* edge_dt; 04658 char* endptr = 0; 04659 04660 flags_str = cvReadStringByName( fs, node, "flags", 0 ); 04661 vtx_dt = cvReadStringByName( fs, node, "vertex_dt", 0 ); 04662 edge_dt = cvReadStringByName( fs, node, "edge_dt", 0 ); 04663 vtx_count = cvReadIntByName( fs, node, "vertex_count", -1 ); 04664 edge_count = cvReadIntByName( fs, node, "edge_count", -1 ); 04665 04666 if( !flags_str || vtx_count == -1 || edge_count == -1 || !edge_dt ) 04667 CV_Error( CV_StsError, "Some of essential graph attributes are absent" ); 04668 04669 flags = CV_SET_MAGIC_VAL + CV_GRAPH; 04670 04671 if( isxdigit(flags_str[0]) ) 04672 { 04673 const int OLD_SEQ_ELTYPE_BITS = 9; 04674 const int OLD_SEQ_KIND_BITS = 3; 04675 const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS; 04676 const int OLD_GRAPH_FLAG_ORIENTED = 1 << OLD_SEQ_FLAG_SHIFT; 04677 04678 int flags0 = (int)strtol( flags_str, &endptr, 16 ); 04679 if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SET_MAGIC_VAL ) 04680 CV_Error( CV_StsError, "The sequence flags are invalid" ); 04681 if( flags0 & OLD_GRAPH_FLAG_ORIENTED ) 04682 flags |= CV_GRAPH_FLAG_ORIENTED; 04683 } 04684 else 04685 { 04686 if( strstr(flags_str, "oriented") ) 04687 flags |= CV_GRAPH_FLAG_ORIENTED; 04688 } 04689 04690 header_dt = cvReadStringByName( fs, node, "header_dt", 0 ); 04691 header_node = cvGetFileNodeByName( fs, node, "header_user_data" ); 04692 04693 if( (header_dt != 0) ^ (header_node != 0) ) 04694 CV_Error( CV_StsError, 04695 "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" ); 04696 04697 if( header_dt ) 04698 header_size = icvCalcElemSize( header_dt, header_size ); 04699 04700 if( vtx_dt ) 04701 { 04702 src_vtx_size = icvCalcElemSize( vtx_dt, 0 ); 04703 vtx_size = icvCalcElemSize( vtx_dt, vtx_size ); 04704 fmt_pair_count = icvDecodeFormat( edge_dt, 04705 fmt_pairs, CV_FS_MAX_FMT_PAIRS ); 04706 fmt_pair_count *= 2; 04707 for( i = 0; i < fmt_pair_count; i += 2 ) 04708 vtx_items_per_elem += fmt_pairs[i]; 04709 } 04710 04711 { 04712 char dst_edge_dt_buf[128]; 04713 const char* dst_edge_dt = 0; 04714 04715 fmt_pair_count = icvDecodeFormat( edge_dt, 04716 fmt_pairs, CV_FS_MAX_FMT_PAIRS ); 04717 if( fmt_pair_count < 2 || 04718 fmt_pairs[0] != 2 || fmt_pairs[1] != CV_32S || 04719 fmt_pairs[2] < 1 || fmt_pairs[3] != CV_32F ) 04720 CV_Error( CV_StsBadArg, 04721 "Graph edges should start with 2 integers and a float" ); 04722 04723 // alignment of user part of the edge data following 2if 04724 if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[5]) >= (int)sizeof(double)) 04725 edge_user_align = sizeof(double); 04726 04727 fmt_pair_count *= 2; 04728 for( i = 0; i < fmt_pair_count; i += 2 ) 04729 edge_items_per_elem += fmt_pairs[i]; 04730 04731 if( edge_dt[2] == 'f' || (edge_dt[2] == '1' && edge_dt[3] == 'f') ) 04732 dst_edge_dt = edge_dt + 3 + cv_isdigit(edge_dt[2]); 04733 else 04734 { 04735 int val = (int)strtol( edge_dt + 2, &endptr, 10 ); 04736 sprintf( dst_edge_dt_buf, "%df%s", val-1, endptr ); 04737 dst_edge_dt = dst_edge_dt_buf; 04738 } 04739 04740 edge_size = icvCalcElemSize( dst_edge_dt, sizeof(CvGraphEdge) ); 04741 src_edge_size = icvCalcElemSize( edge_dt, 0 ); 04742 } 04743 04744 graph = cvCreateGraph( flags, header_size, vtx_size, edge_size, fs->dststorage ); 04745 04746 if( header_node ) 04747 cvReadRawData( fs, header_node, (char*)graph + sizeof(CvGraph), header_dt ); 04748 04749 read_buf_size = MAX( src_vtx_size*3, 1 << 16 ); 04750 read_buf_size = MAX( src_edge_size*3, read_buf_size ); 04751 read_buf = (char*)cvAlloc( read_buf_size ); 04752 vtx_buf = (CvGraphVtx**)cvAlloc( vtx_count * sizeof(vtx_buf[0]) ); 04753 04754 vtx_node = cvGetFileNodeByName( fs, node, "vertices" ); 04755 edge_node = cvGetFileNodeByName( fs, node, "edges" ); 04756 if( !edge_node ) 04757 CV_Error( CV_StsBadArg, "No edges data" ); 04758 if( vtx_dt && !vtx_node ) 04759 CV_Error( CV_StsBadArg, "No vertices data" ); 04760 04761 // as vertices and edges are read in similar way, 04762 // do it as a parametrized 2-iteration loop 04763 for( k = 0; k < 2; k++ ) 04764 { 04765 const char* dt = k == 0 ? vtx_dt : edge_dt; 04766 int elem_size = k == 0 ? vtx_size : edge_size; 04767 int src_elem_size = k == 0 ? src_vtx_size : src_edge_size; 04768 int items_per_elem = k == 0 ? vtx_items_per_elem : edge_items_per_elem; 04769 int elem_count = k == 0 ? vtx_count : edge_count; 04770 char* dst_ptr = read_buf; 04771 int read_max = read_buf_size /MAX(src_elem_size, 1), read_count = 0; 04772 CvSeqReader reader; 04773 if(dt) 04774 cvStartReadRawData( fs, k == 0 ? vtx_node : edge_node, &reader ); 04775 04776 for( i = 0; i < elem_count; i++ ) 04777 { 04778 if( read_count == 0 && dt ) 04779 { 04780 int count = MIN( elem_count - i, read_max )*items_per_elem; 04781 cvReadRawDataSlice( fs, &reader, count, read_buf, dt ); 04782 read_count = count; 04783 dst_ptr = read_buf; 04784 } 04785 04786 if( k == 0 ) 04787 { 04788 CvGraphVtx* vtx; 04789 cvGraphAddVtx( graph, 0, &vtx ); 04790 vtx_buf[i] = vtx; 04791 if( dt ) 04792 memcpy( vtx + 1, dst_ptr, src_elem_size ); 04793 } 04794 else 04795 { 04796 CvGraphEdge* edge = 0; 04797 int vtx1 = ((int*)dst_ptr)[0]; 04798 int vtx2 = ((int*)dst_ptr)[1]; 04799 int result; 04800 04801 if( (unsigned)vtx1 >= (unsigned)vtx_count || 04802 (unsigned)vtx2 >= (unsigned)vtx_count ) 04803 CV_Error( CV_StsOutOfRange, 04804 "Some of stored vertex indices are out of range" ); 04805 04806 result = cvGraphAddEdgeByPtr( graph, 04807 vtx_buf[vtx1], vtx_buf[vtx2], 0, &edge ); 04808 04809 if( result == 0 ) 04810 CV_Error( CV_StsBadArg, "Duplicated edge has occured" ); 04811 04812 edge->weight = *(float*)(dst_ptr + sizeof(int)*2); 04813 if( elem_size > (int)sizeof(CvGraphEdge) ) 04814 { 04815 char* dst_ptr2 = (char*)cvAlignPtr( dst_ptr + sizeof(int)*2 + 04816 sizeof(float), edge_user_align ); 04817 memcpy( edge + 1, dst_ptr2, elem_size - sizeof(CvGraphEdge) ); 04818 } 04819 } 04820 04821 dst_ptr += src_elem_size; 04822 read_count--; 04823 } 04824 } 04825 04826 ptr = graph; 04827 cvFree( &read_buf ); 04828 cvFree( &vtx_buf ); 04829 04830 return ptr; 04831 } 04832 04833 /****************************************************************************************\ 04834 * RTTI Functions * 04835 \****************************************************************************************/ 04836 04837 CvTypeInfo *CvType::first = 0, *CvType::last = 0; 04838 04839 CvType::CvType( const char* type_name, 04840 CvIsInstanceFunc is_instance, CvReleaseFunc release, 04841 CvReadFunc read, CvWriteFunc write, CvCloneFunc clone ) 04842 { 04843 CvTypeInfo _info; 04844 _info.flags = 0; 04845 _info.header_size = sizeof(_info); 04846 _info.type_name = type_name; 04847 _info.prev = _info.next = 0; 04848 _info.is_instance = is_instance; 04849 _info.release = release; 04850 _info.clone = clone; 04851 _info.read = read; 04852 _info.write = write; 04853 04854 cvRegisterType( &_info ); 04855 info = first; 04856 } 04857 04858 04859 CvType::~CvType() 04860 { 04861 cvUnregisterType( info->type_name ); 04862 } 04863 04864 04865 CvType seq_type( CV_TYPE_NAME_SEQ, icvIsSeq, icvReleaseSeq, icvReadSeq, 04866 icvWriteSeqTree /* this is the entry point for 04867 writing a single sequence too */, icvCloneSeq ); 04868 04869 CvType seq_tree_type( CV_TYPE_NAME_SEQ_TREE, icvIsSeq, icvReleaseSeq, 04870 icvReadSeqTree, icvWriteSeqTree, icvCloneSeq ); 04871 04872 CvType seq_graph_type( CV_TYPE_NAME_GRAPH, icvIsGraph, icvReleaseGraph, 04873 icvReadGraph, icvWriteGraph, icvCloneGraph ); 04874 04875 CvType sparse_mat_type( CV_TYPE_NAME_SPARSE_MAT, icvIsSparseMat, 04876 (CvReleaseFunc)cvReleaseSparseMat, icvReadSparseMat, 04877 icvWriteSparseMat, (CvCloneFunc)cvCloneSparseMat ); 04878 04879 CvType image_type( CV_TYPE_NAME_IMAGE, icvIsImage, (CvReleaseFunc)cvReleaseImage, 04880 icvReadImage, icvWriteImage, (CvCloneFunc)cvCloneImage ); 04881 04882 CvType mat_type( CV_TYPE_NAME_MAT, icvIsMat, (CvReleaseFunc)cvReleaseMat, 04883 icvReadMat, icvWriteMat, (CvCloneFunc)cvCloneMat ); 04884 04885 CvType matnd_type( CV_TYPE_NAME_MATND, icvIsMatND, (CvReleaseFunc)cvReleaseMatND, 04886 icvReadMatND, icvWriteMatND, (CvCloneFunc)cvCloneMatND ); 04887 04888 CV_IMPL void 04889 cvRegisterType( const CvTypeInfo* _info ) 04890 { 04891 CvTypeInfo* info = 0; 04892 int i, len; 04893 char c; 04894 04895 //if( !CvType::first ) 04896 // icvCreateStandardTypes(); 04897 04898 if( !_info || _info->header_size != sizeof(CvTypeInfo) ) 04899 CV_Error( CV_StsBadSize, "Invalid type info" ); 04900 04901 if( !_info->is_instance || !_info->release || 04902 !_info->read || !_info->write ) 04903 CV_Error( CV_StsNullPtr, 04904 "Some of required function pointers " 04905 "(is_instance, release, read or write) are NULL"); 04906 04907 c = _info->type_name[0]; 04908 if( !cv_isalpha(c) && c != '_' ) 04909 CV_Error( CV_StsBadArg, "Type name should start with a letter or _" ); 04910 04911 len = (int)strlen(_info->type_name); 04912 04913 for( i = 0; i < len; i++ ) 04914 { 04915 c = _info->type_name[i]; 04916 if( !cv_isalnum(c) && c != '-' && c != '_' ) 04917 CV_Error( CV_StsBadArg, 04918 "Type name should contain only letters, digits, - and _" ); 04919 } 04920 04921 info = (CvTypeInfo*)cvAlloc( sizeof(*info) + len + 1 ); 04922 04923 *info = *_info; 04924 info->type_name = (char*)(info + 1); 04925 memcpy( (char*)info->type_name, _info->type_name, len + 1 ); 04926 04927 info->flags = 0; 04928 info->next = CvType::first; 04929 info->prev = 0; 04930 if( CvType::first ) 04931 CvType::first->prev = info; 04932 else 04933 CvType::last = info; 04934 CvType::first = info; 04935 } 04936 04937 04938 CV_IMPL void 04939 cvUnregisterType( const char* type_name ) 04940 { 04941 CvTypeInfo* info; 04942 04943 info = cvFindType( type_name ); 04944 if( info ) 04945 { 04946 if( info->prev ) 04947 info->prev->next = info->next; 04948 else 04949 CvType::first = info->next; 04950 04951 if( info->next ) 04952 info->next->prev = info->prev; 04953 else 04954 CvType::last = info->prev; 04955 04956 if( !CvType::first || !CvType::last ) 04957 CvType::first = CvType::last = 0; 04958 04959 cvFree( &info ); 04960 } 04961 } 04962 04963 04964 CV_IMPL CvTypeInfo* 04965 cvFirstType( void ) 04966 { 04967 return CvType::first; 04968 } 04969 04970 04971 CV_IMPL CvTypeInfo* 04972 cvFindType( const char* type_name ) 04973 { 04974 CvTypeInfo* info = 0; 04975 04976 if (type_name) 04977 for( info = CvType::first; info != 0; info = info->next ) 04978 if( strcmp( info->type_name, type_name ) == 0 ) 04979 break; 04980 04981 return info; 04982 } 04983 04984 04985 CV_IMPL CvTypeInfo* 04986 cvTypeOf( const void* struct_ptr ) 04987 { 04988 CvTypeInfo* info = 0; 04989 04990 if( struct_ptr ) 04991 { 04992 for( info = CvType::first; info != 0; info = info->next ) 04993 if( info->is_instance( struct_ptr )) 04994 break; 04995 } 04996 04997 return info; 04998 } 04999 05000 05001 /* universal functions */ 05002 CV_IMPL void 05003 cvRelease( void** struct_ptr ) 05004 { 05005 CvTypeInfo* info; 05006 05007 if( !struct_ptr ) 05008 CV_Error( CV_StsNullPtr, "NULL double pointer" ); 05009 05010 if( *struct_ptr ) 05011 { 05012 info = cvTypeOf( *struct_ptr ); 05013 if( !info ) 05014 CV_Error( CV_StsError, "Unknown object type" ); 05015 if( !info->release ) 05016 CV_Error( CV_StsError, "release function pointer is NULL" ); 05017 05018 info->release( struct_ptr ); 05019 *struct_ptr = 0; 05020 } 05021 } 05022 05023 05024 void* cvClone( const void* struct_ptr ) 05025 { 05026 void* struct_copy = 0; 05027 CvTypeInfo* info; 05028 05029 if( !struct_ptr ) 05030 CV_Error( CV_StsNullPtr, "NULL structure pointer" ); 05031 05032 info = cvTypeOf( struct_ptr ); 05033 if( !info ) 05034 CV_Error( CV_StsError, "Unknown object type" ); 05035 if( !info->clone ) 05036 CV_Error( CV_StsError, "clone function pointer is NULL" ); 05037 05038 struct_copy = info->clone( struct_ptr ); 05039 return struct_copy; 05040 } 05041 05042 05043 /* reads matrix, image, sequence, graph etc. */ 05044 CV_IMPL void* 05045 cvRead( CvFileStorage* fs, CvFileNode* node, CvAttrList* list ) 05046 { 05047 void* obj = 0; 05048 CV_CHECK_FILE_STORAGE( fs ); 05049 05050 if( !node ) 05051 return 0; 05052 05053 if( !CV_NODE_IS_USER(node->tag) || !node->info ) 05054 CV_Error( CV_StsError, "The node does not represent a user object (unknown type?)" ); 05055 05056 obj = node->info->read( fs, node ); 05057 if( list ) 05058 *list = cvAttrList(0,0); 05059 05060 return obj; 05061 } 05062 05063 05064 /* writes matrix, image, sequence, graph etc. */ 05065 CV_IMPL void 05066 cvWrite( CvFileStorage* fs, const char* name, 05067 const void* ptr, CvAttrList attributes ) 05068 { 05069 CvTypeInfo* info; 05070 05071 CV_CHECK_OUTPUT_FILE_STORAGE( fs ); 05072 05073 if( !ptr ) 05074 CV_Error( CV_StsNullPtr, "Null pointer to the written object" ); 05075 05076 info = cvTypeOf( ptr ); 05077 if( !info ) 05078 CV_Error( CV_StsBadArg, "Unknown object" ); 05079 05080 if( !info->write ) 05081 CV_Error( CV_StsBadArg, "The object does not have write function" ); 05082 05083 info->write( fs, name, ptr, attributes ); 05084 } 05085 05086 05087 /* simple API for reading/writing data */ 05088 CV_IMPL void 05089 cvSave( const char* filename, const void* struct_ptr, 05090 const char* _name, const char* comment, CvAttrList attributes ) 05091 { 05092 CvFileStorage* fs = 0; 05093 05094 if( !struct_ptr ) 05095 CV_Error( CV_StsNullPtr, "NULL object pointer" ); 05096 05097 fs = cvOpenFileStorage( filename, 0, CV_STORAGE_WRITE ); 05098 if( !fs ) 05099 CV_Error( CV_StsError, "Could not open the file storage. Check the path and permissions" ); 05100 05101 cv::String name = _name ? cv::String(_name) : cv::FileStorage::getDefaultObjectName(filename); 05102 05103 if( comment ) 05104 cvWriteComment( fs, comment, 0 ); 05105 cvWrite( fs, name.c_str(), struct_ptr, attributes ); 05106 cvReleaseFileStorage( &fs ); 05107 } 05108 05109 CV_IMPL void* 05110 cvLoad( const char* filename, CvMemStorage* memstorage, 05111 const char* name, const char** _real_name ) 05112 { 05113 void* ptr = 0; 05114 const char* real_name = 0; 05115 cv::FileStorage fs(cvOpenFileStorage(filename, memstorage, CV_STORAGE_READ)); 05116 05117 CvFileNode* node = 0; 05118 05119 if( !fs.isOpened() ) 05120 return 0; 05121 05122 if( name ) 05123 { 05124 node = cvGetFileNodeByName( *fs, 0, name ); 05125 } 05126 else 05127 { 05128 int i, k; 05129 for( k = 0; k < (*fs)->roots->total; k++ ) 05130 { 05131 CvSeq* seq; 05132 CvSeqReader reader; 05133 05134 node = (CvFileNode*)cvGetSeqElem( (*fs)->roots, k ); 05135 if( !CV_NODE_IS_MAP( node->tag )) 05136 return 0; 05137 seq = node->data.seq; 05138 node = 0; 05139 05140 cvStartReadSeq( seq, &reader, 0 ); 05141 05142 // find the first element in the map 05143 for( i = 0; i < seq->total; i++ ) 05144 { 05145 if( CV_IS_SET_ELEM( reader.ptr )) 05146 { 05147 node = (CvFileNode*)reader.ptr; 05148 goto stop_search; 05149 } 05150 CV_NEXT_SEQ_ELEM( seq->elem_size, reader ); 05151 } 05152 } 05153 05154 stop_search: 05155 ; 05156 } 05157 05158 if( !node ) 05159 CV_Error( CV_StsObjectNotFound, "Could not find the/an object in file storage" ); 05160 05161 real_name = cvGetFileNodeName( node ); 05162 ptr = cvRead( *fs, node, 0 ); 05163 05164 // sanity check 05165 if( !memstorage && (CV_IS_SEQ( ptr ) || CV_IS_SET( ptr )) ) 05166 CV_Error( CV_StsNullPtr, 05167 "NULL memory storage is passed - the loaded dynamic structure can not be stored" ); 05168 05169 if( cvGetErrStatus() < 0 ) 05170 { 05171 cvRelease( (void**)&ptr ); 05172 real_name = 0; 05173 } 05174 05175 if( _real_name) 05176 { 05177 if (real_name) 05178 { 05179 *_real_name = (const char*)cvAlloc(strlen(real_name)); 05180 memcpy((void*)*_real_name, real_name, strlen(real_name)); 05181 } else { 05182 *_real_name = 0; 05183 } 05184 } 05185 05186 return ptr; 05187 } 05188 05189 05190 ///////////////////////// new C++ interface for CvFileStorage /////////////////////////// 05191 05192 namespace cv 05193 { 05194 05195 static void getElemSize( const String& fmt, size_t& elemSize, size_t& cn ) 05196 { 05197 const char* dt = fmt.c_str(); 05198 cn = 1; 05199 if( cv_isdigit(dt[0]) ) 05200 { 05201 cn = dt[0] - '0'; 05202 dt++; 05203 } 05204 char c = dt[0]; 05205 elemSize = cn*(c == 'u' || c == 'c' ? sizeof(uchar) : c == 'w' || c == 's' ? sizeof(ushort) : 05206 c == 'i' ? sizeof(int) : c == 'f' ? sizeof(float) : c == 'd' ? sizeof(double) : 05207 c == 'r' ? sizeof(void*) : (size_t)0); 05208 } 05209 05210 FileStorage::FileStorage() 05211 { 05212 state = UNDEFINED; 05213 } 05214 05215 FileStorage::FileStorage(const String& filename, int flags, const String& encoding) 05216 { 05217 state = UNDEFINED; 05218 open( filename, flags, encoding ); 05219 } 05220 05221 FileStorage::FileStorage(CvFileStorage* _fs, bool owning) 05222 { 05223 if (owning) fs.reset(_fs); 05224 else fs = Ptr<CvFileStorage> (Ptr<CvFileStorage> (), _fs); 05225 05226 state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED; 05227 } 05228 05229 FileStorage::~FileStorage() 05230 { 05231 while( structs.size() > 0 ) 05232 { 05233 cvEndWriteStruct(fs); 05234 structs.pop_back(); 05235 } 05236 } 05237 05238 bool FileStorage::open(const String& filename, int flags, const String& encoding) 05239 { 05240 release(); 05241 fs.reset(cvOpenFileStorage( filename.c_str(), 0, flags, 05242 !encoding.empty() ? encoding.c_str() : 0)); 05243 bool ok = isOpened(); 05244 state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED; 05245 return ok; 05246 } 05247 05248 bool FileStorage::isOpened() const 05249 { 05250 return fs && fs->is_opened; 05251 } 05252 05253 void FileStorage::release() 05254 { 05255 fs.release(); 05256 structs.clear(); 05257 state = UNDEFINED; 05258 } 05259 05260 String FileStorage::releaseAndGetString() 05261 { 05262 String buf; 05263 if( fs && fs->outbuf ) 05264 icvClose(fs, &buf); 05265 05266 release(); 05267 return buf; 05268 } 05269 05270 FileNode FileStorage::root(int streamidx) const 05271 { 05272 return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode(); 05273 } 05274 05275 FileStorage& operator << (FileStorage& fs, const String& str) 05276 { 05277 enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED, 05278 VALUE_EXPECTED = FileStorage::VALUE_EXPECTED, 05279 INSIDE_MAP = FileStorage::INSIDE_MAP }; 05280 const char* _str = str.c_str(); 05281 if( !fs.isOpened() || !_str ) 05282 return fs; 05283 if( *_str == '}' || *_str == ']' ) 05284 { 05285 if( fs.structs.empty() ) 05286 CV_Error_( CV_StsError, ("Extra closing '%c'", *_str) ); 05287 if( (*_str == ']' ? '[' : '{') != fs.structs.back() ) 05288 CV_Error_( CV_StsError, 05289 ("The closing '%c' does not match the opening '%c'", *_str, fs.structs.back())); 05290 fs.structs.pop_back(); 05291 fs.state = fs.structs.empty() || fs.structs.back() == '{' ? 05292 INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED; 05293 cvEndWriteStruct( *fs ); 05294 fs.elname = String(); 05295 } 05296 else if( fs.state == NAME_EXPECTED + INSIDE_MAP ) 05297 { 05298 if( !cv_isalpha(*_str) ) 05299 CV_Error_( CV_StsError, ("Incorrect element name %s", _str) ); 05300 fs.elname = str; 05301 fs.state = VALUE_EXPECTED + INSIDE_MAP; 05302 } 05303 else if( (fs.state & 3) == VALUE_EXPECTED ) 05304 { 05305 if( *_str == '{' || *_str == '[' ) 05306 { 05307 fs.structs.push_back(*_str); 05308 int flags = *_str++ == '{' ? CV_NODE_MAP : CV_NODE_SEQ; 05309 fs.state = flags == CV_NODE_MAP ? INSIDE_MAP + 05310 NAME_EXPECTED : VALUE_EXPECTED; 05311 if( *_str == ':' ) 05312 { 05313 flags |= CV_NODE_FLOW; 05314 _str++; 05315 } 05316 cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0, 05317 flags, *_str ? _str : 0 ); 05318 fs.elname = String(); 05319 } 05320 else 05321 { 05322 write( fs, fs.elname, (_str[0] == '\\' && (_str[1] == '{' || _str[1] == '}' || 05323 _str[1] == '[' || _str[1] == ']')) ? String(_str+1) : str ); 05324 if( fs.state == INSIDE_MAP + VALUE_EXPECTED ) 05325 fs.state = INSIDE_MAP + NAME_EXPECTED; 05326 } 05327 } 05328 else 05329 CV_Error( CV_StsError, "Invalid fs.state" ); 05330 return fs; 05331 } 05332 05333 05334 void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len ) 05335 { 05336 if( !isOpened() ) 05337 return; 05338 size_t elemSize, cn; 05339 getElemSize( fmt, elemSize, cn ); 05340 CV_Assert( len % elemSize == 0 ); 05341 cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str()); 05342 } 05343 05344 05345 void FileStorage::writeObj( const String& name, const void* obj ) 05346 { 05347 if( !isOpened() ) 05348 return; 05349 cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj ); 05350 } 05351 05352 05353 FileNode FileStorage::operator[](const String& nodename) const 05354 { 05355 return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str())); 05356 } 05357 05358 FileNode FileStorage::operator[](const char* nodename) const 05359 { 05360 return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename)); 05361 } 05362 05363 FileNode FileNode::operator[](const String& nodename) const 05364 { 05365 return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str())); 05366 } 05367 05368 FileNode FileNode::operator[](const char* nodename) const 05369 { 05370 return FileNode(fs, cvGetFileNodeByName(fs, node, nodename)); 05371 } 05372 05373 FileNode FileNode::operator[](int i) const 05374 { 05375 return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) : 05376 i == 0 ? *this : FileNode(); 05377 } 05378 05379 String FileNode::name() const 05380 { 05381 const char* str; 05382 return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str); 05383 } 05384 05385 void* FileNode::readObj() const 05386 { 05387 if( !fs || !node ) 05388 return 0; 05389 return cvRead( (CvFileStorage*)fs, (CvFileNode*)node ); 05390 } 05391 05392 FileNodeIterator::FileNodeIterator() 05393 { 05394 fs = 0; 05395 container = 0; 05396 reader.ptr = 0; 05397 remaining = 0; 05398 } 05399 05400 FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs, 05401 const CvFileNode* _node, size_t _ofs) 05402 { 05403 if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE ) 05404 { 05405 int node_type = _node->tag & FileNode::TYPE_MASK; 05406 fs = _fs; 05407 container = _node; 05408 if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) ) 05409 { 05410 cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader ); 05411 remaining = FileNode(_fs, _node).size(); 05412 } 05413 else 05414 { 05415 reader.ptr = (schar*)_node; 05416 reader.seq = 0; 05417 remaining = 1; 05418 } 05419 (*this) += (int)_ofs; 05420 } 05421 else 05422 { 05423 fs = 0; 05424 container = 0; 05425 reader.ptr = 0; 05426 remaining = 0; 05427 } 05428 } 05429 05430 FileNodeIterator::FileNodeIterator(const FileNodeIterator& it) 05431 { 05432 fs = it.fs; 05433 container = it.container; 05434 reader = it.reader; 05435 remaining = it.remaining; 05436 } 05437 05438 FileNodeIterator& FileNodeIterator::operator ++() 05439 { 05440 if( remaining > 0 ) 05441 { 05442 if( reader.seq ) 05443 { 05444 if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max ) 05445 { 05446 cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 ); 05447 } 05448 } 05449 remaining--; 05450 } 05451 return *this; 05452 } 05453 05454 FileNodeIterator FileNodeIterator::operator ++(int) 05455 { 05456 FileNodeIterator it = *this; 05457 ++(*this); 05458 return it; 05459 } 05460 05461 FileNodeIterator& FileNodeIterator::operator --() 05462 { 05463 if( remaining < FileNode(fs, container).size() ) 05464 { 05465 if( reader.seq ) 05466 { 05467 if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min ) 05468 { 05469 cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 ); 05470 } 05471 } 05472 remaining++; 05473 } 05474 return *this; 05475 } 05476 05477 FileNodeIterator FileNodeIterator::operator --(int) 05478 { 05479 FileNodeIterator it = *this; 05480 --(*this); 05481 return it; 05482 } 05483 05484 FileNodeIterator& FileNodeIterator::operator += (int ofs) 05485 { 05486 if( ofs == 0 ) 05487 return *this; 05488 if( ofs > 0 ) 05489 ofs = std::min(ofs, (int)remaining); 05490 else 05491 { 05492 size_t count = FileNode(fs, container).size(); 05493 ofs = (int)(remaining - std::min(remaining - ofs, count)); 05494 } 05495 remaining -= ofs; 05496 if( reader.seq ) 05497 cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 ); 05498 return *this; 05499 } 05500 05501 FileNodeIterator& FileNodeIterator::operator -= (int ofs) 05502 { 05503 return operator += (-ofs); 05504 } 05505 05506 05507 FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount ) 05508 { 05509 if( fs && container && remaining > 0 ) 05510 { 05511 size_t elem_size, cn; 05512 getElemSize( fmt, elem_size, cn ); 05513 CV_Assert( elem_size > 0 ); 05514 size_t count = std::min(remaining, maxCount); 05515 05516 if( reader.seq ) 05517 { 05518 cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() ); 05519 remaining -= count*cn; 05520 } 05521 else 05522 { 05523 cvReadRawData( fs, container, vec, fmt.c_str() ); 05524 remaining = 0; 05525 } 05526 } 05527 return *this; 05528 } 05529 05530 05531 void write( FileStorage& fs, const String& name, int value ) 05532 { cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); } 05533 05534 void write( FileStorage& fs, const String& name, float value ) 05535 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); } 05536 05537 void write( FileStorage& fs, const String& name, double value ) 05538 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); } 05539 05540 void write( FileStorage& fs, const String& name, const String& value ) 05541 { cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); } 05542 05543 void writeScalar(FileStorage& fs, int value ) 05544 { cvWriteInt( *fs, 0, value ); } 05545 05546 void writeScalar(FileStorage& fs, float value ) 05547 { cvWriteReal( *fs, 0, value ); } 05548 05549 void writeScalar(FileStorage& fs, double value ) 05550 { cvWriteReal( *fs, 0, value ); } 05551 05552 void writeScalar(FileStorage& fs, const String& value ) 05553 { cvWriteString( *fs, 0, value.c_str() ); } 05554 05555 05556 void write( FileStorage& fs, const String& name, const Mat& value ) 05557 { 05558 if( value.dims <= 2 ) 05559 { 05560 CvMat mat = value; 05561 cvWrite( *fs, name.size() ? name.c_str() : 0, &mat ); 05562 } 05563 else 05564 { 05565 CvMatND mat = value; 05566 cvWrite( *fs, name.size() ? name.c_str() : 0, &mat ); 05567 } 05568 } 05569 05570 // TODO: the 4 functions below need to be implemented more efficiently 05571 void write( FileStorage& fs, const String& name, const SparseMat& value ) 05572 { 05573 Ptr<CvSparseMat> mat(cvCreateSparseMat(value)); 05574 cvWrite( *fs, name.size() ? name.c_str() : 0, mat ); 05575 } 05576 05577 05578 internal::WriteStructContext::WriteStructContext(FileStorage& _fs, 05579 const String& name, int flags, const String& typeName) : fs(&_fs) 05580 { 05581 cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags, 05582 !typeName.empty() ? typeName.c_str() : 0); 05583 fs->elname = String(); 05584 if ((flags & FileNode::TYPE_MASK) == FileNode::SEQ) 05585 { 05586 fs->state = FileStorage::VALUE_EXPECTED; 05587 fs->structs.push_back('['); 05588 } 05589 else 05590 { 05591 fs->state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP; 05592 fs->structs.push_back('{'); 05593 } 05594 } 05595 05596 internal::WriteStructContext::~WriteStructContext() 05597 { 05598 cvEndWriteStruct(**fs); 05599 fs->structs.pop_back(); 05600 fs->state = fs->structs.empty() || fs->structs.back() == '{' ? 05601 FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP : 05602 FileStorage::VALUE_EXPECTED; 05603 fs->elname = String(); 05604 } 05605 05606 05607 void read( const FileNode& node, Mat& mat, const Mat& default_mat ) 05608 { 05609 if( node.empty() ) 05610 { 05611 default_mat.copyTo(mat); 05612 return; 05613 } 05614 void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node); 05615 if(CV_IS_MAT_HDR_Z(obj)) 05616 { 05617 cvarrToMat(obj).copyTo(mat); 05618 cvReleaseMat((CvMat**)&obj); 05619 } 05620 else if(CV_IS_MATND_HDR(obj)) 05621 { 05622 cvarrToMat(obj).copyTo(mat); 05623 cvReleaseMatND((CvMatND **)&obj); 05624 } 05625 else 05626 { 05627 cvRelease(&obj); 05628 CV_Error(CV_StsBadArg, "Unknown array type"); 05629 } 05630 } 05631 05632 void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat ) 05633 { 05634 if( node.empty() ) 05635 { 05636 default_mat.copyTo(mat); 05637 return; 05638 } 05639 Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node)); 05640 CV_Assert(CV_IS_SPARSE_MAT(m)); 05641 m->copyToSparseMat(mat); 05642 } 05643 05644 void write(FileStorage& fs, const String& objname, const std::vector<KeyPoint>& keypoints) 05645 { 05646 cv::internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW); 05647 05648 int i, npoints = (int)keypoints.size(); 05649 for( i = 0; i < npoints; i++ ) 05650 { 05651 const KeyPoint& kpt = keypoints[i]; 05652 cv::write(fs, kpt.pt.x); 05653 cv::write(fs, kpt.pt.y); 05654 cv::write(fs, kpt.size); 05655 cv::write(fs, kpt.angle); 05656 cv::write(fs, kpt.response); 05657 cv::write(fs, kpt.octave); 05658 cv::write(fs, kpt.class_id); 05659 } 05660 } 05661 05662 05663 void read(const FileNode& node, std::vector<KeyPoint>& keypoints) 05664 { 05665 keypoints.resize(0); 05666 FileNodeIterator it = node.begin(), it_end = node.end(); 05667 for( ; it != it_end; ) 05668 { 05669 KeyPoint kpt; 05670 it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id; 05671 keypoints.push_back(kpt); 05672 } 05673 } 05674 05675 05676 void write(FileStorage& fs, const String& objname, const std::vector<DMatch>& matches) 05677 { 05678 cv::internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW); 05679 05680 int i, n = (int)matches.size(); 05681 for( i = 0; i < n; i++ ) 05682 { 05683 const DMatch& m = matches[i]; 05684 cv::write(fs, m.queryIdx); 05685 cv::write(fs, m.trainIdx); 05686 cv::write(fs, m.imgIdx); 05687 cv::write(fs, m.distance); 05688 } 05689 } 05690 05691 void read(const FileNode& node, std::vector<DMatch>& matches) 05692 { 05693 matches.resize(0); 05694 FileNodeIterator it = node.begin(), it_end = node.end(); 05695 for( ; it != it_end; ) 05696 { 05697 DMatch m; 05698 it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance; 05699 matches.push_back(m); 05700 } 05701 } 05702 05703 05704 int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); } 05705 bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; } 05706 05707 size_t FileNode::size() const 05708 { 05709 int t = type(); 05710 return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count : 05711 t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone(); 05712 } 05713 05714 void read(const FileNode& node, int& value, int default_value) 05715 { 05716 value = !node.node ? default_value : 05717 CV_NODE_IS_INT(node.node->tag) ? node.node->data.i : 05718 CV_NODE_IS_REAL(node.node->tag) ? cvRound(node.node->data.f) : 0x7fffffff; 05719 } 05720 05721 void read(const FileNode& node, float& value, float default_value) 05722 { 05723 value = !node.node ? default_value : 05724 CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i : 05725 CV_NODE_IS_REAL(node.node->tag) ? (float)node.node->data.f : 1e30f; 05726 } 05727 05728 void read(const FileNode& node, double& value, double default_value) 05729 { 05730 value = !node.node ? default_value : 05731 CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i : 05732 CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : 1e300; 05733 } 05734 05735 void read(const FileNode& node, String& value, const String& default_value) 05736 { 05737 value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String(); 05738 } 05739 05740 } 05741 05742 /* End of file. */ 05743
Generated on Tue Jul 12 2022 15:17:29 by
1.7.2
