PageRenderTime 188ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 2ms

/modules/core/src/persistence.cpp

https://gitlab.com/gaurav1981/opencv
C++ | 5603 lines | 4524 code | 863 blank | 216 comment | 1501 complexity | 96e5928290abefef273790c9b83e2a37 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0

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

Large files files are truncated, but you can click here to view the full file