/OpenCV_231/opencv2_core/persistence.cpp
C++ | 1772 lines | 1382 code | 263 blank | 127 comment | 589 complexity | 4efe372ee7d3a76ddda325464274c02e MD5 | raw file
- /*M///////////////////////////////////////////////////////////////////////////////////////
- //
- // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
- //
- // By downloading, copying, installing or using the software you agree to this license.
- // If you do not agree to this license, do not download, install,
- // copy or use the software.
- //
- //
- // License Agreement
- // For Open Source Computer Vision Library
- //
- // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
- // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
- // Third party copyrights are property of their respective owners.
- //
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the following conditions are met:
- //
- // * Redistribution's of source code must retain the above copyright notice,
- // this list of conditions and the following disclaimer.
- //
- // * Redistribution's in binary form must reproduce the above copyright notice,
- // this list of conditions and the following disclaimer in the documentation
- // and/or other materials provided with the distribution.
- //
- // * The name of the copyright holders may not be used to endorse or promote products
- // derived from this software without specific prior written permission.
- //
- // This software is provided by the copyright holders and contributors "as is" and
- // any express or implied warranties, including, but not limited to, the implied
- // warranties of merchantability and fitness for a particular purpose are disclaimed.
- // In no event shall the Intel Corporation or contributors be liable for any direct,
- // indirect, incidental, special, exemplary, or consequential damages
- // (including, but not limited to, procurement of substitute goods or services;
- // loss of use, data, or profits; or business interruption) however caused
- // and on any theory of liability, whether in contract, strict liability,
- // or tort (including negligence or otherwise) arising in any way out of
- // the use of this software, even if advised of the possibility of such damage.
- //
- //M*/
- #include "precomp.hpp"
- #include <ctype.h>
- #include <wchar.h>
- #include <zlib.h>
- /****************************************************************************************\
- * Common macros and type definitions *
- \****************************************************************************************/
- #define cv_isprint(c) ((uchar)(c) >= (uchar)' ')
- #define cv_isprint_or_tab(c) ((uchar)(c) >= (uchar)' ' || (c) == '\t')
- static inline bool cv_isalnum(char c)
- {
- return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
- }
- static inline bool cv_isalpha(char c)
- {
- return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
- }
- static inline bool cv_isdigit(char c)
- {
- return '0' <= c && c <= '9';
- }
- static inline bool cv_isspace(char c)
- {
- return (9 <= c && c <= 13) || c == ' ';
- }
- static char* icv_itoa( int _val, char* buffer, int /*radix*/ )
- {
- const int radix = 10;
- char* ptr=buffer + 23 /* enough even for 64-bit integers */;
- unsigned val = abs(_val);
- *ptr = '\0';
- do
- {
- unsigned r = val / radix;
- *--ptr = (char)(val - (r*radix) + '0');
- val = r;
- }
- while( val != 0 );
- if( _val < 0 )
- *--ptr = '-';
- return ptr;
- }
- cv::string cv::FileStorage::getDefaultObjectName(const string& _filename)
- {
- static const char* stubname = "unnamed";
- const char* filename = _filename.c_str();
- const char* ptr2 = filename + _filename.size();
- const char* ptr = ptr2 - 1;
- cv::AutoBuffer<char> name_buf(_filename.size()+1);
- while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
- {
- if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) )
- ptr2 = ptr;
- ptr--;
- }
- ptr++;
- if( ptr == ptr2 )
- CV_Error( CV_StsBadArg, "Invalid filename" );
- char* name = name_buf;
- // name must start with letter or '_'
- if( !cv_isalpha(*ptr) && *ptr!= '_' ){
- *name++ = '_';
- }
- while( ptr < ptr2 )
- {
- char c = *ptr++;
- if( !cv_isalnum(c) && c != '-' && c != '_' )
- c = '_';
- *name++ = c;
- }
- *name = '\0';
- name = name_buf;
- if( strcmp( name, "_" ) == 0 )
- strcpy( name, stubname );
- return cv::string(name);
- }
- namespace cv
- {
- #ifndef ANDROID //unsuported wcstombs on android
- string fromUtf16(const WString& str)
- {
- cv::AutoBuffer<char> _buf(str.size()*4 + 1);
- char* buf = _buf;
-
- size_t sz = wcstombs(buf, str.c_str(), str.size());
- if( sz == (size_t)-1 )
- return string();
- buf[sz] = '\0';
- return string(buf);
- }
- WString toUtf16(const string& str)
- {
- cv::AutoBuffer<wchar_t> _buf(str.size() + 1);
- wchar_t* buf = _buf;
-
- size_t sz = mbstowcs(buf, str.c_str(), str.size());
- if( sz == (size_t)-1 )
- return WString();
- buf[sz] = '\0';
- return WString(buf);
- }
- #endif
- }
- typedef struct CvGenericHash
- {
- CV_SET_FIELDS()
- int tab_size;
- void** table;
- }
- CvGenericHash;
- typedef CvGenericHash CvStringHash;
- typedef struct CvFileMapNode
- {
- CvFileNode value;
- const CvStringHashNode* key;
- struct CvFileMapNode* next;
- }
- CvFileMapNode;
- typedef struct CvXMLStackRecord
- {
- CvMemStoragePos pos;
- CvString struct_tag;
- int struct_indent;
- int struct_flags;
- }
- CvXMLStackRecord;
- #define CV_XML_OPENING_TAG 1
- #define CV_XML_CLOSING_TAG 2
- #define CV_XML_EMPTY_TAG 3
- #define CV_XML_HEADER_TAG 4
- #define CV_XML_DIRECTIVE_TAG 5
- //typedef void (*CvParse)( struct CvFileStorage* fs );
- typedef void (*CvStartWriteStruct)( struct CvFileStorage* fs, const char* key,
- int struct_flags, const char* type_name );
- typedef void (*CvEndWriteStruct)( struct CvFileStorage* fs );
- typedef void (*CvWriteInt)( struct CvFileStorage* fs, const char* key, int value );
- typedef void (*CvWriteReal)( struct CvFileStorage* fs, const char* key, double value );
- typedef void (*CvWriteString)( struct CvFileStorage* fs, const char* key,
- const char* value, int quote );
- typedef void (*CvWriteComment)( struct CvFileStorage* fs, const char* comment, int eol_comment );
- typedef void (*CvStartNextStream)( struct CvFileStorage* fs );
- typedef struct CvFileStorage
- {
- int flags;
- int is_xml;
- int write_mode;
- int is_first;
- CvMemStorage* memstorage;
- CvMemStorage* dststorage;
- CvMemStorage* strstorage;
- CvStringHash* str_hash;
- CvSeq* roots;
- CvSeq* write_stack;
- int struct_indent;
- int struct_flags;
- CvString struct_tag;
- int space;
- char* filename;
- FILE* file;
- gzFile gzfile;
- char* buffer;
- char* buffer_start;
- char* buffer_end;
- int wrap_margin;
- int lineno;
- int dummy_eof;
- const char* errmsg;
- char errmsgbuf[128];
- CvStartWriteStruct start_write_struct;
- CvEndWriteStruct end_write_struct;
- CvWriteInt write_int;
- CvWriteReal write_real;
- CvWriteString write_string;
- CvWriteComment write_comment;
- CvStartNextStream start_next_stream;
- //CvParse parse;
- }
- CvFileStorage;
- static void icvPuts( CvFileStorage* fs, const char* str )
- {
- CV_Assert( fs->file || fs->gzfile );
- if( fs->file )
- fputs( str, fs->file );
- else
- gzputs( fs->gzfile, str );
- }
- static char* icvGets( CvFileStorage* fs, char* str, int maxCount )
- {
- CV_Assert( fs->file || fs->gzfile );
- if( fs->file )
- return fgets( str, maxCount, fs->file );
- return gzgets( fs->gzfile, str, maxCount );
- }
- static int icvEof( CvFileStorage* fs )
- {
- CV_Assert( fs->file || fs->gzfile );
- if( fs->file )
- return feof(fs->file);
- return gzeof(fs->gzfile);
- }
- static void icvClose( CvFileStorage* fs )
- {
- if( fs->file )
- fclose( fs->file );
- if( fs->gzfile )
- gzclose( fs->gzfile );
- fs->file = 0;
- fs->gzfile = 0;
- }
- static void icvRewind( CvFileStorage* fs )
- {
- CV_Assert( fs->file || fs->gzfile );
- if( fs->file )
- rewind(fs->file);
- else
- gzrewind(fs->gzfile);
- }
- #define CV_YML_INDENT 3
- #define CV_XML_INDENT 2
- #define CV_YML_INDENT_FLOW 1
- #define CV_FS_MAX_LEN 4096
- #define CV_FILE_STORAGE ('Y' + ('A' << 8) + ('M' << 16) + ('L' << 24))
- #define CV_IS_FILE_STORAGE(fs) ((fs) != 0 && (fs)->flags == CV_FILE_STORAGE)
- #define CV_CHECK_FILE_STORAGE(fs) \
- { \
- if( !CV_IS_FILE_STORAGE(fs) ) \
- CV_Error( (fs) ? CV_StsBadArg : CV_StsNullPtr, \
- "Invalid pointer to file storage" ); \
- }
- #define CV_CHECK_OUTPUT_FILE_STORAGE(fs) \
- { \
- CV_CHECK_FILE_STORAGE(fs); \
- if( !fs->write_mode ) \
- CV_Error( CV_StsError, "The file storage is opened for reading" ); \
- }
- CV_IMPL const char*
- cvAttrValue( const CvAttrList* attr, const char* attr_name )
- {
- while( attr && attr->attr )
- {
- int i;
- for( i = 0; attr->attr[i*2] != 0; i++ )
- {
- if( strcmp( attr_name, attr->attr[i*2] ) == 0 )
- return attr->attr[i*2+1];
- }
- attr = attr->next;
- }
- return 0;
- }
- static CvGenericHash*
- cvCreateMap( int flags, int header_size, int elem_size,
- CvMemStorage* storage, int start_tab_size )
- {
- if( header_size < (int)sizeof(CvGenericHash) )
- CV_Error( CV_StsBadSize, "Too small map header_size" );
- if( start_tab_size <= 0 )
- start_tab_size = 16;
- CvGenericHash* map = (CvGenericHash*)cvCreateSet( flags, header_size, elem_size, storage );
- map->tab_size = start_tab_size;
- start_tab_size *= sizeof(map->table[0]);
- map->table = (void**)cvMemStorageAlloc( storage, start_tab_size );
- memset( map->table, 0, start_tab_size );
- return map;
- }
- #ifdef __GNUC__
- #define CV_PARSE_ERROR( errmsg ) \
- icvParseError( fs, __func__, (errmsg), __FILE__, __LINE__ )
- #else
- #define CV_PARSE_ERROR( errmsg ) \
- icvParseError( fs, "", (errmsg), __FILE__, __LINE__ )
- #endif
- static void
- icvParseError( CvFileStorage* fs, const char* func_name,
- const char* err_msg, const char* source_file, int source_line )
- {
- char buf[1<<10];
- sprintf( buf, "%s(%d): %s", fs->filename, fs->lineno, err_msg );
- cvError( CV_StsParseError, func_name, buf, source_file, source_line );
- }
- static void
- icvFSCreateCollection( CvFileStorage* fs, int tag, CvFileNode* collection )
- {
- if( CV_NODE_IS_MAP(tag) )
- {
- if( collection->tag != CV_NODE_NONE )
- {
- assert( fs->is_xml != 0 );
- CV_PARSE_ERROR( "Sequence element should not have name (use <_></_>)" );
- }
- collection->data.map = cvCreateMap( 0, sizeof(CvFileNodeHash),
- sizeof(CvFileMapNode), fs->memstorage, 16 );
- }
- else
- {
- CvSeq* seq;
- seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvFileNode), fs->memstorage );
- // if <collection> contains some scalar element, add it to the newly created collection
- if( CV_NODE_TYPE(collection->tag) != CV_NODE_NONE )
- cvSeqPush( seq, collection );
- collection->data.seq = seq;
- }
- collection->tag = tag;
- cvSetSeqBlockSize( collection->data.seq, 8 );
- }
- /*static void
- icvFSReleaseCollection( CvSeq* seq )
- {
- if( seq )
- {
- int is_map = CV_IS_SET(seq);
- CvSeqReader reader;
- int i, total = seq->total;
- cvStartReadSeq( seq, &reader, 0 );
- for( i = 0; i < total; i++ )
- {
- CvFileNode* node = (CvFileNode*)reader.ptr;
- if( (!is_map || CV_IS_SET_ELEM( node )) && CV_NODE_IS_COLLECTION(node->tag) )
- {
- if( CV_NODE_IS_USER(node->tag) && node->info && node->data.obj.decoded )
- cvRelease( (void**)&node->data.obj.decoded );
- if( !CV_NODE_SEQ_IS_SIMPLE( node->data.seq ))
- icvFSReleaseCollection( node->data.seq );
- }
- CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
- }
- }
- }*/
- static char*
- icvFSDoResize( CvFileStorage* fs, char* ptr, int len )
- {
- char* new_ptr = 0;
- int written_len = (int)(ptr - fs->buffer_start);
- int new_size = (int)((fs->buffer_end - fs->buffer_start)*3/2);
- new_size = MAX( written_len + len, new_size );
- new_ptr = (char*)cvAlloc( new_size + 256 );
- fs->buffer = new_ptr + (fs->buffer - fs->buffer_start);
- if( written_len > 0 )
- memcpy( new_ptr, fs->buffer_start, written_len );
- fs->buffer_start = new_ptr;
- fs->buffer_end = fs->buffer_start + new_size;
- new_ptr += written_len;
- return new_ptr;
- }
- inline char* icvFSResizeWriteBuffer( CvFileStorage* fs, char* ptr, int len )
- {
- return ptr + len < fs->buffer_end ? ptr : icvFSDoResize( fs, ptr, len );
- }
- static char*
- icvFSFlush( CvFileStorage* fs )
- {
- char* ptr = fs->buffer;
- int indent;
- if( ptr > fs->buffer_start + fs->space )
- {
- ptr[0] = '\n';
- ptr[1] = '\0';
- icvPuts( fs, fs->buffer_start );
- fs->buffer = fs->buffer_start;
- }
- indent = fs->struct_indent;
- if( fs->space != indent )
- {
- if( fs->space < indent )
- memset( fs->buffer_start + fs->space, ' ', indent - fs->space );
- fs->space = indent;
- }
- ptr = fs->buffer = fs->buffer_start + fs->space;
- return ptr;
- }
- /* closes file storage and deallocates buffers */
- CV_IMPL void
- cvReleaseFileStorage( CvFileStorage** p_fs )
- {
- if( !p_fs )
- CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" );
- if( *p_fs )
- {
- CvFileStorage* fs = *p_fs;
- *p_fs = 0;
- if( fs->write_mode && (fs->file || fs->gzfile) )
- {
- if( fs->write_stack )
- {
- while( fs->write_stack->total > 0 )
- cvEndWriteStruct(fs);
- }
- icvFSFlush(fs);
- if( fs->is_xml )
- icvPuts( fs, "</opencv_storage>\n" );
- }
- //icvFSReleaseCollection( fs->roots ); // delete all the user types recursively
- icvClose(fs);
- cvReleaseMemStorage( &fs->strstorage );
- cvFree( &fs->buffer_start );
- cvReleaseMemStorage( &fs->memstorage );
- memset( fs, 0, sizeof(*fs) );
- cvFree( &fs );
- }
- }
- #define CV_HASHVAL_SCALE 33
- CV_IMPL CvStringHashNode*
- cvGetHashedKey( CvFileStorage* fs, const char* str, int len, int create_missing )
- {
- CvStringHashNode* node = 0;
- unsigned hashval = 0;
- int i, tab_size;
- CvStringHash* map = fs->str_hash;
- if( !fs )
- return 0;
- if( len < 0 )
- {
- for( i = 0; str[i] != '\0'; i++ )
- hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
- len = i;
- }
- else for( i = 0; i < len; i++ )
- hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
- hashval &= INT_MAX;
- tab_size = map->tab_size;
- if( (tab_size & (tab_size - 1)) == 0 )
- i = (int)(hashval & (tab_size - 1));
- else
- i = (int)(hashval % tab_size);
- for( node = (CvStringHashNode*)(map->table[i]); node != 0; node = node->next )
- {
- if( node->hashval == hashval &&
- node->str.len == len &&
- memcmp( node->str.ptr, str, len ) == 0 )
- break;
- }
- if( !node && create_missing )
- {
- node = (CvStringHashNode*)cvSetNew( (CvSet*)map );
- node->hashval = hashval;
- node->str = cvMemStorageAllocString( map->storage, str, len );
- node->next = (CvStringHashNode*)(map->table[i]);
- map->table[i] = node;
- }
- return node;
- }
- CV_IMPL CvFileNode*
- cvGetFileNode( CvFileStorage* fs, CvFileNode* _map_node,
- const CvStringHashNode* key,
- int create_missing )
- {
- CvFileNode* value = 0;
- int k = 0, attempts = 1;
- if( !fs )
- return 0;
- CV_CHECK_FILE_STORAGE(fs);
- if( !key )
- CV_Error( CV_StsNullPtr, "Null key element" );
- if( _map_node )
- {
- if( !fs->roots )
- return 0;
- attempts = fs->roots->total;
- }
- for( k = 0; k < attempts; k++ )
- {
- int i, tab_size;
- CvFileNode* map_node = _map_node;
- CvFileMapNode* another;
- CvFileNodeHash* map;
- if( !map_node )
- map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
- if( !CV_NODE_IS_MAP(map_node->tag) )
- {
- if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
- CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
- CV_Error( CV_StsError, "The node is neither a map nor an empty collection" );
- return 0;
- }
- map = map_node->data.map;
- tab_size = map->tab_size;
- if( (tab_size & (tab_size - 1)) == 0 )
- i = (int)(key->hashval & (tab_size - 1));
- else
- i = (int)(key->hashval % tab_size);
- for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
- if( another->key == key )
- {
- if( !create_missing )
- {
- value = &another->value;
- return value;
- }
- CV_PARSE_ERROR( "Duplicated key" );
- }
- if( k == attempts - 1 && create_missing )
- {
- CvFileMapNode* node = (CvFileMapNode*)cvSetNew( (CvSet*)map );
- node->key = key;
- node->next = (CvFileMapNode*)(map->table[i]);
- map->table[i] = node;
- value = (CvFileNode*)node;
- }
- }
- return value;
- }
- CV_IMPL CvFileNode*
- cvGetFileNodeByName( const CvFileStorage* fs, const CvFileNode* _map_node, const char* str )
- {
- CvFileNode* value = 0;
- int i, len, tab_size;
- unsigned hashval = 0;
- int k = 0, attempts = 1;
- if( !fs )
- return 0;
- CV_CHECK_FILE_STORAGE(fs);
- if( !str )
- CV_Error( CV_StsNullPtr, "Null element name" );
- for( i = 0; str[i] != '\0'; i++ )
- hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
- hashval &= INT_MAX;
- len = i;
- if( !_map_node )
- {
- if( !fs->roots )
- return 0;
- attempts = fs->roots->total;
- }
- for( k = 0; k < attempts; k++ )
- {
- CvFileNodeHash* map;
- const CvFileNode* map_node = _map_node;
- CvFileMapNode* another;
- if( !map_node )
- map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
- if( !CV_NODE_IS_MAP(map_node->tag) )
- {
- if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
- CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
- CV_Error( CV_StsError, "The node is neither a map nor an empty collection" );
- return 0;
- }
- map = map_node->data.map;
- tab_size = map->tab_size;
- if( (tab_size & (tab_size - 1)) == 0 )
- i = (int)(hashval & (tab_size - 1));
- else
- i = (int)(hashval % tab_size);
- for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
- {
- const CvStringHashNode* key = another->key;
- if( key->hashval == hashval &&
- key->str.len == len &&
- memcmp( key->str.ptr, str, len ) == 0 )
- {
- value = &another->value;
- return value;
- }
- }
- }
- return value;
- }
- CV_IMPL CvFileNode*
- cvGetRootFileNode( const CvFileStorage* fs, int stream_index )
- {
- CV_CHECK_FILE_STORAGE(fs);
- if( !fs->roots || (unsigned)stream_index >= (unsigned)fs->roots->total )
- return 0;
- return (CvFileNode*)cvGetSeqElem( fs->roots, stream_index );
- }
- /* returns the sequence element by its index */
- /*CV_IMPL CvFileNode*
- cvGetFileNodeFromSeq( CvFileStorage* fs,
- CvFileNode* seq_node, int index )
- {
- CvFileNode* value = 0;
- CvSeq* seq;
- if( !seq_node )
- seq = fs->roots;
- else if( !CV_NODE_IS_SEQ(seq_node->tag) )
- {
- if( CV_NODE_IS_MAP(seq_node->tag) )
- CV_Error( CV_StsError, "The node is map. Use cvGetFileNodeFromMap()." );
- if( CV_NODE_TYPE(seq_node->tag) == CV_NODE_NONE )
- CV_Error( CV_StsError, "The node is an empty object (None)." );
- if( index != 0 && index != -1 )
- CV_Error( CV_StsOutOfRange, "" );
- value = seq_node;
- EXIT;
- }
- else
- seq = seq_node->data.seq;
- if( !seq )
- CV_Error( CV_StsNullPtr, "The file storage is empty" );
- value = (CvFileNode*)cvGetSeqElem( seq, index, 0 );
-
- return value;
- }*/
- static char*
- icvDoubleToString( char* buf, double value )
- {
- Cv64suf val;
- unsigned ieee754_hi;
- val.f = value;
- ieee754_hi = (unsigned)(val.u >> 32);
- if( (ieee754_hi & 0x7ff00000) != 0x7ff00000 )
- {
- int ivalue = cvRound(value);
- if( ivalue == value )
- sprintf( buf, "%d.", ivalue );
- else
- {
- static const char* fmt = "%.16e";
- char* ptr = buf;
- sprintf( buf, fmt, value );
- if( *ptr == '+' || *ptr == '-' )
- ptr++;
- for( ; cv_isdigit(*ptr); ptr++ )
- ;
- if( *ptr == ',' )
- *ptr = '.';
- }
- }
- else
- {
- unsigned ieee754_lo = (unsigned)val.u;
- if( (ieee754_hi & 0x7fffffff) + (ieee754_lo != 0) > 0x7ff00000 )
- strcpy( buf, ".Nan" );
- else
- strcpy( buf, (int)ieee754_hi < 0 ? "-.Inf" : ".Inf" );
- }
- return buf;
- }
- static char*
- icvFloatToString( char* buf, float value )
- {
- Cv32suf val;
- unsigned ieee754;
- val.f = value;
- ieee754 = val.u;
- if( (ieee754 & 0x7f800000) != 0x7f800000 )
- {
- int ivalue = cvRound(value);
- if( ivalue == value )
- sprintf( buf, "%d.", ivalue );
- else
- {
- static const char* fmt = "%.8e";
- char* ptr = buf;
- sprintf( buf, fmt, value );
- if( *ptr == '+' || *ptr == '-' )
- ptr++;
- for( ; cv_isdigit(*ptr); ptr++ )
- ;
- if( *ptr == ',' )
- *ptr = '.';
- }
- }
- else
- {
- if( (ieee754 & 0x7fffffff) != 0x7f800000 )
- strcpy( buf, ".Nan" );
- else
- strcpy( buf, (int)ieee754 < 0 ? "-.Inf" : ".Inf" );
- }
- return buf;
- }
- static void
- icvProcessSpecialDouble( CvFileStorage* fs, char* buf, double* value, char** endptr )
- {
- char c = buf[0];
- int inf_hi = 0x7ff00000;
- if( c == '-' || c == '+' )
- {
- inf_hi = c == '-' ? 0xfff00000 : 0x7ff00000;
- c = *++buf;
- }
- if( c != '.' )
- CV_PARSE_ERROR( "Bad format of floating-point constant" );
- if( toupper(buf[1]) == 'I' && toupper(buf[2]) == 'N' && toupper(buf[3]) == 'F' )
- *(uint64*)value = ((uint64)inf_hi << 32);
- else if( toupper(buf[1]) == 'N' && toupper(buf[2]) == 'A' && toupper(buf[3]) == 'N' )
- *(uint64*)value = (uint64)-1;
- else
- CV_PARSE_ERROR( "Bad format of floating-point constant" );
- *endptr = buf + 4;
- }
- static double icv_strtod( CvFileStorage* fs, char* ptr, char** endptr )
- {
- double fval = strtod( ptr, endptr );
- if( **endptr == '.' )
- {
- char* dot_pos = *endptr;
- *dot_pos = ',';
- double fval2 = strtod( ptr, endptr );
- *dot_pos = '.';
- if( *endptr > dot_pos )
- fval = fval2;
- else
- *endptr = dot_pos;
- }
- if( *endptr == ptr || cv_isalpha(**endptr) )
- icvProcessSpecialDouble( fs, ptr, &fval, endptr );
- return fval;
- }
- /****************************************************************************************\
- * YAML Parser *
- \****************************************************************************************/
- static char*
- icvYMLSkipSpaces( CvFileStorage* fs, char* ptr, int min_indent, int max_comment_indent )
- {
- for(;;)
- {
- while( *ptr == ' ' )
- ptr++;
- if( *ptr == '#' )
- {
- if( ptr - fs->buffer_start > max_comment_indent )
- return ptr;
- *ptr = '\0';
- }
- else if( cv_isprint(*ptr) )
- {
- if( ptr - fs->buffer_start < min_indent )
- CV_PARSE_ERROR( "Incorrect indentation" );
- break;
- }
- else if( *ptr == '\0' || *ptr == '\n' || *ptr == '\r' )
- {
- int max_size = (int)(fs->buffer_end - fs->buffer_start);
- ptr = icvGets( fs, fs->buffer_start, max_size );
- if( !ptr )
- {
- // emulate end of stream
- ptr = fs->buffer_start;
- ptr[0] = ptr[1] = ptr[2] = '.';
- ptr[3] = '\0';
- fs->dummy_eof = 1;
- break;
- }
- else
- {
- int l = (int)strlen(ptr);
- if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) )
- CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
- }
- fs->lineno++;
- }
- else
- CV_PARSE_ERROR( *ptr == '\t' ? "Tabs are prohibited in YAML!" : "Invalid character" );
- }
- return ptr;
- }
- static char*
- icvYMLParseKey( CvFileStorage* fs, char* ptr,
- CvFileNode* map_node, CvFileNode** value_placeholder )
- {
- char c;
- char *endptr = ptr - 1, *saveptr;
- CvStringHashNode* str_hash_node;
- if( *ptr == '-' )
- CV_PARSE_ERROR( "Key may not start with \'-\'" );
- do c = *++endptr;
- while( cv_isprint(c) && c != ':' );
- if( c != ':' )
- CV_PARSE_ERROR( "Missing \':\'" );
- saveptr = endptr + 1;
- do c = *--endptr;
- while( c == ' ' );
- ++endptr;
- if( endptr == ptr )
- CV_PARSE_ERROR( "An empty key" );
- str_hash_node = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 );
- *value_placeholder = cvGetFileNode( fs, map_node, str_hash_node, 1 );
- ptr = saveptr;
- return ptr;
- }
- static char*
- icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
- int parent_flags, int min_indent )
- {
- char buf[CV_FS_MAX_LEN + 1024];
- char* endptr = 0;
- char c = ptr[0], d = ptr[1];
- int is_parent_flow = CV_NODE_IS_FLOW(parent_flags);
- int value_type = CV_NODE_NONE;
- int len;
- memset( node, 0, sizeof(*node) );
- if( c == '!' ) // handle explicit type specification
- {
- if( d == '!' || d == '^' )
- {
- ptr++;
- value_type |= CV_NODE_USER;
- }
- endptr = ptr++;
- do d = *++endptr;
- while( cv_isprint(d) && d != ' ' );
- len = (int)(endptr - ptr);
- if( len == 0 )
- CV_PARSE_ERROR( "Empty type name" );
- d = *endptr;
- *endptr = '\0';
- if( len == 3 && !CV_NODE_IS_USER(value_type) )
- {
- if( memcmp( ptr, "str", 3 ) == 0 )
- value_type = CV_NODE_STRING;
- else if( memcmp( ptr, "int", 3 ) == 0 )
- value_type = CV_NODE_INT;
- else if( memcmp( ptr, "seq", 3 ) == 0 )
- value_type = CV_NODE_SEQ;
- else if( memcmp( ptr, "map", 3 ) == 0 )
- value_type = CV_NODE_MAP;
- }
- else if( len == 5 && !CV_NODE_IS_USER(value_type) )
- {
- if( memcmp( ptr, "float", 5 ) == 0 )
- value_type = CV_NODE_REAL;
- }
- else if( CV_NODE_IS_USER(value_type) )
- {
- node->info = cvFindType( ptr );
- if( !node->info )
- node->tag &= ~CV_NODE_USER;
- }
- *endptr = d;
- ptr = icvYMLSkipSpaces( fs, endptr, min_indent, INT_MAX );
- c = *ptr;
- if( !CV_NODE_IS_USER(value_type) )
- {
- if( value_type == CV_NODE_STRING && c != '\'' && c != '\"' )
- goto force_string;
- if( value_type == CV_NODE_INT )
- goto force_int;
- if( value_type == CV_NODE_REAL )
- goto force_real;
- }
- }
- if( cv_isdigit(c) ||
- ((c == '-' || c == '+') && (cv_isdigit(d) || d == '.')) ||
- (c == '.' && cv_isalnum(d))) // a number
- {
- double fval;
- int ival;
- endptr = ptr + (c == '-' || c == '+');
- while( cv_isdigit(*endptr) )
- endptr++;
- if( *endptr == '.' || *endptr == 'e' )
- {
- force_real:
- fval = icv_strtod( fs, ptr, &endptr );
- /*if( endptr == ptr || cv_isalpha(*endptr) )
- icvProcessSpecialDouble( fs, endptr, &fval, &endptr ));*/
- node->tag = CV_NODE_REAL;
- node->data.f = fval;
- }
- else
- {
- force_int:
- ival = (int)strtol( ptr, &endptr, 0 );
- node->tag = CV_NODE_INT;
- node->data.i = ival;
- }
- if( !endptr || endptr == ptr )
- CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
- ptr = endptr;
- }
- else if( c == '\'' || c == '\"' ) // an explicit string
- {
- node->tag = CV_NODE_STRING;
- if( c == '\'' )
- for( len = 0; len < CV_FS_MAX_LEN; )
- {
- c = *++ptr;
- if( cv_isalnum(c) || (c != '\'' && cv_isprint(c)))
- buf[len++] = c;
- else if( c == '\'' )
- {
- c = *++ptr;
- if( c != '\'' )
- break;
- buf[len++] = c;
- }
- else
- CV_PARSE_ERROR( "Invalid character" );
- }
- else
- for( len = 0; len < CV_FS_MAX_LEN; )
- {
- c = *++ptr;
- if( cv_isalnum(c) || (c != '\\' && c != '\"' && cv_isprint(c)))
- buf[len++] = c;
- else if( c == '\"' )
- {
- ++ptr;
- break;
- }
- else if( c == '\\' )
- {
- d = *++ptr;
- if( d == '\'' )
- buf[len++] = d;
- else if( d == '\"' || d == '\\' || d == '\'' )
- buf[len++] = d;
- else if( d == 'n' )
- buf[len++] = '\n';
- else if( d == 'r' )
- buf[len++] = '\r';
- else if( d == 't' )
- buf[len++] = '\t';
- else if( d == 'x' || (cv_isdigit(d) && d < '8') )
- {
- int val, is_hex = d == 'x';
- c = ptr[3];
- ptr[3] = '\0';
- val = strtol( ptr + is_hex, &endptr, is_hex ? 8 : 16 );
- ptr[3] = c;
- if( endptr == ptr + is_hex )
- buf[len++] = 'x';
- else
- {
- buf[len++] = (char)val;
- ptr = endptr;
- }
- }
- }
- else
- CV_PARSE_ERROR( "Invalid character" );
- }
- if( len >= CV_FS_MAX_LEN )
- CV_PARSE_ERROR( "Too long string literal" );
- node->data.str = cvMemStorageAllocString( fs->memstorage, buf, len );
- }
- else if( c == '[' || c == '{' ) // collection as a flow
- {
- int new_min_indent = min_indent + !is_parent_flow;
- int struct_flags = CV_NODE_FLOW + (c == '{' ? CV_NODE_MAP : CV_NODE_SEQ);
- int is_simple = 1;
- icvFSCreateCollection( fs, CV_NODE_TYPE(struct_flags) +
- (node->info ? CV_NODE_USER : 0), node );
- d = c == '[' ? ']' : '}';
- for( ++ptr ;;)
- {
- CvFileNode* elem = 0;
- ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX );
- if( *ptr == '}' || *ptr == ']' )
- {
- if( *ptr != d )
- CV_PARSE_ERROR( "The wrong closing bracket" );
- ptr++;
- break;
- }
- if( node->data.seq->total != 0 )
- {
- if( *ptr != ',' )
- CV_PARSE_ERROR( "Missing , between the elements" );
- ptr = icvYMLSkipSpaces( fs, ptr + 1, new_min_indent, INT_MAX );
- }
- if( CV_NODE_IS_MAP(struct_flags) )
- {
- ptr = icvYMLParseKey( fs, ptr, node, &elem );
- ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX );
- }
- else
- {
- if( *ptr == ']' )
- break;
- elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
- }
- ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, new_min_indent );
- if( CV_NODE_IS_MAP(struct_flags) )
- elem->tag |= CV_NODE_NAMED;
- is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
- }
- node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
- }
- else
- {
- int indent, struct_flags, is_simple;
- if( is_parent_flow || c != '-' )
- {
- // implicit (one-line) string or nested block-style collection
- if( !is_parent_flow )
- {
- if( c == '?' )
- CV_PARSE_ERROR( "Complex keys are not supported" );
- if( c == '|' || c == '>' )
- CV_PARSE_ERROR( "Multi-line text literals are not supported" );
- }
- force_string:
- endptr = ptr - 1;
- do c = *++endptr;
- while( cv_isprint(c) &&
- (!is_parent_flow || (c != ',' && c != '}' && c != ']')) &&
- (is_parent_flow || c != ':' || value_type == CV_NODE_STRING));
- if( endptr == ptr )
- CV_PARSE_ERROR( "Invalid character" );
- if( is_parent_flow || c != ':' )
- {
- char* str_end = endptr;
- node->tag = CV_NODE_STRING;
- // strip spaces in the end of string
- do c = *--str_end;
- while( str_end > ptr && c == ' ' );
- str_end++;
- node->data.str = cvMemStorageAllocString( fs->memstorage, ptr, (int)(str_end - ptr) );
- ptr = endptr;
- return ptr;
- }
- struct_flags = CV_NODE_MAP;
- }
- else
- struct_flags = CV_NODE_SEQ;
- icvFSCreateCollection( fs, struct_flags +
- (node->info ? CV_NODE_USER : 0), node );
- indent = (int)(ptr - fs->buffer_start);
- is_simple = 1;
- for(;;)
- {
- CvFileNode* elem = 0;
- if( CV_NODE_IS_MAP(struct_flags) )
- {
- ptr = icvYMLParseKey( fs, ptr, node, &elem );
- }
- else
- {
- c = *ptr++;
- if( c != '-' )
- CV_PARSE_ERROR( "Block sequence elements must be preceded with \'-\'" );
- elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
- }
- ptr = icvYMLSkipSpaces( fs, ptr, indent + 1, INT_MAX );
- ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, indent + 1 );
- if( CV_NODE_IS_MAP(struct_flags) )
- elem->tag |= CV_NODE_NAMED;
- is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
- ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
- if( ptr - fs->buffer_start != indent )
- {
- if( ptr - fs->buffer_start < indent )
- break;
- else
- CV_PARSE_ERROR( "Incorrect indentation" );
- }
- if( memcmp( ptr, "...", 3 ) == 0 )
- break;
- }
- node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
- }
- return ptr;
- }
- static void
- icvYMLParse( CvFileStorage* fs )
- {
- char* ptr = fs->buffer_start;
- int is_first = 1;
- for(;;)
- {
- // 0. skip leading comments and directives and ...
- // 1. reach the first item
- for(;;)
- {
- ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
- if( !ptr )
- return;
- if( *ptr == '%' )
- {
- if( memcmp( ptr, "%YAML:", 6 ) == 0 &&
- memcmp( ptr, "%YAML:1.", 8 ) != 0 )
- CV_PARSE_ERROR( "Unsupported YAML version (it must be 1.x)" );
- *ptr = '\0';
- }
- else if( *ptr == '-' )
- {
- if( memcmp(ptr, "---", 3) == 0 )
- {
- ptr += 3;
- break;
- }
- else if( is_first )
- break;
- }
- else if( cv_isalnum(*ptr) || *ptr=='_')
- {
- if( !is_first )
- CV_PARSE_ERROR( "The YAML streams must start with '---', except the first one" );
- break;
- }
- else if( fs->dummy_eof )
- break;
- else
- CV_PARSE_ERROR( "Invalid or unsupported syntax" );
- }
- ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
- if( memcmp( ptr, "...", 3 ) != 0 )
- {
- // 2. parse the collection
- CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
- ptr = icvYMLParseValue( fs, ptr, root_node, CV_NODE_NONE, 0 );
- if( !CV_NODE_IS_COLLECTION(root_node->tag) )
- CV_PARSE_ERROR( "Only collections as YAML streams are supported by this parser" );
- // 3. parse until the end of file or next collection
- ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
- if( !ptr )
- return;
- }
- if( fs->dummy_eof )
- break;
- ptr += 3;
- is_first = 0;
- }
- }
- /****************************************************************************************\
- * YAML Emitter *
- \****************************************************************************************/
- static void
- icvYMLWrite( CvFileStorage* fs, const char* key, const char* data )
- {
- int i, keylen = 0;
- int datalen = 0;
- int struct_flags;
- char* ptr;
- struct_flags = fs->struct_flags;
- if( key && key[0] == '\0' )
- key = 0;
- if( CV_NODE_IS_COLLECTION(struct_flags) )
- {
- if( (CV_NODE_IS_MAP(struct_flags) ^ (key != 0)) )
- CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
- "or add element with key to sequence" );
- }
- else
- {
- fs->is_first = 0;
- struct_flags = CV_NODE_EMPTY | (key ? CV_NODE_MAP : CV_NODE_SEQ);
- }
- if( key )
- {
- keylen = (int)strlen(key);
- if( keylen == 0 )
- CV_Error( CV_StsBadArg, "The key is an empty" );
- if( keylen > CV_FS_MAX_LEN )
- CV_Error( CV_StsBadArg, "The key is too long" );
- }
- if( data )
- datalen = (int)strlen(data);
- if( CV_NODE_IS_FLOW(struct_flags) )
- {
- int new_offset;
- ptr = fs->buffer;
- if( !CV_NODE_IS_EMPTY(struct_flags) )
- *ptr++ = ',';
- new_offset = (int)(ptr - fs->buffer_start) + keylen + datalen;
- if( new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10 )
- {
- fs->buffer = ptr;
- ptr = icvFSFlush(fs);
- }
- else
- *ptr++ = ' ';
- }
- else
- {
- ptr = icvFSFlush(fs);
- if( !CV_NODE_IS_MAP(struct_flags) )
- {
- *ptr++ = '-';
- if( data )
- *ptr++ = ' ';
- }
- }
- if( key )
- {
- if( !cv_isalpha(key[0]) && key[0] != '_' )
- CV_Error( CV_StsBadArg, "Key must start with a letter or _" );
- ptr = icvFSResizeWriteBuffer( fs, ptr, keylen );
- for( i = 0; i < keylen; i++ )
- {
- char c = key[i];
- ptr[i] = c;
- if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
- CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
- }
- ptr += keylen;
- *ptr++ = ':';
- if( !CV_NODE_IS_FLOW(struct_flags) && data )
- *ptr++ = ' ';
- }
- if( data )
- {
- ptr = icvFSResizeWriteBuffer( fs, ptr, datalen );
- memcpy( ptr, data, datalen );
- ptr += datalen;
- }
- fs->buffer = ptr;
- fs->struct_flags = struct_flags & ~CV_NODE_EMPTY;
- }
- static void
- icvYMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
- const char* type_name CV_DEFAULT(0))
- {
- int parent_flags;
- char buf[CV_FS_MAX_LEN + 1024];
- const char* data = 0;
- struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
- if( !CV_NODE_IS_COLLECTION(struct_flags))
- CV_Error( CV_StsBadArg,
- "Some collection type - CV_NODE_SEQ or CV_NODE_MAP, must be specified" );
- if( CV_NODE_IS_FLOW(struct_flags) )
- {
- char c = CV_NODE_IS_MAP(struct_flags) ? '{' : '[';
- struct_flags |= CV_NODE_FLOW;
- if( type_name )
- sprintf( buf, "!!%s %c", type_name, c );
- else
- {
- buf[0] = c;
- buf[1] = '\0';
- }
- data = buf;
- }
- else if( type_name )
- {
- sprintf( buf, "!!%s", type_name );
- data = buf;
- }
- icvYMLWrite( fs, key, data );
- parent_flags = fs->struct_flags;
- cvSeqPush( fs->write_stack, &parent_flags );
- fs->struct_flags = struct_flags;
- if( !CV_NODE_IS_FLOW(parent_flags) )
- fs->struct_indent += CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags);
- }
- static void
- icvYMLEndWriteStruct( CvFileStorage* fs )
- {
- int parent_flags = 0, struct_flags;
- char* ptr;
- struct_flags = fs->struct_flags;
- if( fs->write_stack->total == 0 )
- CV_Error( CV_StsError, "EndWriteStruct w/o matching StartWriteStruct" );
- cvSeqPop( fs->write_stack, &parent_flags );
- if( CV_NODE_IS_FLOW(struct_flags) )
- {
- ptr = fs->buffer;
- if( ptr > fs->buffer_start + fs->struct_indent && !CV_NODE_IS_EMPTY(struct_flags) )
- *ptr++ = ' ';
- *ptr++ = CV_NODE_IS_MAP(struct_flags) ? '}' : ']';
- fs->buffer = ptr;
- }
- else if( CV_NODE_IS_EMPTY(struct_flags) )
- {
- ptr = icvFSFlush(fs);
- memcpy( ptr, CV_NODE_IS_MAP(struct_flags) ? "{}" : "[]", 2 );
- fs->buffer = ptr + 2;
- }
- if( !CV_NODE_IS_FLOW(parent_flags) )
- fs->struct_indent -= CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags);
- assert( fs->struct_indent >= 0 );
- fs->struct_flags = parent_flags;
- }
- static void
- icvYMLStartNextStream( CvFileStorage* fs )
- {
- if( !fs->is_first )
- {
- while( fs->write_stack->total > 0 )
- icvYMLEndWriteStruct(fs);
- fs->struct_indent = 0;
- icvFSFlush(fs);
- icvPuts( fs, "...\n" );
- icvPuts( fs, "---\n" );
- fs->buffer = fs->buffer_start;
- }
- }
- static void
- icvYMLWriteInt( CvFileStorage* fs, const char* key, int value )
- {
- char buf[128];
- icvYMLWrite( fs, key, icv_itoa( value, buf, 10 ));
- }
- static void
- icvYMLWriteReal( CvFileStorage* fs, const char* key, double value )
- {
- char buf[128];
- icvYMLWrite( fs, key, icvDoubleToString( buf, value ));
- }
- static void
- icvYMLWriteString( CvFileStorage* fs, const char* key,
- const char* str, int quote CV_DEFAULT(0))
- {
- char buf[CV_FS_MAX_LEN*4+16];
- char* data = (char*)str;
- int i, len;
- if( !str )
- CV_Error( CV_StsNullPtr, "Null string pointer" );
- len = (int)strlen(str);
- if( len > CV_FS_MAX_LEN )
- CV_Error( CV_StsBadArg, "The written string is too long" );
- if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
- {
- int need_quote = quote || len == 0;
- data = buf;
- *data++ = '\"';
- for( i = 0; i < len; i++ )
- {
- char c = str[i];
- if( !need_quote && !cv_isalnum(c) && c != '_' && c != ' ' && c != '-' &&
- c != '(' && c != ')' && c != '/' && c != '+' && c != ';' )
- need_quote = 1;
- if( !cv_isalnum(c) && (!cv_isprint(c) || c == '\\' || c == '\'' || c == '\"') )
- {
- *data++ = '\\';
- if( cv_isprint(c) )
- *data++ = c;
- else if( c == '\n' )
- *data++ = 'n';
- else if( c == '\r' )
- *data++ = 'r';
- else if( c == '\t' )
- *data++ = 't';
- else
- {
- sprintf( data, "x%02x", c );
- data += 3;
- }
- }
- else
- *data++ = c;
- }
- if( !need_quote && (cv_isdigit(str[0]) ||
- str[0] == '+' || str[0] == '-' || str[0] == '.' ))
- need_quote = 1;
- if( need_quote )
- *data++ = '\"';
- *data++ = '\0';
- data = buf + !need_quote;
- }
- icvYMLWrite( fs, key, data );
- }
- static void
- icvYMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
- {
- int len; //, indent;
- int multiline;
- const char* eol;
- char* ptr;
- if( !comment )
- CV_Error( CV_StsNullPtr, "Null comment" );
- len = (int)strlen(comment);
- eol = strchr(comment, '\n');
- multiline = eol != 0;
- ptr = fs->buffer;
- if( !eol_comment || multiline ||
- fs->buffer_end - ptr < len || ptr == fs->buffer_start )
- ptr = icvFSFlush( fs );
- else
- *ptr++ = ' ';
- while( comment )
- {
- *ptr++ = '#';
- *ptr++ = ' ';
- if( eol )
- {
- ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 );
- memcpy( ptr, comment, eol - comment + 1 );
- fs->buffer = ptr + (eol - comment);
- comment = eol + 1;
- eol = strchr( comment, '\n' );
- }
- else
- {
- len = (int)strlen(comment);
- ptr = icvFSResizeWriteBuffer( fs, ptr, len );
- memcpy( ptr, comment, len );
- fs->buffer = ptr + len;
- comment = 0;
- }
- ptr = icvFSFlush( fs );
- }
- }
- /****************************************************************************************\
- * XML Parser *
- \****************************************************************************************/
- #define CV_XML_INSIDE_COMMENT 1
- #define CV_XML_INSIDE_TAG 2
- #define CV_XML_INSIDE_DIRECTIVE 3
- static char*
- icvXMLSkipSpaces( CvFileStorage* fs, char* ptr, int mode )
- {
- int level = 0;
- for(;;)
- {
- char c;
- ptr--;
- if( mode == CV_XML_INSIDE_COMMENT )
- {
- do c = *++ptr;
- while( cv_isprint_or_tab(c) && (c != '-' || ptr[1] != '-' || ptr[2] != '>') );
- if( c == '-' )
- {
- assert( ptr[1] == '-' && ptr[2] == '>' );
- mode = 0;
- ptr += 3;
- }
- }
- else if( mode == CV_XML_INSIDE_DIRECTIVE )
- {
- // !!!NOTE!!! This is not quite correct, but should work in most cases
- do
- {
- c = *++ptr;
- level += c == '<';
- level -= c == '>';
- if( level < 0 )
- return ptr;
- } while( cv_isprint_or_tab(c) );
- }
- else
- {
- do c = *++ptr;
- while( c == ' ' || c == '\t' );
- if( c == '<' && ptr[1] == '!' && ptr[2] == '-' && ptr[3] == '-' )
- {
- if( mode != 0 )
- CV_PARSE_ERROR( "Comments are not allowed here" );
- mode = CV_XML_INSIDE_COMMENT;
- ptr += 4;
- }
- else if( cv_isprint(c) )
- break;
- }
- if( !cv_isprint(*ptr) )
- {
- int max_size = (int)(fs->buffer_end - fs->buffer_start);
- if( *ptr != '\0' && *ptr != '\n' && *ptr != '\r' )
- CV_PARSE_ERROR( "Invalid character in the stream" );
- ptr = icvGets( fs, fs->buffer_start, max_size );
- if( !ptr )
- {
- ptr = fs->buffer_start;
- *ptr = '\0';
- fs->dummy_eof = 1;
- break;
- }
- else
- {
- int l = (int)strlen(ptr);
- if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) )
- CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
- }
- fs->lineno++;
- }
- }
- return ptr;
- }
- static char*
- icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
- CvAttrList** _list, int* _tag_type );
- static char*
- icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
- int value_type CV_DEFAULT(CV_NODE_NONE))
- {
- CvFileNode *elem = node;
- int have_space = 1, is_simple = 1;
- int is_user_type = CV_NODE_IS_USER(value_type);
- memset( node, 0, sizeof(*node) );
- value_type