the do / gr-peach-opencv-project

Fork of gr-peach-opencv-project by the do

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers persistence.cpp Source File

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 &quot;" );
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 &apos; or &gt;" );
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 (&apos; and &quot;)
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