PageRenderTime 131ms CodeModel.GetById 44ms RepoModel.GetById 2ms app.codeStats 1ms

/OpenCV_231/opencv2_core/persistence.cpp

https://github.com/Jorgepaiz/OpenCV_Library
C++ | 1772 lines | 1382 code | 263 blank | 127 comment | 589 complexity | 4efe372ee7d3a76ddda325464274c02e MD5 | raw file
  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. #include "precomp.hpp"
  43. #include <ctype.h>
  44. #include <wchar.h>
  45. #include <zlib.h>
  46. /****************************************************************************************\
  47. * Common macros and type definitions *
  48. \****************************************************************************************/
  49. #define cv_isprint(c) ((uchar)(c) >= (uchar)' ')
  50. #define cv_isprint_or_tab(c) ((uchar)(c) >= (uchar)' ' || (c) == '\t')
  51. static inline bool cv_isalnum(char c)
  52. {
  53. return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
  54. }
  55. static inline bool cv_isalpha(char c)
  56. {
  57. return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
  58. }
  59. static inline bool cv_isdigit(char c)
  60. {
  61. return '0' <= c && c <= '9';
  62. }
  63. static inline bool cv_isspace(char c)
  64. {
  65. return (9 <= c && c <= 13) || c == ' ';
  66. }
  67. static char* icv_itoa( int _val, char* buffer, int /*radix*/ )
  68. {
  69. const int radix = 10;
  70. char* ptr=buffer + 23 /* enough even for 64-bit integers */;
  71. unsigned val = abs(_val);
  72. *ptr = '\0';
  73. do
  74. {
  75. unsigned r = val / radix;
  76. *--ptr = (char)(val - (r*radix) + '0');
  77. val = r;
  78. }
  79. while( val != 0 );
  80. if( _val < 0 )
  81. *--ptr = '-';
  82. return ptr;
  83. }
  84. cv::string cv::FileStorage::getDefaultObjectName(const string& _filename)
  85. {
  86. static const char* stubname = "unnamed";
  87. const char* filename = _filename.c_str();
  88. const char* ptr2 = filename + _filename.size();
  89. const char* ptr = ptr2 - 1;
  90. cv::AutoBuffer<char> name_buf(_filename.size()+1);
  91. while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
  92. {
  93. if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) )
  94. ptr2 = ptr;
  95. ptr--;
  96. }
  97. ptr++;
  98. if( ptr == ptr2 )
  99. CV_Error( CV_StsBadArg, "Invalid filename" );
  100. char* name = name_buf;
  101. // name must start with letter or '_'
  102. if( !cv_isalpha(*ptr) && *ptr!= '_' ){
  103. *name++ = '_';
  104. }
  105. while( ptr < ptr2 )
  106. {
  107. char c = *ptr++;
  108. if( !cv_isalnum(c) && c != '-' && c != '_' )
  109. c = '_';
  110. *name++ = c;
  111. }
  112. *name = '\0';
  113. name = name_buf;
  114. if( strcmp( name, "_" ) == 0 )
  115. strcpy( name, stubname );
  116. return cv::string(name);
  117. }
  118. namespace cv
  119. {
  120. #ifndef ANDROID //unsuported wcstombs on android
  121. string fromUtf16(const WString& str)
  122. {
  123. cv::AutoBuffer<char> _buf(str.size()*4 + 1);
  124. char* buf = _buf;
  125. size_t sz = wcstombs(buf, str.c_str(), str.size());
  126. if( sz == (size_t)-1 )
  127. return string();
  128. buf[sz] = '\0';
  129. return string(buf);
  130. }
  131. WString toUtf16(const string& str)
  132. {
  133. cv::AutoBuffer<wchar_t> _buf(str.size() + 1);
  134. wchar_t* buf = _buf;
  135. size_t sz = mbstowcs(buf, str.c_str(), str.size());
  136. if( sz == (size_t)-1 )
  137. return WString();
  138. buf[sz] = '\0';
  139. return WString(buf);
  140. }
  141. #endif
  142. }
  143. typedef struct CvGenericHash
  144. {
  145. CV_SET_FIELDS()
  146. int tab_size;
  147. void** table;
  148. }
  149. CvGenericHash;
  150. typedef CvGenericHash CvStringHash;
  151. typedef struct CvFileMapNode
  152. {
  153. CvFileNode value;
  154. const CvStringHashNode* key;
  155. struct CvFileMapNode* next;
  156. }
  157. CvFileMapNode;
  158. typedef struct CvXMLStackRecord
  159. {
  160. CvMemStoragePos pos;
  161. CvString struct_tag;
  162. int struct_indent;
  163. int struct_flags;
  164. }
  165. CvXMLStackRecord;
  166. #define CV_XML_OPENING_TAG 1
  167. #define CV_XML_CLOSING_TAG 2
  168. #define CV_XML_EMPTY_TAG 3
  169. #define CV_XML_HEADER_TAG 4
  170. #define CV_XML_DIRECTIVE_TAG 5
  171. //typedef void (*CvParse)( struct CvFileStorage* fs );
  172. typedef void (*CvStartWriteStruct)( struct CvFileStorage* fs, const char* key,
  173. int struct_flags, const char* type_name );
  174. typedef void (*CvEndWriteStruct)( struct CvFileStorage* fs );
  175. typedef void (*CvWriteInt)( struct CvFileStorage* fs, const char* key, int value );
  176. typedef void (*CvWriteReal)( struct CvFileStorage* fs, const char* key, double value );
  177. typedef void (*CvWriteString)( struct CvFileStorage* fs, const char* key,
  178. const char* value, int quote );
  179. typedef void (*CvWriteComment)( struct CvFileStorage* fs, const char* comment, int eol_comment );
  180. typedef void (*CvStartNextStream)( struct CvFileStorage* fs );
  181. typedef struct CvFileStorage
  182. {
  183. int flags;
  184. int is_xml;
  185. int write_mode;
  186. int is_first;
  187. CvMemStorage* memstorage;
  188. CvMemStorage* dststorage;
  189. CvMemStorage* strstorage;
  190. CvStringHash* str_hash;
  191. CvSeq* roots;
  192. CvSeq* write_stack;
  193. int struct_indent;
  194. int struct_flags;
  195. CvString struct_tag;
  196. int space;
  197. char* filename;
  198. FILE* file;
  199. gzFile gzfile;
  200. char* buffer;
  201. char* buffer_start;
  202. char* buffer_end;
  203. int wrap_margin;
  204. int lineno;
  205. int dummy_eof;
  206. const char* errmsg;
  207. char errmsgbuf[128];
  208. CvStartWriteStruct start_write_struct;
  209. CvEndWriteStruct end_write_struct;
  210. CvWriteInt write_int;
  211. CvWriteReal write_real;
  212. CvWriteString write_string;
  213. CvWriteComment write_comment;
  214. CvStartNextStream start_next_stream;
  215. //CvParse parse;
  216. }
  217. CvFileStorage;
  218. static void icvPuts( CvFileStorage* fs, const char* str )
  219. {
  220. CV_Assert( fs->file || fs->gzfile );
  221. if( fs->file )
  222. fputs( str, fs->file );
  223. else
  224. gzputs( fs->gzfile, str );
  225. }
  226. static char* icvGets( CvFileStorage* fs, char* str, int maxCount )
  227. {
  228. CV_Assert( fs->file || fs->gzfile );
  229. if( fs->file )
  230. return fgets( str, maxCount, fs->file );
  231. return gzgets( fs->gzfile, str, maxCount );
  232. }
  233. static int icvEof( CvFileStorage* fs )
  234. {
  235. CV_Assert( fs->file || fs->gzfile );
  236. if( fs->file )
  237. return feof(fs->file);
  238. return gzeof(fs->gzfile);
  239. }
  240. static void icvClose( CvFileStorage* fs )
  241. {
  242. if( fs->file )
  243. fclose( fs->file );
  244. if( fs->gzfile )
  245. gzclose( fs->gzfile );
  246. fs->file = 0;
  247. fs->gzfile = 0;
  248. }
  249. static void icvRewind( CvFileStorage* fs )
  250. {
  251. CV_Assert( fs->file || fs->gzfile );
  252. if( fs->file )
  253. rewind(fs->file);
  254. else
  255. gzrewind(fs->gzfile);
  256. }
  257. #define CV_YML_INDENT 3
  258. #define CV_XML_INDENT 2
  259. #define CV_YML_INDENT_FLOW 1
  260. #define CV_FS_MAX_LEN 4096
  261. #define CV_FILE_STORAGE ('Y' + ('A' << 8) + ('M' << 16) + ('L' << 24))
  262. #define CV_IS_FILE_STORAGE(fs) ((fs) != 0 && (fs)->flags == CV_FILE_STORAGE)
  263. #define CV_CHECK_FILE_STORAGE(fs) \
  264. { \
  265. if( !CV_IS_FILE_STORAGE(fs) ) \
  266. CV_Error( (fs) ? CV_StsBadArg : CV_StsNullPtr, \
  267. "Invalid pointer to file storage" ); \
  268. }
  269. #define CV_CHECK_OUTPUT_FILE_STORAGE(fs) \
  270. { \
  271. CV_CHECK_FILE_STORAGE(fs); \
  272. if( !fs->write_mode ) \
  273. CV_Error( CV_StsError, "The file storage is opened for reading" ); \
  274. }
  275. CV_IMPL const char*
  276. cvAttrValue( const CvAttrList* attr, const char* attr_name )
  277. {
  278. while( attr && attr->attr )
  279. {
  280. int i;
  281. for( i = 0; attr->attr[i*2] != 0; i++ )
  282. {
  283. if( strcmp( attr_name, attr->attr[i*2] ) == 0 )
  284. return attr->attr[i*2+1];
  285. }
  286. attr = attr->next;
  287. }
  288. return 0;
  289. }
  290. static CvGenericHash*
  291. cvCreateMap( int flags, int header_size, int elem_size,
  292. CvMemStorage* storage, int start_tab_size )
  293. {
  294. if( header_size < (int)sizeof(CvGenericHash) )
  295. CV_Error( CV_StsBadSize, "Too small map header_size" );
  296. if( start_tab_size <= 0 )
  297. start_tab_size = 16;
  298. CvGenericHash* map = (CvGenericHash*)cvCreateSet( flags, header_size, elem_size, storage );
  299. map->tab_size = start_tab_size;
  300. start_tab_size *= sizeof(map->table[0]);
  301. map->table = (void**)cvMemStorageAlloc( storage, start_tab_size );
  302. memset( map->table, 0, start_tab_size );
  303. return map;
  304. }
  305. #ifdef __GNUC__
  306. #define CV_PARSE_ERROR( errmsg ) \
  307. icvParseError( fs, __func__, (errmsg), __FILE__, __LINE__ )
  308. #else
  309. #define CV_PARSE_ERROR( errmsg ) \
  310. icvParseError( fs, "", (errmsg), __FILE__, __LINE__ )
  311. #endif
  312. static void
  313. icvParseError( CvFileStorage* fs, const char* func_name,
  314. const char* err_msg, const char* source_file, int source_line )
  315. {
  316. char buf[1<<10];
  317. sprintf( buf, "%s(%d): %s", fs->filename, fs->lineno, err_msg );
  318. cvError( CV_StsParseError, func_name, buf, source_file, source_line );
  319. }
  320. static void
  321. icvFSCreateCollection( CvFileStorage* fs, int tag, CvFileNode* collection )
  322. {
  323. if( CV_NODE_IS_MAP(tag) )
  324. {
  325. if( collection->tag != CV_NODE_NONE )
  326. {
  327. assert( fs->is_xml != 0 );
  328. CV_PARSE_ERROR( "Sequence element should not have name (use <_></_>)" );
  329. }
  330. collection->data.map = cvCreateMap( 0, sizeof(CvFileNodeHash),
  331. sizeof(CvFileMapNode), fs->memstorage, 16 );
  332. }
  333. else
  334. {
  335. CvSeq* seq;
  336. seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvFileNode), fs->memstorage );
  337. // if <collection> contains some scalar element, add it to the newly created collection
  338. if( CV_NODE_TYPE(collection->tag) != CV_NODE_NONE )
  339. cvSeqPush( seq, collection );
  340. collection->data.seq = seq;
  341. }
  342. collection->tag = tag;
  343. cvSetSeqBlockSize( collection->data.seq, 8 );
  344. }
  345. /*static void
  346. icvFSReleaseCollection( CvSeq* seq )
  347. {
  348. if( seq )
  349. {
  350. int is_map = CV_IS_SET(seq);
  351. CvSeqReader reader;
  352. int i, total = seq->total;
  353. cvStartReadSeq( seq, &reader, 0 );
  354. for( i = 0; i < total; i++ )
  355. {
  356. CvFileNode* node = (CvFileNode*)reader.ptr;
  357. if( (!is_map || CV_IS_SET_ELEM( node )) && CV_NODE_IS_COLLECTION(node->tag) )
  358. {
  359. if( CV_NODE_IS_USER(node->tag) && node->info && node->data.obj.decoded )
  360. cvRelease( (void**)&node->data.obj.decoded );
  361. if( !CV_NODE_SEQ_IS_SIMPLE( node->data.seq ))
  362. icvFSReleaseCollection( node->data.seq );
  363. }
  364. CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
  365. }
  366. }
  367. }*/
  368. static char*
  369. icvFSDoResize( CvFileStorage* fs, char* ptr, int len )
  370. {
  371. char* new_ptr = 0;
  372. int written_len = (int)(ptr - fs->buffer_start);
  373. int new_size = (int)((fs->buffer_end - fs->buffer_start)*3/2);
  374. new_size = MAX( written_len + len, new_size );
  375. new_ptr = (char*)cvAlloc( new_size + 256 );
  376. fs->buffer = new_ptr + (fs->buffer - fs->buffer_start);
  377. if( written_len > 0 )
  378. memcpy( new_ptr, fs->buffer_start, written_len );
  379. fs->buffer_start = new_ptr;
  380. fs->buffer_end = fs->buffer_start + new_size;
  381. new_ptr += written_len;
  382. return new_ptr;
  383. }
  384. inline char* icvFSResizeWriteBuffer( CvFileStorage* fs, char* ptr, int len )
  385. {
  386. return ptr + len < fs->buffer_end ? ptr : icvFSDoResize( fs, ptr, len );
  387. }
  388. static char*
  389. icvFSFlush( CvFileStorage* fs )
  390. {
  391. char* ptr = fs->buffer;
  392. int indent;
  393. if( ptr > fs->buffer_start + fs->space )
  394. {
  395. ptr[0] = '\n';
  396. ptr[1] = '\0';
  397. icvPuts( fs, fs->buffer_start );
  398. fs->buffer = fs->buffer_start;
  399. }
  400. indent = fs->struct_indent;
  401. if( fs->space != indent )
  402. {
  403. if( fs->space < indent )
  404. memset( fs->buffer_start + fs->space, ' ', indent - fs->space );
  405. fs->space = indent;
  406. }
  407. ptr = fs->buffer = fs->buffer_start + fs->space;
  408. return ptr;
  409. }
  410. /* closes file storage and deallocates buffers */
  411. CV_IMPL void
  412. cvReleaseFileStorage( CvFileStorage** p_fs )
  413. {
  414. if( !p_fs )
  415. CV_Error( CV_StsNullPtr, "NULL double pointer to file storage" );
  416. if( *p_fs )
  417. {
  418. CvFileStorage* fs = *p_fs;
  419. *p_fs = 0;
  420. if( fs->write_mode && (fs->file || fs->gzfile) )
  421. {
  422. if( fs->write_stack )
  423. {
  424. while( fs->write_stack->total > 0 )
  425. cvEndWriteStruct(fs);
  426. }
  427. icvFSFlush(fs);
  428. if( fs->is_xml )
  429. icvPuts( fs, "</opencv_storage>\n" );
  430. }
  431. //icvFSReleaseCollection( fs->roots ); // delete all the user types recursively
  432. icvClose(fs);
  433. cvReleaseMemStorage( &fs->strstorage );
  434. cvFree( &fs->buffer_start );
  435. cvReleaseMemStorage( &fs->memstorage );
  436. memset( fs, 0, sizeof(*fs) );
  437. cvFree( &fs );
  438. }
  439. }
  440. #define CV_HASHVAL_SCALE 33
  441. CV_IMPL CvStringHashNode*
  442. cvGetHashedKey( CvFileStorage* fs, const char* str, int len, int create_missing )
  443. {
  444. CvStringHashNode* node = 0;
  445. unsigned hashval = 0;
  446. int i, tab_size;
  447. CvStringHash* map = fs->str_hash;
  448. if( !fs )
  449. return 0;
  450. if( len < 0 )
  451. {
  452. for( i = 0; str[i] != '\0'; i++ )
  453. hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
  454. len = i;
  455. }
  456. else for( i = 0; i < len; i++ )
  457. hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
  458. hashval &= INT_MAX;
  459. tab_size = map->tab_size;
  460. if( (tab_size & (tab_size - 1)) == 0 )
  461. i = (int)(hashval & (tab_size - 1));
  462. else
  463. i = (int)(hashval % tab_size);
  464. for( node = (CvStringHashNode*)(map->table[i]); node != 0; node = node->next )
  465. {
  466. if( node->hashval == hashval &&
  467. node->str.len == len &&
  468. memcmp( node->str.ptr, str, len ) == 0 )
  469. break;
  470. }
  471. if( !node && create_missing )
  472. {
  473. node = (CvStringHashNode*)cvSetNew( (CvSet*)map );
  474. node->hashval = hashval;
  475. node->str = cvMemStorageAllocString( map->storage, str, len );
  476. node->next = (CvStringHashNode*)(map->table[i]);
  477. map->table[i] = node;
  478. }
  479. return node;
  480. }
  481. CV_IMPL CvFileNode*
  482. cvGetFileNode( CvFileStorage* fs, CvFileNode* _map_node,
  483. const CvStringHashNode* key,
  484. int create_missing )
  485. {
  486. CvFileNode* value = 0;
  487. int k = 0, attempts = 1;
  488. if( !fs )
  489. return 0;
  490. CV_CHECK_FILE_STORAGE(fs);
  491. if( !key )
  492. CV_Error( CV_StsNullPtr, "Null key element" );
  493. if( _map_node )
  494. {
  495. if( !fs->roots )
  496. return 0;
  497. attempts = fs->roots->total;
  498. }
  499. for( k = 0; k < attempts; k++ )
  500. {
  501. int i, tab_size;
  502. CvFileNode* map_node = _map_node;
  503. CvFileMapNode* another;
  504. CvFileNodeHash* map;
  505. if( !map_node )
  506. map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
  507. if( !CV_NODE_IS_MAP(map_node->tag) )
  508. {
  509. if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
  510. CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
  511. CV_Error( CV_StsError, "The node is neither a map nor an empty collection" );
  512. return 0;
  513. }
  514. map = map_node->data.map;
  515. tab_size = map->tab_size;
  516. if( (tab_size & (tab_size - 1)) == 0 )
  517. i = (int)(key->hashval & (tab_size - 1));
  518. else
  519. i = (int)(key->hashval % tab_size);
  520. for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
  521. if( another->key == key )
  522. {
  523. if( !create_missing )
  524. {
  525. value = &another->value;
  526. return value;
  527. }
  528. CV_PARSE_ERROR( "Duplicated key" );
  529. }
  530. if( k == attempts - 1 && create_missing )
  531. {
  532. CvFileMapNode* node = (CvFileMapNode*)cvSetNew( (CvSet*)map );
  533. node->key = key;
  534. node->next = (CvFileMapNode*)(map->table[i]);
  535. map->table[i] = node;
  536. value = (CvFileNode*)node;
  537. }
  538. }
  539. return value;
  540. }
  541. CV_IMPL CvFileNode*
  542. cvGetFileNodeByName( const CvFileStorage* fs, const CvFileNode* _map_node, const char* str )
  543. {
  544. CvFileNode* value = 0;
  545. int i, len, tab_size;
  546. unsigned hashval = 0;
  547. int k = 0, attempts = 1;
  548. if( !fs )
  549. return 0;
  550. CV_CHECK_FILE_STORAGE(fs);
  551. if( !str )
  552. CV_Error( CV_StsNullPtr, "Null element name" );
  553. for( i = 0; str[i] != '\0'; i++ )
  554. hashval = hashval*CV_HASHVAL_SCALE + (unsigned char)str[i];
  555. hashval &= INT_MAX;
  556. len = i;
  557. if( !_map_node )
  558. {
  559. if( !fs->roots )
  560. return 0;
  561. attempts = fs->roots->total;
  562. }
  563. for( k = 0; k < attempts; k++ )
  564. {
  565. CvFileNodeHash* map;
  566. const CvFileNode* map_node = _map_node;
  567. CvFileMapNode* another;
  568. if( !map_node )
  569. map_node = (CvFileNode*)cvGetSeqElem( fs->roots, k );
  570. if( !CV_NODE_IS_MAP(map_node->tag) )
  571. {
  572. if( (!CV_NODE_IS_SEQ(map_node->tag) || map_node->data.seq->total != 0) &&
  573. CV_NODE_TYPE(map_node->tag) != CV_NODE_NONE )
  574. CV_Error( CV_StsError, "The node is neither a map nor an empty collection" );
  575. return 0;
  576. }
  577. map = map_node->data.map;
  578. tab_size = map->tab_size;
  579. if( (tab_size & (tab_size - 1)) == 0 )
  580. i = (int)(hashval & (tab_size - 1));
  581. else
  582. i = (int)(hashval % tab_size);
  583. for( another = (CvFileMapNode*)(map->table[i]); another != 0; another = another->next )
  584. {
  585. const CvStringHashNode* key = another->key;
  586. if( key->hashval == hashval &&
  587. key->str.len == len &&
  588. memcmp( key->str.ptr, str, len ) == 0 )
  589. {
  590. value = &another->value;
  591. return value;
  592. }
  593. }
  594. }
  595. return value;
  596. }
  597. CV_IMPL CvFileNode*
  598. cvGetRootFileNode( const CvFileStorage* fs, int stream_index )
  599. {
  600. CV_CHECK_FILE_STORAGE(fs);
  601. if( !fs->roots || (unsigned)stream_index >= (unsigned)fs->roots->total )
  602. return 0;
  603. return (CvFileNode*)cvGetSeqElem( fs->roots, stream_index );
  604. }
  605. /* returns the sequence element by its index */
  606. /*CV_IMPL CvFileNode*
  607. cvGetFileNodeFromSeq( CvFileStorage* fs,
  608. CvFileNode* seq_node, int index )
  609. {
  610. CvFileNode* value = 0;
  611. CvSeq* seq;
  612. if( !seq_node )
  613. seq = fs->roots;
  614. else if( !CV_NODE_IS_SEQ(seq_node->tag) )
  615. {
  616. if( CV_NODE_IS_MAP(seq_node->tag) )
  617. CV_Error( CV_StsError, "The node is map. Use cvGetFileNodeFromMap()." );
  618. if( CV_NODE_TYPE(seq_node->tag) == CV_NODE_NONE )
  619. CV_Error( CV_StsError, "The node is an empty object (None)." );
  620. if( index != 0 && index != -1 )
  621. CV_Error( CV_StsOutOfRange, "" );
  622. value = seq_node;
  623. EXIT;
  624. }
  625. else
  626. seq = seq_node->data.seq;
  627. if( !seq )
  628. CV_Error( CV_StsNullPtr, "The file storage is empty" );
  629. value = (CvFileNode*)cvGetSeqElem( seq, index, 0 );
  630. return value;
  631. }*/
  632. static char*
  633. icvDoubleToString( char* buf, double value )
  634. {
  635. Cv64suf val;
  636. unsigned ieee754_hi;
  637. val.f = value;
  638. ieee754_hi = (unsigned)(val.u >> 32);
  639. if( (ieee754_hi & 0x7ff00000) != 0x7ff00000 )
  640. {
  641. int ivalue = cvRound(value);
  642. if( ivalue == value )
  643. sprintf( buf, "%d.", ivalue );
  644. else
  645. {
  646. static const char* fmt = "%.16e";
  647. char* ptr = buf;
  648. sprintf( buf, fmt, value );
  649. if( *ptr == '+' || *ptr == '-' )
  650. ptr++;
  651. for( ; cv_isdigit(*ptr); ptr++ )
  652. ;
  653. if( *ptr == ',' )
  654. *ptr = '.';
  655. }
  656. }
  657. else
  658. {
  659. unsigned ieee754_lo = (unsigned)val.u;
  660. if( (ieee754_hi & 0x7fffffff) + (ieee754_lo != 0) > 0x7ff00000 )
  661. strcpy( buf, ".Nan" );
  662. else
  663. strcpy( buf, (int)ieee754_hi < 0 ? "-.Inf" : ".Inf" );
  664. }
  665. return buf;
  666. }
  667. static char*
  668. icvFloatToString( char* buf, float value )
  669. {
  670. Cv32suf val;
  671. unsigned ieee754;
  672. val.f = value;
  673. ieee754 = val.u;
  674. if( (ieee754 & 0x7f800000) != 0x7f800000 )
  675. {
  676. int ivalue = cvRound(value);
  677. if( ivalue == value )
  678. sprintf( buf, "%d.", ivalue );
  679. else
  680. {
  681. static const char* fmt = "%.8e";
  682. char* ptr = buf;
  683. sprintf( buf, fmt, value );
  684. if( *ptr == '+' || *ptr == '-' )
  685. ptr++;
  686. for( ; cv_isdigit(*ptr); ptr++ )
  687. ;
  688. if( *ptr == ',' )
  689. *ptr = '.';
  690. }
  691. }
  692. else
  693. {
  694. if( (ieee754 & 0x7fffffff) != 0x7f800000 )
  695. strcpy( buf, ".Nan" );
  696. else
  697. strcpy( buf, (int)ieee754 < 0 ? "-.Inf" : ".Inf" );
  698. }
  699. return buf;
  700. }
  701. static void
  702. icvProcessSpecialDouble( CvFileStorage* fs, char* buf, double* value, char** endptr )
  703. {
  704. char c = buf[0];
  705. int inf_hi = 0x7ff00000;
  706. if( c == '-' || c == '+' )
  707. {
  708. inf_hi = c == '-' ? 0xfff00000 : 0x7ff00000;
  709. c = *++buf;
  710. }
  711. if( c != '.' )
  712. CV_PARSE_ERROR( "Bad format of floating-point constant" );
  713. if( toupper(buf[1]) == 'I' && toupper(buf[2]) == 'N' && toupper(buf[3]) == 'F' )
  714. *(uint64*)value = ((uint64)inf_hi << 32);
  715. else if( toupper(buf[1]) == 'N' && toupper(buf[2]) == 'A' && toupper(buf[3]) == 'N' )
  716. *(uint64*)value = (uint64)-1;
  717. else
  718. CV_PARSE_ERROR( "Bad format of floating-point constant" );
  719. *endptr = buf + 4;
  720. }
  721. static double icv_strtod( CvFileStorage* fs, char* ptr, char** endptr )
  722. {
  723. double fval = strtod( ptr, endptr );
  724. if( **endptr == '.' )
  725. {
  726. char* dot_pos = *endptr;
  727. *dot_pos = ',';
  728. double fval2 = strtod( ptr, endptr );
  729. *dot_pos = '.';
  730. if( *endptr > dot_pos )
  731. fval = fval2;
  732. else
  733. *endptr = dot_pos;
  734. }
  735. if( *endptr == ptr || cv_isalpha(**endptr) )
  736. icvProcessSpecialDouble( fs, ptr, &fval, endptr );
  737. return fval;
  738. }
  739. /****************************************************************************************\
  740. * YAML Parser *
  741. \****************************************************************************************/
  742. static char*
  743. icvYMLSkipSpaces( CvFileStorage* fs, char* ptr, int min_indent, int max_comment_indent )
  744. {
  745. for(;;)
  746. {
  747. while( *ptr == ' ' )
  748. ptr++;
  749. if( *ptr == '#' )
  750. {
  751. if( ptr - fs->buffer_start > max_comment_indent )
  752. return ptr;
  753. *ptr = '\0';
  754. }
  755. else if( cv_isprint(*ptr) )
  756. {
  757. if( ptr - fs->buffer_start < min_indent )
  758. CV_PARSE_ERROR( "Incorrect indentation" );
  759. break;
  760. }
  761. else if( *ptr == '\0' || *ptr == '\n' || *ptr == '\r' )
  762. {
  763. int max_size = (int)(fs->buffer_end - fs->buffer_start);
  764. ptr = icvGets( fs, fs->buffer_start, max_size );
  765. if( !ptr )
  766. {
  767. // emulate end of stream
  768. ptr = fs->buffer_start;
  769. ptr[0] = ptr[1] = ptr[2] = '.';
  770. ptr[3] = '\0';
  771. fs->dummy_eof = 1;
  772. break;
  773. }
  774. else
  775. {
  776. int l = (int)strlen(ptr);
  777. if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) )
  778. CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
  779. }
  780. fs->lineno++;
  781. }
  782. else
  783. CV_PARSE_ERROR( *ptr == '\t' ? "Tabs are prohibited in YAML!" : "Invalid character" );
  784. }
  785. return ptr;
  786. }
  787. static char*
  788. icvYMLParseKey( CvFileStorage* fs, char* ptr,
  789. CvFileNode* map_node, CvFileNode** value_placeholder )
  790. {
  791. char c;
  792. char *endptr = ptr - 1, *saveptr;
  793. CvStringHashNode* str_hash_node;
  794. if( *ptr == '-' )
  795. CV_PARSE_ERROR( "Key may not start with \'-\'" );
  796. do c = *++endptr;
  797. while( cv_isprint(c) && c != ':' );
  798. if( c != ':' )
  799. CV_PARSE_ERROR( "Missing \':\'" );
  800. saveptr = endptr + 1;
  801. do c = *--endptr;
  802. while( c == ' ' );
  803. ++endptr;
  804. if( endptr == ptr )
  805. CV_PARSE_ERROR( "An empty key" );
  806. str_hash_node = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 );
  807. *value_placeholder = cvGetFileNode( fs, map_node, str_hash_node, 1 );
  808. ptr = saveptr;
  809. return ptr;
  810. }
  811. static char*
  812. icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
  813. int parent_flags, int min_indent )
  814. {
  815. char buf[CV_FS_MAX_LEN + 1024];
  816. char* endptr = 0;
  817. char c = ptr[0], d = ptr[1];
  818. int is_parent_flow = CV_NODE_IS_FLOW(parent_flags);
  819. int value_type = CV_NODE_NONE;
  820. int len;
  821. memset( node, 0, sizeof(*node) );
  822. if( c == '!' ) // handle explicit type specification
  823. {
  824. if( d == '!' || d == '^' )
  825. {
  826. ptr++;
  827. value_type |= CV_NODE_USER;
  828. }
  829. endptr = ptr++;
  830. do d = *++endptr;
  831. while( cv_isprint(d) && d != ' ' );
  832. len = (int)(endptr - ptr);
  833. if( len == 0 )
  834. CV_PARSE_ERROR( "Empty type name" );
  835. d = *endptr;
  836. *endptr = '\0';
  837. if( len == 3 && !CV_NODE_IS_USER(value_type) )
  838. {
  839. if( memcmp( ptr, "str", 3 ) == 0 )
  840. value_type = CV_NODE_STRING;
  841. else if( memcmp( ptr, "int", 3 ) == 0 )
  842. value_type = CV_NODE_INT;
  843. else if( memcmp( ptr, "seq", 3 ) == 0 )
  844. value_type = CV_NODE_SEQ;
  845. else if( memcmp( ptr, "map", 3 ) == 0 )
  846. value_type = CV_NODE_MAP;
  847. }
  848. else if( len == 5 && !CV_NODE_IS_USER(value_type) )
  849. {
  850. if( memcmp( ptr, "float", 5 ) == 0 )
  851. value_type = CV_NODE_REAL;
  852. }
  853. else if( CV_NODE_IS_USER(value_type) )
  854. {
  855. node->info = cvFindType( ptr );
  856. if( !node->info )
  857. node->tag &= ~CV_NODE_USER;
  858. }
  859. *endptr = d;
  860. ptr = icvYMLSkipSpaces( fs, endptr, min_indent, INT_MAX );
  861. c = *ptr;
  862. if( !CV_NODE_IS_USER(value_type) )
  863. {
  864. if( value_type == CV_NODE_STRING && c != '\'' && c != '\"' )
  865. goto force_string;
  866. if( value_type == CV_NODE_INT )
  867. goto force_int;
  868. if( value_type == CV_NODE_REAL )
  869. goto force_real;
  870. }
  871. }
  872. if( cv_isdigit(c) ||
  873. ((c == '-' || c == '+') && (cv_isdigit(d) || d == '.')) ||
  874. (c == '.' && cv_isalnum(d))) // a number
  875. {
  876. double fval;
  877. int ival;
  878. endptr = ptr + (c == '-' || c == '+');
  879. while( cv_isdigit(*endptr) )
  880. endptr++;
  881. if( *endptr == '.' || *endptr == 'e' )
  882. {
  883. force_real:
  884. fval = icv_strtod( fs, ptr, &endptr );
  885. /*if( endptr == ptr || cv_isalpha(*endptr) )
  886. icvProcessSpecialDouble( fs, endptr, &fval, &endptr ));*/
  887. node->tag = CV_NODE_REAL;
  888. node->data.f = fval;
  889. }
  890. else
  891. {
  892. force_int:
  893. ival = (int)strtol( ptr, &endptr, 0 );
  894. node->tag = CV_NODE_INT;
  895. node->data.i = ival;
  896. }
  897. if( !endptr || endptr == ptr )
  898. CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
  899. ptr = endptr;
  900. }
  901. else if( c == '\'' || c == '\"' ) // an explicit string
  902. {
  903. node->tag = CV_NODE_STRING;
  904. if( c == '\'' )
  905. for( len = 0; len < CV_FS_MAX_LEN; )
  906. {
  907. c = *++ptr;
  908. if( cv_isalnum(c) || (c != '\'' && cv_isprint(c)))
  909. buf[len++] = c;
  910. else if( c == '\'' )
  911. {
  912. c = *++ptr;
  913. if( c != '\'' )
  914. break;
  915. buf[len++] = c;
  916. }
  917. else
  918. CV_PARSE_ERROR( "Invalid character" );
  919. }
  920. else
  921. for( len = 0; len < CV_FS_MAX_LEN; )
  922. {
  923. c = *++ptr;
  924. if( cv_isalnum(c) || (c != '\\' && c != '\"' && cv_isprint(c)))
  925. buf[len++] = c;
  926. else if( c == '\"' )
  927. {
  928. ++ptr;
  929. break;
  930. }
  931. else if( c == '\\' )
  932. {
  933. d = *++ptr;
  934. if( d == '\'' )
  935. buf[len++] = d;
  936. else if( d == '\"' || d == '\\' || d == '\'' )
  937. buf[len++] = d;
  938. else if( d == 'n' )
  939. buf[len++] = '\n';
  940. else if( d == 'r' )
  941. buf[len++] = '\r';
  942. else if( d == 't' )
  943. buf[len++] = '\t';
  944. else if( d == 'x' || (cv_isdigit(d) && d < '8') )
  945. {
  946. int val, is_hex = d == 'x';
  947. c = ptr[3];
  948. ptr[3] = '\0';
  949. val = strtol( ptr + is_hex, &endptr, is_hex ? 8 : 16 );
  950. ptr[3] = c;
  951. if( endptr == ptr + is_hex )
  952. buf[len++] = 'x';
  953. else
  954. {
  955. buf[len++] = (char)val;
  956. ptr = endptr;
  957. }
  958. }
  959. }
  960. else
  961. CV_PARSE_ERROR( "Invalid character" );
  962. }
  963. if( len >= CV_FS_MAX_LEN )
  964. CV_PARSE_ERROR( "Too long string literal" );
  965. node->data.str = cvMemStorageAllocString( fs->memstorage, buf, len );
  966. }
  967. else if( c == '[' || c == '{' ) // collection as a flow
  968. {
  969. int new_min_indent = min_indent + !is_parent_flow;
  970. int struct_flags = CV_NODE_FLOW + (c == '{' ? CV_NODE_MAP : CV_NODE_SEQ);
  971. int is_simple = 1;
  972. icvFSCreateCollection( fs, CV_NODE_TYPE(struct_flags) +
  973. (node->info ? CV_NODE_USER : 0), node );
  974. d = c == '[' ? ']' : '}';
  975. for( ++ptr ;;)
  976. {
  977. CvFileNode* elem = 0;
  978. ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX );
  979. if( *ptr == '}' || *ptr == ']' )
  980. {
  981. if( *ptr != d )
  982. CV_PARSE_ERROR( "The wrong closing bracket" );
  983. ptr++;
  984. break;
  985. }
  986. if( node->data.seq->total != 0 )
  987. {
  988. if( *ptr != ',' )
  989. CV_PARSE_ERROR( "Missing , between the elements" );
  990. ptr = icvYMLSkipSpaces( fs, ptr + 1, new_min_indent, INT_MAX );
  991. }
  992. if( CV_NODE_IS_MAP(struct_flags) )
  993. {
  994. ptr = icvYMLParseKey( fs, ptr, node, &elem );
  995. ptr = icvYMLSkipSpaces( fs, ptr, new_min_indent, INT_MAX );
  996. }
  997. else
  998. {
  999. if( *ptr == ']' )
  1000. break;
  1001. elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
  1002. }
  1003. ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, new_min_indent );
  1004. if( CV_NODE_IS_MAP(struct_flags) )
  1005. elem->tag |= CV_NODE_NAMED;
  1006. is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
  1007. }
  1008. node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
  1009. }
  1010. else
  1011. {
  1012. int indent, struct_flags, is_simple;
  1013. if( is_parent_flow || c != '-' )
  1014. {
  1015. // implicit (one-line) string or nested block-style collection
  1016. if( !is_parent_flow )
  1017. {
  1018. if( c == '?' )
  1019. CV_PARSE_ERROR( "Complex keys are not supported" );
  1020. if( c == '|' || c == '>' )
  1021. CV_PARSE_ERROR( "Multi-line text literals are not supported" );
  1022. }
  1023. force_string:
  1024. endptr = ptr - 1;
  1025. do c = *++endptr;
  1026. while( cv_isprint(c) &&
  1027. (!is_parent_flow || (c != ',' && c != '}' && c != ']')) &&
  1028. (is_parent_flow || c != ':' || value_type == CV_NODE_STRING));
  1029. if( endptr == ptr )
  1030. CV_PARSE_ERROR( "Invalid character" );
  1031. if( is_parent_flow || c != ':' )
  1032. {
  1033. char* str_end = endptr;
  1034. node->tag = CV_NODE_STRING;
  1035. // strip spaces in the end of string
  1036. do c = *--str_end;
  1037. while( str_end > ptr && c == ' ' );
  1038. str_end++;
  1039. node->data.str = cvMemStorageAllocString( fs->memstorage, ptr, (int)(str_end - ptr) );
  1040. ptr = endptr;
  1041. return ptr;
  1042. }
  1043. struct_flags = CV_NODE_MAP;
  1044. }
  1045. else
  1046. struct_flags = CV_NODE_SEQ;
  1047. icvFSCreateCollection( fs, struct_flags +
  1048. (node->info ? CV_NODE_USER : 0), node );
  1049. indent = (int)(ptr - fs->buffer_start);
  1050. is_simple = 1;
  1051. for(;;)
  1052. {
  1053. CvFileNode* elem = 0;
  1054. if( CV_NODE_IS_MAP(struct_flags) )
  1055. {
  1056. ptr = icvYMLParseKey( fs, ptr, node, &elem );
  1057. }
  1058. else
  1059. {
  1060. c = *ptr++;
  1061. if( c != '-' )
  1062. CV_PARSE_ERROR( "Block sequence elements must be preceded with \'-\'" );
  1063. elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
  1064. }
  1065. ptr = icvYMLSkipSpaces( fs, ptr, indent + 1, INT_MAX );
  1066. ptr = icvYMLParseValue( fs, ptr, elem, struct_flags, indent + 1 );
  1067. if( CV_NODE_IS_MAP(struct_flags) )
  1068. elem->tag |= CV_NODE_NAMED;
  1069. is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
  1070. ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
  1071. if( ptr - fs->buffer_start != indent )
  1072. {
  1073. if( ptr - fs->buffer_start < indent )
  1074. break;
  1075. else
  1076. CV_PARSE_ERROR( "Incorrect indentation" );
  1077. }
  1078. if( memcmp( ptr, "...", 3 ) == 0 )
  1079. break;
  1080. }
  1081. node->data.seq->flags |= is_simple ? CV_NODE_SEQ_SIMPLE : 0;
  1082. }
  1083. return ptr;
  1084. }
  1085. static void
  1086. icvYMLParse( CvFileStorage* fs )
  1087. {
  1088. char* ptr = fs->buffer_start;
  1089. int is_first = 1;
  1090. for(;;)
  1091. {
  1092. // 0. skip leading comments and directives and ...
  1093. // 1. reach the first item
  1094. for(;;)
  1095. {
  1096. ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
  1097. if( !ptr )
  1098. return;
  1099. if( *ptr == '%' )
  1100. {
  1101. if( memcmp( ptr, "%YAML:", 6 ) == 0 &&
  1102. memcmp( ptr, "%YAML:1.", 8 ) != 0 )
  1103. CV_PARSE_ERROR( "Unsupported YAML version (it must be 1.x)" );
  1104. *ptr = '\0';
  1105. }
  1106. else if( *ptr == '-' )
  1107. {
  1108. if( memcmp(ptr, "---", 3) == 0 )
  1109. {
  1110. ptr += 3;
  1111. break;
  1112. }
  1113. else if( is_first )
  1114. break;
  1115. }
  1116. else if( cv_isalnum(*ptr) || *ptr=='_')
  1117. {
  1118. if( !is_first )
  1119. CV_PARSE_ERROR( "The YAML streams must start with '---', except the first one" );
  1120. break;
  1121. }
  1122. else if( fs->dummy_eof )
  1123. break;
  1124. else
  1125. CV_PARSE_ERROR( "Invalid or unsupported syntax" );
  1126. }
  1127. ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
  1128. if( memcmp( ptr, "...", 3 ) != 0 )
  1129. {
  1130. // 2. parse the collection
  1131. CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
  1132. ptr = icvYMLParseValue( fs, ptr, root_node, CV_NODE_NONE, 0 );
  1133. if( !CV_NODE_IS_COLLECTION(root_node->tag) )
  1134. CV_PARSE_ERROR( "Only collections as YAML streams are supported by this parser" );
  1135. // 3. parse until the end of file or next collection
  1136. ptr = icvYMLSkipSpaces( fs, ptr, 0, INT_MAX );
  1137. if( !ptr )
  1138. return;
  1139. }
  1140. if( fs->dummy_eof )
  1141. break;
  1142. ptr += 3;
  1143. is_first = 0;
  1144. }
  1145. }
  1146. /****************************************************************************************\
  1147. * YAML Emitter *
  1148. \****************************************************************************************/
  1149. static void
  1150. icvYMLWrite( CvFileStorage* fs, const char* key, const char* data )
  1151. {
  1152. int i, keylen = 0;
  1153. int datalen = 0;
  1154. int struct_flags;
  1155. char* ptr;
  1156. struct_flags = fs->struct_flags;
  1157. if( key && key[0] == '\0' )
  1158. key = 0;
  1159. if( CV_NODE_IS_COLLECTION(struct_flags) )
  1160. {
  1161. if( (CV_NODE_IS_MAP(struct_flags) ^ (key != 0)) )
  1162. CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
  1163. "or add element with key to sequence" );
  1164. }
  1165. else
  1166. {
  1167. fs->is_first = 0;
  1168. struct_flags = CV_NODE_EMPTY | (key ? CV_NODE_MAP : CV_NODE_SEQ);
  1169. }
  1170. if( key )
  1171. {
  1172. keylen = (int)strlen(key);
  1173. if( keylen == 0 )
  1174. CV_Error( CV_StsBadArg, "The key is an empty" );
  1175. if( keylen > CV_FS_MAX_LEN )
  1176. CV_Error( CV_StsBadArg, "The key is too long" );
  1177. }
  1178. if( data )
  1179. datalen = (int)strlen(data);
  1180. if( CV_NODE_IS_FLOW(struct_flags) )
  1181. {
  1182. int new_offset;
  1183. ptr = fs->buffer;
  1184. if( !CV_NODE_IS_EMPTY(struct_flags) )
  1185. *ptr++ = ',';
  1186. new_offset = (int)(ptr - fs->buffer_start) + keylen + datalen;
  1187. if( new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10 )
  1188. {
  1189. fs->buffer = ptr;
  1190. ptr = icvFSFlush(fs);
  1191. }
  1192. else
  1193. *ptr++ = ' ';
  1194. }
  1195. else
  1196. {
  1197. ptr = icvFSFlush(fs);
  1198. if( !CV_NODE_IS_MAP(struct_flags) )
  1199. {
  1200. *ptr++ = '-';
  1201. if( data )
  1202. *ptr++ = ' ';
  1203. }
  1204. }
  1205. if( key )
  1206. {
  1207. if( !cv_isalpha(key[0]) && key[0] != '_' )
  1208. CV_Error( CV_StsBadArg, "Key must start with a letter or _" );
  1209. ptr = icvFSResizeWriteBuffer( fs, ptr, keylen );
  1210. for( i = 0; i < keylen; i++ )
  1211. {
  1212. char c = key[i];
  1213. ptr[i] = c;
  1214. if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
  1215. CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
  1216. }
  1217. ptr += keylen;
  1218. *ptr++ = ':';
  1219. if( !CV_NODE_IS_FLOW(struct_flags) && data )
  1220. *ptr++ = ' ';
  1221. }
  1222. if( data )
  1223. {
  1224. ptr = icvFSResizeWriteBuffer( fs, ptr, datalen );
  1225. memcpy( ptr, data, datalen );
  1226. ptr += datalen;
  1227. }
  1228. fs->buffer = ptr;
  1229. fs->struct_flags = struct_flags & ~CV_NODE_EMPTY;
  1230. }
  1231. static void
  1232. icvYMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
  1233. const char* type_name CV_DEFAULT(0))
  1234. {
  1235. int parent_flags;
  1236. char buf[CV_FS_MAX_LEN + 1024];
  1237. const char* data = 0;
  1238. struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
  1239. if( !CV_NODE_IS_COLLECTION(struct_flags))
  1240. CV_Error( CV_StsBadArg,
  1241. "Some collection type - CV_NODE_SEQ or CV_NODE_MAP, must be specified" );
  1242. if( CV_NODE_IS_FLOW(struct_flags) )
  1243. {
  1244. char c = CV_NODE_IS_MAP(struct_flags) ? '{' : '[';
  1245. struct_flags |= CV_NODE_FLOW;
  1246. if( type_name )
  1247. sprintf( buf, "!!%s %c", type_name, c );
  1248. else
  1249. {
  1250. buf[0] = c;
  1251. buf[1] = '\0';
  1252. }
  1253. data = buf;
  1254. }
  1255. else if( type_name )
  1256. {
  1257. sprintf( buf, "!!%s", type_name );
  1258. data = buf;
  1259. }
  1260. icvYMLWrite( fs, key, data );
  1261. parent_flags = fs->struct_flags;
  1262. cvSeqPush( fs->write_stack, &parent_flags );
  1263. fs->struct_flags = struct_flags;
  1264. if( !CV_NODE_IS_FLOW(parent_flags) )
  1265. fs->struct_indent += CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags);
  1266. }
  1267. static void
  1268. icvYMLEndWriteStruct( CvFileStorage* fs )
  1269. {
  1270. int parent_flags = 0, struct_flags;
  1271. char* ptr;
  1272. struct_flags = fs->struct_flags;
  1273. if( fs->write_stack->total == 0 )
  1274. CV_Error( CV_StsError, "EndWriteStruct w/o matching StartWriteStruct" );
  1275. cvSeqPop( fs->write_stack, &parent_flags );
  1276. if( CV_NODE_IS_FLOW(struct_flags) )
  1277. {
  1278. ptr = fs->buffer;
  1279. if( ptr > fs->buffer_start + fs->struct_indent && !CV_NODE_IS_EMPTY(struct_flags) )
  1280. *ptr++ = ' ';
  1281. *ptr++ = CV_NODE_IS_MAP(struct_flags) ? '}' : ']';
  1282. fs->buffer = ptr;
  1283. }
  1284. else if( CV_NODE_IS_EMPTY(struct_flags) )
  1285. {
  1286. ptr = icvFSFlush(fs);
  1287. memcpy( ptr, CV_NODE_IS_MAP(struct_flags) ? "{}" : "[]", 2 );
  1288. fs->buffer = ptr + 2;
  1289. }
  1290. if( !CV_NODE_IS_FLOW(parent_flags) )
  1291. fs->struct_indent -= CV_YML_INDENT + CV_NODE_IS_FLOW(struct_flags);
  1292. assert( fs->struct_indent >= 0 );
  1293. fs->struct_flags = parent_flags;
  1294. }
  1295. static void
  1296. icvYMLStartNextStream( CvFileStorage* fs )
  1297. {
  1298. if( !fs->is_first )
  1299. {
  1300. while( fs->write_stack->total > 0 )
  1301. icvYMLEndWriteStruct(fs);
  1302. fs->struct_indent = 0;
  1303. icvFSFlush(fs);
  1304. icvPuts( fs, "...\n" );
  1305. icvPuts( fs, "---\n" );
  1306. fs->buffer = fs->buffer_start;
  1307. }
  1308. }
  1309. static void
  1310. icvYMLWriteInt( CvFileStorage* fs, const char* key, int value )
  1311. {
  1312. char buf[128];
  1313. icvYMLWrite( fs, key, icv_itoa( value, buf, 10 ));
  1314. }
  1315. static void
  1316. icvYMLWriteReal( CvFileStorage* fs, const char* key, double value )
  1317. {
  1318. char buf[128];
  1319. icvYMLWrite( fs, key, icvDoubleToString( buf, value ));
  1320. }
  1321. static void
  1322. icvYMLWriteString( CvFileStorage* fs, const char* key,
  1323. const char* str, int quote CV_DEFAULT(0))
  1324. {
  1325. char buf[CV_FS_MAX_LEN*4+16];
  1326. char* data = (char*)str;
  1327. int i, len;
  1328. if( !str )
  1329. CV_Error( CV_StsNullPtr, "Null string pointer" );
  1330. len = (int)strlen(str);
  1331. if( len > CV_FS_MAX_LEN )
  1332. CV_Error( CV_StsBadArg, "The written string is too long" );
  1333. if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
  1334. {
  1335. int need_quote = quote || len == 0;
  1336. data = buf;
  1337. *data++ = '\"';
  1338. for( i = 0; i < len; i++ )
  1339. {
  1340. char c = str[i];
  1341. if( !need_quote && !cv_isalnum(c) && c != '_' && c != ' ' && c != '-' &&
  1342. c != '(' && c != ')' && c != '/' && c != '+' && c != ';' )
  1343. need_quote = 1;
  1344. if( !cv_isalnum(c) && (!cv_isprint(c) || c == '\\' || c == '\'' || c == '\"') )
  1345. {
  1346. *data++ = '\\';
  1347. if( cv_isprint(c) )
  1348. *data++ = c;
  1349. else if( c == '\n' )
  1350. *data++ = 'n';
  1351. else if( c == '\r' )
  1352. *data++ = 'r';
  1353. else if( c == '\t' )
  1354. *data++ = 't';
  1355. else
  1356. {
  1357. sprintf( data, "x%02x", c );
  1358. data += 3;
  1359. }
  1360. }
  1361. else
  1362. *data++ = c;
  1363. }
  1364. if( !need_quote && (cv_isdigit(str[0]) ||
  1365. str[0] == '+' || str[0] == '-' || str[0] == '.' ))
  1366. need_quote = 1;
  1367. if( need_quote )
  1368. *data++ = '\"';
  1369. *data++ = '\0';
  1370. data = buf + !need_quote;
  1371. }
  1372. icvYMLWrite( fs, key, data );
  1373. }
  1374. static void
  1375. icvYMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
  1376. {
  1377. int len; //, indent;
  1378. int multiline;
  1379. const char* eol;
  1380. char* ptr;
  1381. if( !comment )
  1382. CV_Error( CV_StsNullPtr, "Null comment" );
  1383. len = (int)strlen(comment);
  1384. eol = strchr(comment, '\n');
  1385. multiline = eol != 0;
  1386. ptr = fs->buffer;
  1387. if( !eol_comment || multiline ||
  1388. fs->buffer_end - ptr < len || ptr == fs->buffer_start )
  1389. ptr = icvFSFlush( fs );
  1390. else
  1391. *ptr++ = ' ';
  1392. while( comment )
  1393. {
  1394. *ptr++ = '#';
  1395. *ptr++ = ' ';
  1396. if( eol )
  1397. {
  1398. ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 );
  1399. memcpy( ptr, comment, eol - comment + 1 );
  1400. fs->buffer = ptr + (eol - comment);
  1401. comment = eol + 1;
  1402. eol = strchr( comment, '\n' );
  1403. }
  1404. else
  1405. {
  1406. len = (int)strlen(comment);
  1407. ptr = icvFSResizeWriteBuffer( fs, ptr, len );
  1408. memcpy( ptr, comment, len );
  1409. fs->buffer = ptr + len;
  1410. comment = 0;
  1411. }
  1412. ptr = icvFSFlush( fs );
  1413. }
  1414. }
  1415. /****************************************************************************************\
  1416. * XML Parser *
  1417. \****************************************************************************************/
  1418. #define CV_XML_INSIDE_COMMENT 1
  1419. #define CV_XML_INSIDE_TAG 2
  1420. #define CV_XML_INSIDE_DIRECTIVE 3
  1421. static char*
  1422. icvXMLSkipSpaces( CvFileStorage* fs, char* ptr, int mode )
  1423. {
  1424. int level = 0;
  1425. for(;;)
  1426. {
  1427. char c;
  1428. ptr--;
  1429. if( mode == CV_XML_INSIDE_COMMENT )
  1430. {
  1431. do c = *++ptr;
  1432. while( cv_isprint_or_tab(c) && (c != '-' || ptr[1] != '-' || ptr[2] != '>') );
  1433. if( c == '-' )
  1434. {
  1435. assert( ptr[1] == '-' && ptr[2] == '>' );
  1436. mode = 0;
  1437. ptr += 3;
  1438. }
  1439. }
  1440. else if( mode == CV_XML_INSIDE_DIRECTIVE )
  1441. {
  1442. // !!!NOTE!!! This is not quite correct, but should work in most cases
  1443. do
  1444. {
  1445. c = *++ptr;
  1446. level += c == '<';
  1447. level -= c == '>';
  1448. if( level < 0 )
  1449. return ptr;
  1450. } while( cv_isprint_or_tab(c) );
  1451. }
  1452. else
  1453. {
  1454. do c = *++ptr;
  1455. while( c == ' ' || c == '\t' );
  1456. if( c == '<' && ptr[1] == '!' && ptr[2] == '-' && ptr[3] == '-' )
  1457. {
  1458. if( mode != 0 )
  1459. CV_PARSE_ERROR( "Comments are not allowed here" );
  1460. mode = CV_XML_INSIDE_COMMENT;
  1461. ptr += 4;
  1462. }
  1463. else if( cv_isprint(c) )
  1464. break;
  1465. }
  1466. if( !cv_isprint(*ptr) )
  1467. {
  1468. int max_size = (int)(fs->buffer_end - fs->buffer_start);
  1469. if( *ptr != '\0' && *ptr != '\n' && *ptr != '\r' )
  1470. CV_PARSE_ERROR( "Invalid character in the stream" );
  1471. ptr = icvGets( fs, fs->buffer_start, max_size );
  1472. if( !ptr )
  1473. {
  1474. ptr = fs->buffer_start;
  1475. *ptr = '\0';
  1476. fs->dummy_eof = 1;
  1477. break;
  1478. }
  1479. else
  1480. {
  1481. int l = (int)strlen(ptr);
  1482. if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) )
  1483. CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
  1484. }
  1485. fs->lineno++;
  1486. }
  1487. }
  1488. return ptr;
  1489. }
  1490. static char*
  1491. icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
  1492. CvAttrList** _list, int* _tag_type );
  1493. static char*
  1494. icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
  1495. int value_type CV_DEFAULT(CV_NODE_NONE))
  1496. {
  1497. CvFileNode *elem = node;
  1498. int have_space = 1, is_simple = 1;
  1499. int is_user_type = CV_NODE_IS_USER(value_type);
  1500. memset( node, 0, sizeof(*node) );
  1501. value_type