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