PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/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
  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' && *ptr != '\r' )
  1520. CV_PARSE_ERROR( "Invalid character in the stream" );
  1521. ptr = icvGets( fs, fs->buffer_start, max_size );
  1522. if( !ptr )
  1523. {
  1524. ptr = fs->buffer_start;
  1525. *ptr = '\0';
  1526. fs->dummy_eof = 1;
  1527. break;
  1528. }
  1529. else
  1530. {
  1531. int l = (int)strlen(ptr);
  1532. if( ptr[l-1] != '\n' && ptr[l-1] != '\r' && !icvEof(fs) )
  1533. CV_PARSE_ERROR( "Too long string or a last string w/o newline" );
  1534. }
  1535. fs->lineno++;
  1536. }
  1537. }
  1538. return ptr;
  1539. }
  1540. static char*
  1541. icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
  1542. CvAttrList** _list, int* _tag_type );
  1543. static char*
  1544. icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
  1545. int value_type CV_DEFAULT(CV_NODE_NONE))
  1546. {
  1547. CvFileNode *elem = node;
  1548. int have_space = 1, is_simple = 1;
  1549. int is_user_type = CV_NODE_IS_USER(value_type);
  1550. memset( node, 0, sizeof(*node) );
  1551. value_type = CV_NODE_TYPE(value_type);
  1552. for(;;)
  1553. {
  1554. char c = *ptr, d;
  1555. char* endptr;
  1556. if( cv_isspace(c) || c == '\0' || (c == '<' && ptr[1] == '!' && ptr[2] == '-') )
  1557. {
  1558. ptr = icvXMLSkipSpaces( fs, ptr, 0 );
  1559. have_space = 1;
  1560. c = *ptr;
  1561. }
  1562. d = ptr[1];
  1563. if( c =='<' || c == '\0' )
  1564. {
  1565. CvStringHashNode *key = 0, *key2 = 0;
  1566. CvAttrList* list = 0;
  1567. CvTypeInfo* info = 0;
  1568. int tag_type = 0;
  1569. int is_noname = 0;
  1570. const char* type_name = 0;
  1571. int elem_type = CV_NODE_NONE;
  1572. if( d == '/' || c == '\0' )
  1573. break;
  1574. ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type );
  1575. if( tag_type == CV_XML_DIRECTIVE_TAG )
  1576. CV_PARSE_ERROR( "Directive tags are not allowed here" );
  1577. if( tag_type == CV_XML_EMPTY_TAG )
  1578. CV_PARSE_ERROR( "Empty tags are not supported" );
  1579. assert( tag_type == CV_XML_OPENING_TAG );
  1580. type_name = list ? cvAttrValue( list, "type_id" ) : 0;
  1581. if( type_name )
  1582. {
  1583. if( strcmp( type_name, "str" ) == 0 )
  1584. elem_type = CV_NODE_STRING;
  1585. else if( strcmp( type_name, "map" ) == 0 )
  1586. elem_type = CV_NODE_MAP;
  1587. else if( strcmp( type_name, "seq" ) == 0 )
  1588. elem_type = CV_NODE_SEQ;
  1589. else
  1590. {
  1591. info = cvFindType( type_name );
  1592. if( info )
  1593. elem_type = CV_NODE_USER;
  1594. }
  1595. }
  1596. is_noname = key->str.len == 1 && key->str.ptr[0] == '_';
  1597. if( !CV_NODE_IS_COLLECTION(node->tag) )
  1598. {
  1599. icvFSCreateCollection( fs, is_noname ? CV_NODE_SEQ : CV_NODE_MAP, node );
  1600. }
  1601. else if( is_noname ^ CV_NODE_IS_SEQ(node->tag) )
  1602. CV_PARSE_ERROR( is_noname ? "Map element should have a name" :
  1603. "Sequence element should not have name (use <_></_>)" );
  1604. if( is_noname )
  1605. elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
  1606. else
  1607. elem = cvGetFileNode( fs, node, key, 1 );
  1608. ptr = icvXMLParseValue( fs, ptr, elem, elem_type);
  1609. if( !is_noname )
  1610. elem->tag |= CV_NODE_NAMED;
  1611. is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
  1612. elem->info = info;
  1613. ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type );
  1614. if( tag_type != CV_XML_CLOSING_TAG || key2 != key )
  1615. CV_PARSE_ERROR( "Mismatched closing tag" );
  1616. have_space = 1;
  1617. }
  1618. else
  1619. {
  1620. if( !have_space )
  1621. CV_PARSE_ERROR( "There should be space between literals" );
  1622. elem = node;
  1623. if( node->tag != CV_NODE_NONE )
  1624. {
  1625. if( !CV_NODE_IS_COLLECTION(node->tag) )
  1626. icvFSCreateCollection( fs, CV_NODE_SEQ, node );
  1627. elem = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
  1628. elem->info = 0;
  1629. }
  1630. if( value_type != CV_NODE_STRING &&
  1631. (cv_isdigit(c) || ((c == '-' || c == '+') &&
  1632. (cv_isdigit(d) || d == '.')) || (c == '.' && cv_isalnum(d))) ) // a number
  1633. {
  1634. double fval;
  1635. int ival;
  1636. endptr = ptr + (c == '-' || c == '+');
  1637. while( cv_isdigit(*endptr) )
  1638. endptr++;
  1639. if( *endptr == '.' || *endptr == 'e' )
  1640. {
  1641. fval = icv_strtod( fs, ptr, &endptr );
  1642. /*if( endptr == ptr || cv_isalpha(*endptr) )
  1643. icvProcessSpecialDouble( fs, ptr, &fval, &endptr ));*/
  1644. elem->tag = CV_NODE_REAL;
  1645. elem->data.f = fval;
  1646. }
  1647. else
  1648. {
  1649. ival = (int)strtol( ptr, &endptr, 0 );
  1650. elem->tag = CV_NODE_INT;
  1651. elem->data.i = ival;
  1652. }
  1653. if( endptr == ptr )
  1654. CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
  1655. ptr = endptr;
  1656. }
  1657. else
  1658. {
  1659. // string
  1660. char buf[CV_FS_MAX_LEN+16];
  1661. int i = 0, len, is_quoted = 0;
  1662. elem->tag = CV_NODE_STRING;
  1663. if( c == '\"' )
  1664. is_quoted = 1;
  1665. else
  1666. --ptr;
  1667. for( ;; )
  1668. {
  1669. c = *++ptr;
  1670. if( !cv_isalnum(c) )
  1671. {
  1672. if( c == '\"' )
  1673. {
  1674. if( !is_quoted )
  1675. CV_PARSE_ERROR( "Literal \" is not allowed within a string. Use &quot;" );
  1676. ++ptr;
  1677. break;
  1678. }
  1679. else if( !cv_isprint(c) || c == '<' || (!is_quoted && cv_isspace(c)))
  1680. {
  1681. if( is_quoted )
  1682. CV_PARSE_ERROR( "Closing \" is expected" );
  1683. break;
  1684. }
  1685. else if( c == '\'' || c == '>' )
  1686. {
  1687. CV_PARSE_ERROR( "Literal \' or > are not allowed. Use &apos; or &gt;" );
  1688. }
  1689. else if( c == '&' )
  1690. {
  1691. if( *++ptr == '#' )
  1692. {
  1693. int val, base = 10;
  1694. ptr++;
  1695. if( *ptr == 'x' )
  1696. {
  1697. base = 16;
  1698. ptr++;
  1699. }
  1700. val = (int)strtol( ptr, &endptr, base );
  1701. if( (unsigned)val > (unsigned)255 ||
  1702. !endptr || *endptr != ';' )
  1703. CV_PARSE_ERROR( "Invalid numeric value in the string" );
  1704. c = (char)val;
  1705. }
  1706. else
  1707. {
  1708. endptr = ptr;
  1709. do c = *++endptr;
  1710. while( cv_isalnum(c) );
  1711. if( c != ';' )
  1712. CV_PARSE_ERROR( "Invalid character in the symbol entity name" );
  1713. len = (int)(endptr - ptr);
  1714. if( len == 2 && memcmp( ptr, "lt", len ) == 0 )
  1715. c = '<';
  1716. else if( len == 2 && memcmp( ptr, "gt", len ) == 0 )
  1717. c = '>';
  1718. else if( len == 3 && memcmp( ptr, "amp", len ) == 0 )
  1719. c = '&';
  1720. else if( len == 4 && memcmp( ptr, "apos", len ) == 0 )
  1721. c = '\'';
  1722. else if( len == 4 && memcmp( ptr, "quot", len ) == 0 )
  1723. c = '\"';
  1724. else
  1725. {
  1726. memcpy( buf + i, ptr-1, len + 2 );
  1727. i += len + 2;
  1728. }
  1729. }
  1730. ptr = endptr;
  1731. }
  1732. }
  1733. buf[i++] = c;
  1734. if( i >= CV_FS_MAX_LEN )
  1735. CV_PARSE_ERROR( "Too long string literal" );
  1736. }
  1737. elem->data.str = cvMemStorageAllocString( fs->memstorage, buf, i );
  1738. }
  1739. if( !CV_NODE_IS_COLLECTION(value_type) && value_type != CV_NODE_NONE )
  1740. break;
  1741. have_space = 0;
  1742. }
  1743. }
  1744. if( (CV_NODE_TYPE(node->tag) == CV_NODE_NONE ||
  1745. (CV_NODE_TYPE(node->tag) != value_type &&
  1746. !CV_NODE_IS_COLLECTION(node->tag))) &&
  1747. CV_NODE_IS_COLLECTION(value_type) )
  1748. {
  1749. icvFSCreateCollection( fs, CV_NODE_IS_MAP(value_type) ?
  1750. CV_NODE_MAP : CV_NODE_SEQ, node );
  1751. }
  1752. if( value_type != CV_NODE_NONE &&
  1753. value_type != CV_NODE_TYPE(node->tag) )
  1754. CV_PARSE_ERROR( "The actual type is different from the specified type" );
  1755. if( CV_NODE_IS_COLLECTION(node->tag) && is_simple )
  1756. node->data.seq->flags |= CV_NODE_SEQ_SIMPLE;
  1757. node->tag |= is_user_type ? CV_NODE_USER : 0;
  1758. return ptr;
  1759. }
  1760. static char*
  1761. icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
  1762. CvAttrList** _list, int* _tag_type )
  1763. {
  1764. int tag_type = 0;
  1765. CvStringHashNode* tagname = 0;
  1766. CvAttrList *first = 0, *last = 0;
  1767. int count = 0, max_count = 4;
  1768. int attr_buf_size = (max_count*2 + 1)*sizeof(char*) + sizeof(CvAttrList);
  1769. char* endptr;
  1770. char c;
  1771. int have_space;
  1772. if( *ptr == '\0' )
  1773. CV_PARSE_ERROR( "Preliminary end of the stream" );
  1774. if( *ptr != '<' )
  1775. CV_PARSE_ERROR( "Tag should start with \'<\'" );
  1776. ptr++;
  1777. if( cv_isalnum(*ptr) || *ptr == '_' )
  1778. tag_type = CV_XML_OPENING_TAG;
  1779. else if( *ptr == '/' )
  1780. {
  1781. tag_type = CV_XML_CLOSING_TAG;
  1782. ptr++;
  1783. }
  1784. else if( *ptr == '?' )
  1785. {
  1786. tag_type = CV_XML_HEADER_TAG;
  1787. ptr++;
  1788. }
  1789. else if( *ptr == '!' )
  1790. {
  1791. tag_type = CV_XML_DIRECTIVE_TAG;
  1792. assert( ptr[1] != '-' || ptr[2] != '-' );
  1793. ptr++;
  1794. }
  1795. else
  1796. CV_PARSE_ERROR( "Unknown tag type" );
  1797. for(;;)
  1798. {
  1799. CvStringHashNode* attrname;
  1800. if( !cv_isalpha(*ptr) && *ptr != '_' )
  1801. CV_PARSE_ERROR( "Name should start with a letter or underscore" );
  1802. endptr = ptr - 1;
  1803. do c = *++endptr;
  1804. while( cv_isalnum(c) || c == '_' || c == '-' );
  1805. attrname = cvGetHashedKey( fs, ptr, (int)(endptr - ptr), 1 );
  1806. ptr = endptr;
  1807. if( !tagname )
  1808. tagname = attrname;
  1809. else
  1810. {
  1811. if( tag_type == CV_XML_CLOSING_TAG )
  1812. CV_PARSE_ERROR( "Closing tag should not contain any attributes" );
  1813. if( !last || count >= max_count )
  1814. {
  1815. CvAttrList* chunk;
  1816. chunk = (CvAttrList*)cvMemStorageAlloc( fs->memstorage, attr_buf_size );
  1817. memset( chunk, 0, attr_buf_size );
  1818. chunk->attr = (const char**)(chunk + 1);
  1819. count = 0;
  1820. if( !last )
  1821. first = last = chunk;
  1822. else
  1823. last = last->next = chunk;
  1824. }
  1825. last->attr[count*2] = attrname->str.ptr;
  1826. }
  1827. if( last )
  1828. {
  1829. CvFileNode stub;
  1830. if( *ptr != '=' )
  1831. {
  1832. ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
  1833. if( *ptr != '=' )
  1834. CV_PARSE_ERROR( "Attribute name should be followed by \'=\'" );
  1835. }
  1836. c = *++ptr;
  1837. if( c != '\"' && c != '\'' )
  1838. {
  1839. ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
  1840. if( *ptr != '\"' && *ptr != '\'' )
  1841. CV_PARSE_ERROR( "Attribute value should be put into single or double quotes" );
  1842. }
  1843. ptr = icvXMLParseValue( fs, ptr, &stub, CV_NODE_STRING );
  1844. assert( stub.tag == CV_NODE_STRING );
  1845. last->attr[count*2+1] = stub.data.str.ptr;
  1846. count++;
  1847. }
  1848. c = *ptr;
  1849. have_space = cv_isspace(c) || c == '\0';
  1850. if( c != '>' )
  1851. {
  1852. ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
  1853. c = *ptr;
  1854. }
  1855. if( c == '>' )
  1856. {
  1857. if( tag_type == CV_XML_HEADER_TAG )
  1858. CV_PARSE_ERROR( "Invalid closing tag for <?xml ..." );
  1859. ptr++;
  1860. break;
  1861. }
  1862. else if( c == '?' && tag_type == CV_XML_HEADER_TAG )
  1863. {
  1864. if( ptr[1] != '>' )
  1865. CV_PARSE_ERROR( "Invalid closing tag for <?xml ..." );
  1866. ptr += 2;
  1867. break;
  1868. }
  1869. else if( c == '/' && ptr[1] == '>' && tag_type == CV_XML_OPENING_TAG )
  1870. {
  1871. tag_type = CV_XML_EMPTY_TAG;
  1872. ptr += 2;
  1873. break;
  1874. }
  1875. if( !have_space )
  1876. CV_PARSE_ERROR( "There should be space between attributes" );
  1877. }
  1878. *_tag = tagname;
  1879. *_tag_type = tag_type;
  1880. *_list = first;
  1881. return ptr;
  1882. }
  1883. static void
  1884. icvXMLParse( CvFileStorage* fs )
  1885. {
  1886. char* ptr = fs->buffer_start;
  1887. CvStringHashNode *key = 0, *key2 = 0;
  1888. CvAttrList* list = 0;
  1889. int tag_type = 0;
  1890. // CV_XML_INSIDE_TAG is used to prohibit leading comments
  1891. ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
  1892. if( memcmp( ptr, "<?xml", 5 ) != 0 )
  1893. CV_PARSE_ERROR( "Valid XML should start with \'<?xml ...?>\'" );
  1894. ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type );
  1895. /*{
  1896. const char* version = cvAttrValue( list, "version" );
  1897. if( version && strncmp( version, "1.", 2 ) != 0 )
  1898. CV_Error( CV_StsParseError, "Unsupported version of XML" );
  1899. }*/
  1900. // we support any 8-bit encoding, so we do not need to check the actual encoding.
  1901. // we do not support utf-16, but in the case of utf-16 we will not get here anyway.
  1902. /*{
  1903. const char* encoding = cvAttrValue( list, "encoding" );
  1904. if( encoding && strcmp( encoding, "ASCII" ) != 0 &&
  1905. strcmp( encoding, "UTF-8" ) != 0 &&
  1906. strcmp( encoding, "utf-8" ) != 0 )
  1907. CV_PARSE_ERROR( "Unsupported encoding" );
  1908. }*/
  1909. while( *ptr != '\0' )
  1910. {
  1911. ptr = icvXMLSkipSpaces( fs, ptr, 0 );
  1912. if( *ptr != '\0' )
  1913. {
  1914. CvFileNode* root_node;
  1915. ptr = icvXMLParseTag( fs, ptr, &key, &list, &tag_type );
  1916. if( tag_type != CV_XML_OPENING_TAG ||
  1917. strcmp(key->str.ptr,"opencv_storage") != 0 )
  1918. CV_PARSE_ERROR( "<opencv_storage> tag is missing" );
  1919. root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
  1920. ptr = icvXMLParseValue( fs, ptr, root_node, CV_NODE_NONE );
  1921. ptr = icvXMLParseTag( fs, ptr, &key2, &list, &tag_type );
  1922. if( tag_type != CV_XML_CLOSING_TAG || key != key2 )
  1923. CV_PARSE_ERROR( "</opencv_storage> tag is missing" );
  1924. ptr = icvXMLSkipSpaces( fs, ptr, 0 );
  1925. }
  1926. }
  1927. assert( fs->dummy_eof != 0 );
  1928. }
  1929. /****************************************************************************************\
  1930. * XML Emitter *
  1931. \****************************************************************************************/
  1932. #define icvXMLFlush icvFSFlush
  1933. static void
  1934. icvXMLWriteTag( CvFileStorage* fs, const char* key, int tag_type, CvAttrList list )
  1935. {
  1936. char* ptr = fs->buffer;
  1937. int i, len = 0;
  1938. int struct_flags = fs->struct_flags;
  1939. if( key && key[0] == '\0' )
  1940. key = 0;
  1941. if( tag_type == CV_XML_OPENING_TAG || tag_type == CV_XML_EMPTY_TAG )
  1942. {
  1943. if( CV_NODE_IS_COLLECTION(struct_flags) )
  1944. {
  1945. if( CV_NODE_IS_MAP(struct_flags) ^ (key != 0) )
  1946. CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
  1947. "or add element with key to sequence" );
  1948. }
  1949. else
  1950. {
  1951. struct_flags = CV_NODE_EMPTY + (key ? CV_NODE_MAP : CV_NODE_SEQ);
  1952. fs->is_first = 0;
  1953. }
  1954. if( !CV_NODE_IS_EMPTY(struct_flags) )
  1955. ptr = icvXMLFlush(fs);
  1956. }
  1957. if( !key )
  1958. key = "_";
  1959. else if( key[0] == '_' && key[1] == '\0' )
  1960. CV_Error( CV_StsBadArg, "A single _ is a reserved tag name" );
  1961. len = (int)strlen( key );
  1962. *ptr++ = '<';
  1963. if( tag_type == CV_XML_CLOSING_TAG )
  1964. {
  1965. if( list.attr )
  1966. CV_Error( CV_StsBadArg, "Closing tag should not include any attributes" );
  1967. *ptr++ = '/';
  1968. }
  1969. if( !cv_isalpha(key[0]) && key[0] != '_' )
  1970. CV_Error( CV_StsBadArg, "Key should start with a letter or _" );
  1971. ptr = icvFSResizeWriteBuffer( fs, ptr, len );
  1972. for( i = 0; i < len; i++ )
  1973. {
  1974. char c = key[i];
  1975. if( !cv_isalnum(c) && c != '_' && c != '-' )
  1976. CV_Error( CV_StsBadArg, "Key name may only contain alphanumeric characters [a-zA-Z0-9], '-' and '_'" );
  1977. ptr[i] = c;
  1978. }
  1979. ptr += len;
  1980. for(;;)
  1981. {
  1982. const char** attr = list.attr;
  1983. for( ; attr && attr[0] != 0; attr += 2 )
  1984. {
  1985. int len0 = (int)strlen(attr[0]);
  1986. int len1 = (int)strlen(attr[1]);
  1987. ptr = icvFSResizeWriteBuffer( fs, ptr, len0 + len1 + 4 );
  1988. *ptr++ = ' ';
  1989. memcpy( ptr, attr[0], len0 );
  1990. ptr += len0;
  1991. *ptr++ = '=';
  1992. *ptr++ = '\"';
  1993. memcpy( ptr, attr[1], len1 );
  1994. ptr += len1;
  1995. *ptr++ = '\"';
  1996. }
  1997. if( !list.next )
  1998. break;
  1999. list = *list.next;
  2000. }
  2001. if( tag_type == CV_XML_EMPTY_TAG )
  2002. *ptr++ = '/';
  2003. *ptr++ = '>';
  2004. fs->buffer = ptr;
  2005. fs->struct_flags = struct_flags & ~CV_NODE_EMPTY;
  2006. }
  2007. static void
  2008. icvXMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
  2009. const char* type_name CV_DEFAULT(0))
  2010. {
  2011. CvXMLStackRecord parent;
  2012. const char* attr[10];
  2013. int idx = 0;
  2014. struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
  2015. if( !CV_NODE_IS_COLLECTION(struct_flags))
  2016. CV_Error( CV_StsBadArg,
  2017. "Some collection type: CV_NODE_SEQ or CV_NODE_MAP must be specified" );
  2018. if( type_name )
  2019. {
  2020. attr[idx++] = "type_id";
  2021. attr[idx++] = type_name;
  2022. }
  2023. attr[idx++] = 0;
  2024. icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(attr,0) );
  2025. parent.struct_flags = fs->struct_flags & ~CV_NODE_EMPTY;
  2026. parent.struct_indent = fs->struct_indent;
  2027. parent.struct_tag = fs->struct_tag;
  2028. cvSaveMemStoragePos( fs->strstorage, &parent.pos );
  2029. cvSeqPush( fs->write_stack, &parent );
  2030. fs->struct_indent += CV_XML_INDENT;
  2031. if( !CV_NODE_IS_FLOW(struct_flags) )
  2032. icvXMLFlush( fs );
  2033. fs->struct_flags = struct_flags;
  2034. if( key )
  2035. {
  2036. fs->struct_tag = cvMemStorageAllocString( fs->strstorage, (char*)key, -1 );
  2037. }
  2038. else
  2039. {
  2040. fs->struct_tag.ptr = 0;
  2041. fs->struct_tag.len = 0;
  2042. }
  2043. }
  2044. static void
  2045. icvXMLEndWriteStruct( CvFileStorage* fs )
  2046. {
  2047. CvXMLStackRecord parent;
  2048. if( fs->write_stack->total == 0 )
  2049. CV_Error( CV_StsError, "An extra closing tag" );
  2050. icvXMLWriteTag( fs, fs->struct_tag.ptr, CV_XML_CLOSING_TAG, cvAttrList(0,0) );
  2051. cvSeqPop( fs->write_stack, &parent );
  2052. fs->struct_indent = parent.struct_indent;
  2053. fs->struct_flags = parent.struct_flags;
  2054. fs->struct_tag = parent.struct_tag;
  2055. cvRestoreMemStoragePos( fs->strstorage, &parent.pos );
  2056. }
  2057. static void
  2058. icvXMLStartNextStream( CvFileStorage* fs )
  2059. {
  2060. if( !fs->is_first )
  2061. {
  2062. while( fs->write_stack->total > 0 )
  2063. icvXMLEndWriteStruct(fs);
  2064. fs->struct_indent = 0;
  2065. icvXMLFlush(fs);
  2066. /* XML does not allow multiple top-level elements,
  2067. so we just put a comment and continue
  2068. the current (and the only) "stream" */
  2069. icvPuts( fs, "\n<!-- next stream -->\n" );
  2070. /*fputs( "</opencv_storage>\n", fs->file );
  2071. fputs( "<opencv_storage>\n", fs->file );*/
  2072. fs->buffer = fs->buffer_start;
  2073. }
  2074. }
  2075. static void
  2076. icvXMLWriteScalar( CvFileStorage* fs, const char* key, const char* data, int len )
  2077. {
  2078. if( CV_NODE_IS_MAP(fs->struct_flags) ||
  2079. (!CV_NODE_IS_COLLECTION(fs->struct_flags) && key) )
  2080. {
  2081. icvXMLWriteTag( fs, key, CV_XML_OPENING_TAG, cvAttrList(0,0) );
  2082. char* ptr = icvFSResizeWriteBuffer( fs, fs->buffer, len );
  2083. memcpy( ptr, data, len );
  2084. fs->buffer = ptr + len;
  2085. icvXMLWriteTag( fs, key, CV_XML_CLOSING_TAG, cvAttrList(0,0) );
  2086. }
  2087. else
  2088. {
  2089. char* ptr = fs->buffer;
  2090. int new_offset = (int)(ptr - fs->buffer_start) + len;
  2091. if( key )
  2092. CV_Error( CV_StsBadArg, "elements with keys can not be written to sequence" );
  2093. fs->struct_flags = CV_NODE_SEQ;
  2094. if( (new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10) ||
  2095. (ptr > fs->buffer_start && ptr[-1] == '>' && !CV_NODE_IS_EMPTY(fs->struct_flags)) )
  2096. {
  2097. ptr = icvXMLFlush(fs);
  2098. }
  2099. else if( ptr > fs->buffer_start + fs->struct_indent && ptr[-1] != '>' )
  2100. *ptr++ = ' ';
  2101. memcpy( ptr, data, len );
  2102. fs->buffer = ptr + len;
  2103. }
  2104. }
  2105. static void
  2106. icvXMLWriteInt( CvFileStorage* fs, const char* key, int value )
  2107. {
  2108. char buf[128], *ptr = icv_itoa( value, buf, 10 );
  2109. int len = (int)strlen(ptr);
  2110. icvXMLWriteScalar( fs, key, ptr, len );
  2111. }
  2112. static void
  2113. icvXMLWriteReal( CvFileStorage* fs, const char* key, double value )
  2114. {
  2115. char buf[128];
  2116. int len = (int)strlen( icvDoubleToString( buf, value ));
  2117. icvXMLWriteScalar( fs, key, buf, len );
  2118. }
  2119. static void
  2120. icvXMLWriteString( CvFileStorage* fs, const char* key, const char* str, int quote )
  2121. {
  2122. char buf[CV_FS_MAX_LEN*6+16];
  2123. char* data = (char*)str;
  2124. int i, len;
  2125. if( !str )
  2126. CV_Error( CV_StsNullPtr, "Null string pointer" );
  2127. len = (int)strlen(str);
  2128. if( len > CV_FS_MAX_LEN )
  2129. CV_Error( CV_StsBadArg, "The written string is too long" );
  2130. if( quote || len == 0 || str[0] != '\"' || str[0] != str[len-1] )
  2131. {
  2132. int need_quote = quote || len == 0;
  2133. data = buf;
  2134. *data++ = '\"';
  2135. for( i = 0; i < len; i++ )
  2136. {
  2137. char c = str[i];
  2138. if( (uchar)c >= 128 || c == ' ' )
  2139. {
  2140. *data++ = c;
  2141. need_quote = 1;
  2142. }
  2143. else if( !cv_isprint(c) || c == '<' || c == '>' || c == '&' || c == '\'' || c == '\"' )
  2144. {
  2145. *data++ = '&';
  2146. if( c == '<' )
  2147. {
  2148. memcpy(data, "lt", 2);
  2149. data += 2;
  2150. }
  2151. else if( c == '>' )
  2152. {
  2153. memcpy(data, "gt", 2);
  2154. data += 2;
  2155. }
  2156. else if( c == '&' )
  2157. {
  2158. memcpy(data, "amp", 3);
  2159. data += 3;
  2160. }
  2161. else if( c == '\'' )
  2162. {
  2163. memcpy(data, "apos", 4);
  2164. data += 4;
  2165. }
  2166. else if( c == '\"' )
  2167. {
  2168. memcpy( data, "quot", 4);
  2169. data += 4;
  2170. }
  2171. else
  2172. {
  2173. sprintf( data, "#x%02x", (uchar)c );
  2174. data += 4;
  2175. }
  2176. *data++ = ';';
  2177. need_quote = 1;
  2178. }
  2179. else
  2180. *data++ = c;
  2181. }
  2182. if( !need_quote && (cv_isdigit(str[0]) ||
  2183. str[0] == '+' || str[0] == '-' || str[0] == '.' ))
  2184. need_quote = 1;
  2185. if( need_quote )
  2186. *data++ = '\"';
  2187. len = (int)(data - buf) - !need_quote;
  2188. *data++ = '\0';
  2189. data = buf + !need_quote;
  2190. }
  2191. icvXMLWriteScalar( fs, key, data, len );
  2192. }
  2193. static void
  2194. icvXMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
  2195. {
  2196. int len;
  2197. int multiline;
  2198. const char* eol;
  2199. char* ptr;
  2200. if( !comment )
  2201. CV_Error( CV_StsNullPtr, "Null comment" );
  2202. if( strstr(comment, "--") != 0 )
  2203. CV_Error( CV_StsBadArg, "Double hyphen \'--\' is not allowed in the comments" );
  2204. len = (int)strlen(comment);
  2205. eol = strchr(comment, '\n');
  2206. multiline = eol != 0;
  2207. ptr = fs->buffer;
  2208. if( multiline || !eol_comment || fs->buffer_end - ptr < len + 5 )
  2209. ptr = icvXMLFlush( fs );
  2210. else if( ptr > fs->buffer_start + fs->struct_indent )
  2211. *ptr++ = ' ';
  2212. if( !multiline )
  2213. {
  2214. ptr = icvFSResizeWriteBuffer( fs, ptr, len + 9 );
  2215. sprintf( ptr, "<!-- %s -->", comment );
  2216. len = (int)strlen(ptr);
  2217. }
  2218. else
  2219. {
  2220. strcpy( ptr, "<!--" );
  2221. len = 4;
  2222. }
  2223. fs->buffer = ptr + len;
  2224. ptr = icvXMLFlush(fs);
  2225. if( multiline )
  2226. {
  2227. while( comment )
  2228. {
  2229. if( eol )
  2230. {
  2231. ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 );
  2232. memcpy( ptr, comment, eol - comment + 1 );
  2233. ptr += eol - comment;
  2234. comment = eol + 1;
  2235. eol = strchr( comment, '\n' );
  2236. }
  2237. else
  2238. {
  2239. len = (int)strlen(comment);
  2240. ptr = icvFSResizeWriteBuffer( fs, ptr, len );
  2241. memcpy( ptr, comment, len );
  2242. ptr += len;
  2243. comment = 0;
  2244. }
  2245. fs->buffer = ptr;
  2246. ptr = icvXMLFlush( fs );
  2247. }
  2248. sprintf( ptr, "-->" );
  2249. fs->buffer = ptr + 3;
  2250. icvXMLFlush( fs );
  2251. }
  2252. }
  2253. /****************************************************************************************\
  2254. * Common High-Level Functions *
  2255. \****************************************************************************************/
  2256. CV_IMPL CvFileStorage*
  2257. cvOpenFileStorage( const char* filename, CvMemStorage* dststorage, int flags, const char* encoding )
  2258. {
  2259. CvFileStorage* fs = 0;
  2260. char* xml_buf = 0;
  2261. int default_block_size = 1 << 18;
  2262. bool append = (flags & 3) == CV_STORAGE_APPEND;
  2263. bool mem = (flags & CV_STORAGE_MEMORY) != 0;
  2264. bool write_mode = (flags & 3) != 0;
  2265. bool isGZ = false;
  2266. size_t fnamelen = 0;
  2267. if( !filename || filename[0] == '\0' )
  2268. {
  2269. if( !write_mode )
  2270. CV_Error( CV_StsNullPtr, mem ? "NULL or empty filename" : "NULL or empty buffer" );
  2271. mem = true;
  2272. }
  2273. else
  2274. fnamelen = strlen(filename);
  2275. if( mem && append )
  2276. CV_Error( CV_StsBadFlag, "CV_STORAGE_APPEND and CV_STORAGE_MEMORY are not currently compatible" );
  2277. fs = (CvFileStorage*)cvAlloc( sizeof(*fs) );
  2278. memset( fs, 0, sizeof(*fs));
  2279. fs->memstorage = cvCreateMemStorage( default_block_size );
  2280. fs->dststorage = dststorage ? dststorage : fs->memstorage;
  2281. fs->flags = CV_FILE_STORAGE;
  2282. fs->write_mode = write_mode;
  2283. if( !mem )
  2284. {
  2285. fs->filename = (char*)cvMemStorageAlloc( fs->memstorage, fnamelen+1 );
  2286. strcpy( fs->filename, filename );
  2287. char* dot_pos = strrchr(fs->filename, '.');
  2288. char compression = '\0';
  2289. if( dot_pos && dot_pos[1] == 'g' && dot_pos[2] == 'z' &&
  2290. (dot_pos[3] == '\0' || (cv_isdigit(dot_pos[3]) && dot_pos[4] == '\0')) )
  2291. {
  2292. if( append )
  2293. CV_Error(CV_StsNotImplemented, "Appending data to compressed file is not implemented" );
  2294. isGZ = true;
  2295. compression = dot_pos[3];
  2296. if( compression )
  2297. dot_pos[3] = '\0', fnamelen--;
  2298. }
  2299. if( !isGZ )
  2300. {
  2301. fs->file = fopen(fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" );
  2302. if( !fs->file )
  2303. goto _exit_;
  2304. }
  2305. else
  2306. {
  2307. #if USE_ZLIB
  2308. char mode[] = { fs->write_mode ? 'w' : 'r', 'b', compression ? compression : '3', '\0' };
  2309. fs->gzfile = gzopen(fs->filename, mode);
  2310. if( !fs->gzfile )
  2311. goto _exit_;
  2312. #else
  2313. CV_Error(CV_StsNotImplemented, "There is no compressed file storage support in this configuration");
  2314. #endif
  2315. }
  2316. }
  2317. fs->roots = 0;
  2318. fs->struct_indent = 0;
  2319. fs->struct_flags = 0;
  2320. fs->wrap_margin = 71;
  2321. if( fs->write_mode )
  2322. {
  2323. int fmt = flags & CV_STORAGE_FORMAT_MASK;
  2324. if( mem )
  2325. fs->outbuf = new std::deque<char>;
  2326. if( fmt == CV_STORAGE_FORMAT_AUTO && filename )
  2327. {
  2328. const char* dot_pos = filename + fnamelen - (isGZ ? 7 : 4);
  2329. fs->fmt = (dot_pos >= filename && (memcmp( dot_pos, ".xml", 4) == 0 ||
  2330. memcmp(dot_pos, ".XML", 4) == 0 || memcmp(dot_pos, ".Xml", 4) == 0)) ?
  2331. CV_STORAGE_FORMAT_XML : CV_STORAGE_FORMAT_YAML;
  2332. }
  2333. else
  2334. fs->fmt = fmt != CV_STORAGE_FORMAT_AUTO ? fmt : CV_STORAGE_FORMAT_XML;
  2335. // we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (&apos; and &quot;)
  2336. // and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB))
  2337. int buf_size = CV_FS_MAX_LEN*(fs->fmt == CV_STORAGE_FORMAT_XML ? 6 : 4) + 1024;
  2338. if( append )
  2339. fseek( fs->file, 0, SEEK_END );
  2340. fs->write_stack = cvCreateSeq( 0, sizeof(CvSeq), fs->fmt == CV_STORAGE_FORMAT_XML ?
  2341. sizeof(CvXMLStackRecord) : sizeof(int), fs->memstorage );
  2342. fs->is_first = 1;
  2343. fs->struct_indent = 0;
  2344. fs->struct_flags = CV_NODE_EMPTY;
  2345. fs->buffer_start = fs->buffer = (char*)cvAlloc( buf_size + 1024 );
  2346. fs->buffer_end = fs->buffer_start + buf_size;
  2347. if( fs->fmt == CV_STORAGE_FORMAT_XML )
  2348. {
  2349. size_t file_size = fs->file ? (size_t)ftell( fs->file ) : (size_t)0;
  2350. fs->strstorage = cvCreateChildMemStorage( fs->memstorage );
  2351. if( !append || file_size == 0 )
  2352. {
  2353. if( encoding )
  2354. {
  2355. if( strcmp( encoding, "UTF-16" ) == 0 ||
  2356. strcmp( encoding, "utf-16" ) == 0 ||
  2357. strcmp( encoding, "Utf-16" ) == 0 )
  2358. CV_Error( CV_StsBadArg, "UTF-16 XML encoding is not supported! Use 8-bit encoding\n");
  2359. CV_Assert( strlen(encoding) < 1000 );
  2360. char buf[1100];
  2361. sprintf(buf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding);
  2362. icvPuts( fs, buf );
  2363. }
  2364. else
  2365. icvPuts( fs, "<?xml version=\"1.0\"?>\n" );
  2366. icvPuts( fs, "<opencv_storage>\n" );
  2367. }
  2368. else
  2369. {
  2370. int xml_buf_size = 1 << 10;
  2371. char substr[] = "</opencv_storage>";
  2372. int last_occurence = -1;
  2373. xml_buf_size = MIN(xml_buf_size, int(file_size));
  2374. fseek( fs->file, -xml_buf_size, SEEK_END );
  2375. xml_buf = (char*)cvAlloc( xml_buf_size+2 );
  2376. // find the last occurence of </opencv_storage>
  2377. for(;;)
  2378. {
  2379. int line_offset = ftell( fs->file );
  2380. char* ptr0 = icvGets( fs, xml_buf, xml_buf_size ), *ptr;
  2381. if( !ptr0 )
  2382. break;
  2383. ptr = ptr0;
  2384. for(;;)
  2385. {
  2386. ptr = strstr( ptr, substr );
  2387. if( !ptr )
  2388. break;
  2389. last_occurence = line_offset + (int)(ptr - ptr0);
  2390. ptr += strlen(substr);
  2391. }
  2392. }
  2393. if( last_occurence < 0 )
  2394. CV_Error( CV_StsError, "Could not find </opencv_storage> in the end of file.\n" );
  2395. icvCloseFile( fs );
  2396. fs->file = fopen( fs->filename, "r+t" );
  2397. fseek( fs->file, last_occurence, SEEK_SET );
  2398. // replace the last "</opencv_storage>" with " <!-- resumed -->", which has the same length
  2399. icvPuts( fs, " <!-- resumed -->" );
  2400. fseek( fs->file, 0, SEEK_END );
  2401. icvPuts( fs, "\n" );
  2402. }
  2403. fs->start_write_struct = icvXMLStartWriteStruct;
  2404. fs->end_write_struct = icvXMLEndWriteStruct;
  2405. fs->write_int = icvXMLWriteInt;
  2406. fs->write_real = icvXMLWriteReal;
  2407. fs->write_string = icvXMLWriteString;
  2408. fs->write_comment = icvXMLWriteComment;
  2409. fs->start_next_stream = icvXMLStartNextStream;
  2410. }
  2411. else
  2412. {
  2413. if( !append )
  2414. icvPuts( fs, "%YAML:1.0\n" );
  2415. else
  2416. icvPuts( fs, "...\n---\n" );
  2417. fs->start_write_struct = icvYMLStartWriteStruct;
  2418. fs->end_write_struct = icvYMLEndWriteStruct;
  2419. fs->write_int = icvYMLWriteInt;
  2420. fs->write_real = icvYMLWriteReal;
  2421. fs->write_string = icvYMLWriteString;
  2422. fs->write_comment = icvYMLWriteComment;
  2423. fs->start_next_stream = icvYMLStartNextStream;
  2424. }
  2425. }
  2426. else
  2427. {
  2428. if( mem )
  2429. {
  2430. fs->strbuf = filename;
  2431. fs->strbufsize = fnamelen;
  2432. }
  2433. size_t buf_size = 1 << 20;
  2434. const char* yaml_signature = "%YAML:";
  2435. char buf[16];
  2436. icvGets( fs, buf, sizeof(buf)-2 );
  2437. fs->fmt = strncmp( buf, yaml_signature, strlen(yaml_signature) ) == 0 ?
  2438. CV_STORAGE_FORMAT_YAML : CV_STORAGE_FORMAT_XML;
  2439. if( !isGZ )
  2440. {
  2441. if( !mem )
  2442. {
  2443. fseek( fs->file, 0, SEEK_END );
  2444. buf_size = ftell( fs->file );
  2445. }
  2446. else
  2447. buf_size = fs->strbufsize;
  2448. buf_size = MIN( buf_size, (size_t)(1 << 20) );
  2449. buf_size = MAX( buf_size, (size_t)(CV_FS_MAX_LEN*2 + 1024) );
  2450. }
  2451. icvRewind(fs);
  2452. fs->str_hash = cvCreateMap( 0, sizeof(CvStringHash),
  2453. sizeof(CvStringHashNode), fs->memstorage, 256 );
  2454. fs->roots = cvCreateSeq( 0, sizeof(CvSeq),
  2455. sizeof(CvFileNode), fs->memstorage );
  2456. fs->buffer = fs->buffer_start = (char*)cvAlloc( buf_size + 256 );
  2457. fs->buffer_end = fs->buffer_start + buf_size;
  2458. fs->buffer[0] = '\n';
  2459. fs->buffer[1] = '\0';
  2460. //mode = cvGetErrMode();
  2461. //cvSetErrMode( CV_ErrModeSilent );
  2462. if( fs->fmt == CV_STORAGE_FORMAT_XML )
  2463. icvXMLParse( fs );
  2464. else
  2465. icvYMLParse( fs );
  2466. //cvSetErrMode( mode );
  2467. // release resources that we do not need anymore
  2468. cvFree( &fs->buffer_start );
  2469. fs->buffer = fs->buffer_end = 0;
  2470. }
  2471. fs->is_opened = true;
  2472. _exit_:
  2473. if( fs )
  2474. {
  2475. if( cvGetErrStatus() < 0 || (!fs->file && !fs->gzfile && !fs->outbuf && !fs->strbuf) )
  2476. {
  2477. cvReleaseFileStorage( &fs );
  2478. }
  2479. else if( !fs->write_mode )
  2480. {
  2481. icvCloseFile(fs);
  2482. // we close the file since it's not needed anymore. But icvCloseFile() resets is_opened,
  2483. // which may be misleading. Since we restore the value of is_opened.
  2484. fs->is_opened = true;
  2485. }
  2486. }
  2487. cvFree( &xml_buf );
  2488. return fs;
  2489. }
  2490. CV_IMPL void
  2491. cvStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
  2492. const char* type_name, CvAttrList /*attributes*/ )
  2493. {
  2494. CV_CHECK_OUTPUT_FILE_STORAGE(fs);
  2495. fs->start_write_struct( fs, key, struct_flags, type_name );
  2496. }
  2497. CV_IMPL void
  2498. cvEndWriteStruct( CvFileStorage* fs )
  2499. {
  2500. CV_CHECK_OUTPUT_FILE_STORAGE(fs);
  2501. fs->end_write_struct( fs );
  2502. }
  2503. CV_IMPL void
  2504. cvWriteInt( CvFileStorage* fs, const char* key, int value )
  2505. {
  2506. CV_CHECK_OUTPUT_FILE_STORAGE(fs);
  2507. fs->write_int( fs, key, value );
  2508. }
  2509. CV_IMPL void
  2510. cvWriteReal( CvFileStorage* fs, const char* key, double value )
  2511. {
  2512. CV_CHECK_OUTPUT_FILE_STORAGE(fs);
  2513. fs->write_real( fs, key, value );
  2514. }
  2515. CV_IMPL void
  2516. cvWriteString( CvFileStorage* fs, const char* key, const char* value, int quote )
  2517. {
  2518. CV_CHECK_OUTPUT_FILE_STORAGE(fs);
  2519. fs->write_string( fs, key, value, quote );
  2520. }
  2521. CV_IMPL void
  2522. cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
  2523. {
  2524. CV_CHECK_OUTPUT_FILE_STORAGE(fs);
  2525. fs->write_comment( fs, comment, eol_comment );
  2526. }
  2527. CV_IMPL void
  2528. cvStartNextStream( CvFileStorage* fs )
  2529. {
  2530. CV_CHECK_OUTPUT_FILE_STORAGE(fs);
  2531. fs->start_next_stream( fs );
  2532. }
  2533. static const char icvTypeSymbol[] = "ucwsifdr";
  2534. #define CV_FS_MAX_FMT_PAIRS 128
  2535. static char*
  2536. icvEncodeFormat( int elem_type, char* dt )
  2537. {
  2538. sprintf( dt, "%d%c", CV_MAT_CN(elem_type), icvTypeSymbol[CV_MAT_DEPTH(elem_type)] );
  2539. return dt + ( dt[2] == '\0' && dt[0] == '1' );
  2540. }
  2541. static int
  2542. icvDecodeFormat( const char* dt, int* fmt_pairs, int max_len )
  2543. {
  2544. int fmt_pair_count = 0;
  2545. int i = 0, k = 0, len = dt ? (int)strlen(dt) : 0;
  2546. if( !dt || !len )
  2547. return 0;
  2548. assert( fmt_pairs != 0 && max_len > 0 );
  2549. fmt_pairs[0] = 0;
  2550. max_len *= 2;
  2551. for( ; k < len; k++ )
  2552. {
  2553. char c = dt[k];
  2554. if( cv_isdigit(c) )
  2555. {
  2556. int count = c - '0';
  2557. if( cv_isdigit(dt[k+1]) )
  2558. {
  2559. char* endptr = 0;
  2560. count = (int)strtol( dt+k, &endptr, 10 );
  2561. k = (int)(endptr - dt) - 1;
  2562. }
  2563. if( count <= 0 )
  2564. CV_Error( CV_StsBadArg, "Invalid data type specification" );
  2565. fmt_pairs[i] = count;
  2566. }
  2567. else
  2568. {
  2569. const char* pos = strchr( icvTypeSymbol, c );
  2570. if( !pos )
  2571. CV_Error( CV_StsBadArg, "Invalid data type specification" );
  2572. if( fmt_pairs[i] == 0 )
  2573. fmt_pairs[i] = 1;
  2574. fmt_pairs[i+1] = (int)(pos - icvTypeSymbol);
  2575. if( i > 0 && fmt_pairs[i+1] == fmt_pairs[i-1] )
  2576. fmt_pairs[i-2] += fmt_pairs[i];
  2577. else
  2578. {
  2579. i += 2;
  2580. if( i >= max_len )
  2581. CV_Error( CV_StsBadArg, "Too long data type specification" );
  2582. }
  2583. fmt_pairs[i] = 0;
  2584. }
  2585. }
  2586. fmt_pair_count = i/2;
  2587. return fmt_pair_count;
  2588. }
  2589. static int
  2590. icvCalcElemSize( const char* dt, int initial_size )
  2591. {
  2592. int size = 0;
  2593. int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
  2594. int comp_size;
  2595. fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
  2596. fmt_pair_count *= 2;
  2597. for( i = 0, size = initial_size; i < fmt_pair_count; i += 2 )
  2598. {
  2599. comp_size = CV_ELEM_SIZE(fmt_pairs[i+1]);
  2600. size = cvAlign( size, comp_size );
  2601. size += comp_size * fmt_pairs[i];
  2602. }
  2603. if( initial_size == 0 )
  2604. {
  2605. comp_size = CV_ELEM_SIZE(fmt_pairs[1]);
  2606. size = cvAlign( size, comp_size );
  2607. }
  2608. return size;
  2609. }
  2610. static int
  2611. icvDecodeSimpleFormat( const char* dt )
  2612. {
  2613. int elem_type = -1;
  2614. int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
  2615. fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
  2616. if( fmt_pair_count != 1 || fmt_pairs[0] > 4 )
  2617. CV_Error( CV_StsError, "Too complex format for the matrix" );
  2618. elem_type = CV_MAKETYPE( fmt_pairs[1], fmt_pairs[0] );
  2619. return elem_type;
  2620. }
  2621. CV_IMPL void
  2622. cvWriteRawData( CvFileStorage* fs, const void* _data, int len, const char* dt )
  2623. {
  2624. const char* data0 = (const char*)_data;
  2625. int offset = 0;
  2626. int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k, fmt_pair_count;
  2627. char buf[256] = "";
  2628. CV_CHECK_OUTPUT_FILE_STORAGE( fs );
  2629. if( len < 0 )
  2630. CV_Error( CV_StsOutOfRange, "Negative number of elements" );
  2631. fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
  2632. if( !len )
  2633. return;
  2634. if( !data0 )
  2635. CV_Error( CV_StsNullPtr, "Null data pointer" );
  2636. if( fmt_pair_count == 1 )
  2637. {
  2638. fmt_pairs[0] *= len;
  2639. len = 1;
  2640. }
  2641. for(;len--;)
  2642. {
  2643. for( k = 0; k < fmt_pair_count; k++ )
  2644. {
  2645. int i, count = fmt_pairs[k*2];
  2646. int elem_type = fmt_pairs[k*2+1];
  2647. int elem_size = CV_ELEM_SIZE(elem_type);
  2648. const char* data, *ptr;
  2649. offset = cvAlign( offset, elem_size );
  2650. data = data0 + offset;
  2651. for( i = 0; i < count; i++ )
  2652. {
  2653. switch( elem_type )
  2654. {
  2655. case CV_8U:
  2656. ptr = icv_itoa( *(uchar*)data, buf, 10 );
  2657. data++;
  2658. break;
  2659. case CV_8S:
  2660. ptr = icv_itoa( *(char*)data, buf, 10 );
  2661. data++;
  2662. break;
  2663. case CV_16U:
  2664. ptr = icv_itoa( *(ushort*)data, buf, 10 );
  2665. data += sizeof(ushort);
  2666. break;
  2667. case CV_16S:
  2668. ptr = icv_itoa( *(short*)data, buf, 10 );
  2669. data += sizeof(short);
  2670. break;
  2671. case CV_32S:
  2672. ptr = icv_itoa( *(int*)data, buf, 10 );
  2673. data += sizeof(int);
  2674. break;
  2675. case CV_32F:
  2676. ptr = icvFloatToString( buf, *(float*)data );
  2677. data += sizeof(float);
  2678. break;
  2679. case CV_64F:
  2680. ptr = icvDoubleToString( buf, *(double*)data );
  2681. data += sizeof(double);
  2682. break;
  2683. case CV_USRTYPE1: /* reference */
  2684. ptr = icv_itoa( (int)*(size_t*)data, buf, 10 );
  2685. data += sizeof(size_t);
  2686. break;
  2687. default:
  2688. assert(0);
  2689. return;
  2690. }
  2691. if( fs->fmt == CV_STORAGE_FORMAT_XML )
  2692. {
  2693. int buf_len = (int)strlen(ptr);
  2694. icvXMLWriteScalar( fs, 0, ptr, buf_len );
  2695. }
  2696. else
  2697. icvYMLWrite( fs, 0, ptr );
  2698. }
  2699. offset = (int)(data - data0);
  2700. }
  2701. }
  2702. }
  2703. CV_IMPL void
  2704. cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, CvSeqReader* reader )
  2705. {
  2706. int node_type;
  2707. CV_CHECK_FILE_STORAGE( fs );
  2708. if( !src || !reader )
  2709. CV_Error( CV_StsNullPtr, "Null pointer to source file node or reader" );
  2710. node_type = CV_NODE_TYPE(src->tag);
  2711. if( node_type == CV_NODE_INT || node_type == CV_NODE_REAL )
  2712. {
  2713. // emulate reading from 1-element sequence
  2714. reader->ptr = (schar*)src;
  2715. reader->block_max = reader->ptr + sizeof(*src)*2;
  2716. reader->block_min = reader->ptr;
  2717. reader->seq = 0;
  2718. }
  2719. else if( node_type == CV_NODE_SEQ )
  2720. {
  2721. cvStartReadSeq( src->data.seq, reader, 0 );
  2722. }
  2723. else if( node_type == CV_NODE_NONE )
  2724. {
  2725. memset( reader, 0, sizeof(*reader) );
  2726. }
  2727. else
  2728. CV_Error( CV_StsBadArg, "The file node should be a numerical scalar or a sequence" );
  2729. }
  2730. CV_IMPL void
  2731. cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader,
  2732. int len, void* _data, const char* dt )
  2733. {
  2734. char* data0 = (char*)_data;
  2735. int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k = 0, fmt_pair_count;
  2736. int i = 0, offset = 0, count = 0;
  2737. CV_CHECK_FILE_STORAGE( fs );
  2738. if( !reader || !data0 )
  2739. CV_Error( CV_StsNullPtr, "Null pointer to reader or destination array" );
  2740. if( !reader->seq && len != 1 )
  2741. CV_Error( CV_StsBadSize, "The readed sequence is a scalar, thus len must be 1" );
  2742. fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
  2743. for(;;)
  2744. {
  2745. for( k = 0; k < fmt_pair_count; k++ )
  2746. {
  2747. int elem_type = fmt_pairs[k*2+1];
  2748. int elem_size = CV_ELEM_SIZE(elem_type);
  2749. char* data;
  2750. count = fmt_pairs[k*2];
  2751. offset = cvAlign( offset, elem_size );
  2752. data = data0 + offset;
  2753. for( i = 0; i < count; i++ )
  2754. {
  2755. CvFileNode* node = (CvFileNode*)reader->ptr;
  2756. if( CV_NODE_IS_INT(node->tag) )
  2757. {
  2758. int ival = node->data.i;
  2759. switch( elem_type )
  2760. {
  2761. case CV_8U:
  2762. *(uchar*)data = cv::saturate_cast<uchar>(ival);
  2763. data++;
  2764. break;
  2765. case CV_8S:
  2766. *(char*)data = cv::saturate_cast<schar>(ival);
  2767. data++;
  2768. break;
  2769. case CV_16U:
  2770. *(ushort*)data = cv::saturate_cast<ushort>(ival);
  2771. data += sizeof(ushort);
  2772. break;
  2773. case CV_16S:
  2774. *(short*)data = cv::saturate_cast<short>(ival);
  2775. data += sizeof(short);
  2776. break;
  2777. case CV_32S:
  2778. *(int*)data = ival;
  2779. data += sizeof(int);
  2780. break;
  2781. case CV_32F:
  2782. *(float*)data = (float)ival;
  2783. data += sizeof(float);
  2784. break;
  2785. case CV_64F:
  2786. *(double*)data = (double)ival;
  2787. data += sizeof(double);
  2788. break;
  2789. case CV_USRTYPE1: /* reference */
  2790. *(size_t*)data = ival;
  2791. data += sizeof(size_t);
  2792. break;
  2793. default:
  2794. assert(0);
  2795. return;
  2796. }
  2797. }
  2798. else if( CV_NODE_IS_REAL(node->tag) )
  2799. {
  2800. double fval = node->data.f;
  2801. int ival;
  2802. switch( elem_type )
  2803. {
  2804. case CV_8U:
  2805. ival = cvRound(fval);
  2806. *(uchar*)data = cv::saturate_cast<uchar>(ival);
  2807. data++;
  2808. break;
  2809. case CV_8S:
  2810. ival = cvRound(fval);
  2811. *(char*)data = cv::saturate_cast<schar>(ival);
  2812. data++;
  2813. break;
  2814. case CV_16U:
  2815. ival = cvRound(fval);
  2816. *(ushort*)data = cv::saturate_cast<ushort>(ival);
  2817. data += sizeof(ushort);
  2818. break;
  2819. case CV_16S:
  2820. ival = cvRound(fval);
  2821. *(short*)data = cv::saturate_cast<short>(ival);
  2822. data += sizeof(short);
  2823. break;
  2824. case CV_32S:
  2825. ival = cvRound(fval);
  2826. *(int*)data = ival;
  2827. data += sizeof(int);
  2828. break;
  2829. case CV_32F:
  2830. *(float*)data = (float)fval;
  2831. data += sizeof(float);
  2832. break;
  2833. case CV_64F:
  2834. *(double*)data = fval;
  2835. data += sizeof(double);
  2836. break;
  2837. case CV_USRTYPE1: /* reference */
  2838. ival = cvRound(fval);
  2839. *(size_t*)data = ival;
  2840. data += sizeof(size_t);
  2841. break;
  2842. default:
  2843. assert(0);
  2844. return;
  2845. }
  2846. }
  2847. else
  2848. CV_Error( CV_StsError,
  2849. "The sequence element is not a numerical scalar" );
  2850. CV_NEXT_SEQ_ELEM( sizeof(CvFileNode), *reader );
  2851. if( !--len )
  2852. goto end_loop;
  2853. }
  2854. offset = (int)(data - data0);
  2855. }
  2856. }
  2857. end_loop:
  2858. if( i != count - 1 || k != fmt_pair_count - 1 )
  2859. CV_Error( CV_StsBadSize,
  2860. "The sequence slice does not fit an integer number of records" );
  2861. if( !reader->seq )
  2862. reader->ptr -= sizeof(CvFileNode);
  2863. }
  2864. CV_IMPL void
  2865. cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
  2866. void* data, const char* dt )
  2867. {
  2868. CvSeqReader reader;
  2869. if( !src || !data )
  2870. CV_Error( CV_StsNullPtr, "Null pointers to source file node or destination array" );
  2871. cvStartReadRawData( fs, src, &reader );
  2872. cvReadRawDataSlice( fs, &reader, CV_NODE_IS_SEQ(src->tag) ?
  2873. src->data.seq->total : 1, data, dt );
  2874. }
  2875. static void
  2876. icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node );
  2877. static void
  2878. icvWriteCollection( CvFileStorage* fs, const CvFileNode* node )
  2879. {
  2880. int i, total = node->data.seq->total;
  2881. int elem_size = node->data.seq->elem_size;
  2882. int is_map = CV_NODE_IS_MAP(node->tag);
  2883. CvSeqReader reader;
  2884. cvStartReadSeq( node->data.seq, &reader, 0 );
  2885. for( i = 0; i < total; i++ )
  2886. {
  2887. CvFileMapNode* elem = (CvFileMapNode*)reader.ptr;
  2888. if( !is_map || CV_IS_SET_ELEM(elem) )
  2889. {
  2890. const char* name = is_map ? elem->key->str.ptr : 0;
  2891. icvWriteFileNode( fs, name, &elem->value );
  2892. }
  2893. CV_NEXT_SEQ_ELEM( elem_size, reader );
  2894. }
  2895. }
  2896. static void
  2897. icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node )
  2898. {
  2899. switch( CV_NODE_TYPE(node->tag) )
  2900. {
  2901. case CV_NODE_INT:
  2902. fs->write_int( fs, name, node->data.i );
  2903. break;
  2904. case CV_NODE_REAL:
  2905. fs->write_real( fs, name, node->data.f );
  2906. break;
  2907. case CV_NODE_STR:
  2908. fs->write_string( fs, name, node->data.str.ptr, 0 );
  2909. break;
  2910. case CV_NODE_SEQ:
  2911. case CV_NODE_MAP:
  2912. fs->start_write_struct( fs, name, CV_NODE_TYPE(node->tag) +
  2913. (CV_NODE_SEQ_IS_SIMPLE(node->data.seq) ? CV_NODE_FLOW : 0),
  2914. node->info ? node->info->type_name : 0 );
  2915. icvWriteCollection( fs, node );
  2916. fs->end_write_struct( fs );
  2917. break;
  2918. case CV_NODE_NONE:
  2919. fs->start_write_struct( fs, name, CV_NODE_SEQ, 0 );
  2920. fs->end_write_struct( fs );
  2921. break;
  2922. default:
  2923. CV_Error( CV_StsBadFlag, "Unknown type of file node" );
  2924. }
  2925. }
  2926. CV_IMPL void
  2927. cvWriteFileNode( CvFileStorage* fs, const char* new_node_name,
  2928. const CvFileNode* node, int embed )
  2929. {
  2930. CvFileStorage* dst = 0;
  2931. CV_CHECK_OUTPUT_FILE_STORAGE(fs);
  2932. if( !node )
  2933. return;
  2934. if( CV_NODE_IS_COLLECTION(node->tag) && embed )
  2935. {
  2936. icvWriteCollection( fs, node );
  2937. }
  2938. else
  2939. {
  2940. icvWriteFileNode( fs, new_node_name, node );
  2941. }
  2942. /*
  2943. int i, stream_count;
  2944. stream_count = fs->roots->total;
  2945. for( i = 0; i < stream_count; i++ )
  2946. {
  2947. CvFileNode* node = (CvFileNode*)cvGetSeqElem( fs->roots, i, 0 );
  2948. icvDumpCollection( dst, node );
  2949. if( i < stream_count - 1 )
  2950. dst->start_next_stream( dst );
  2951. }*/
  2952. cvReleaseFileStorage( &dst );
  2953. }
  2954. CV_IMPL const char*
  2955. cvGetFileNodeName( const CvFileNode* file_node )
  2956. {
  2957. return file_node && CV_NODE_HAS_NAME(file_node->tag) ?
  2958. ((CvFileMapNode*)file_node)->key->str.ptr : 0;
  2959. }
  2960. /****************************************************************************************\
  2961. * Reading/Writing etc. for standard types *
  2962. \****************************************************************************************/
  2963. /*#define CV_TYPE_NAME_MAT "opencv-matrix"
  2964. #define CV_TYPE_NAME_MATND "opencv-nd-matrix"
  2965. #define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix"
  2966. #define CV_TYPE_NAME_IMAGE "opencv-image"
  2967. #define CV_TYPE_NAME_SEQ "opencv-sequence"
  2968. #define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree"
  2969. #define CV_TYPE_NAME_GRAPH "opencv-graph"*/
  2970. /******************************* CvMat ******************************/
  2971. static int
  2972. icvIsMat( const void* ptr )
  2973. {
  2974. return CV_IS_MAT_HDR_Z(ptr);
  2975. }
  2976. static void
  2977. icvWriteMat( CvFileStorage* fs, const char* name,
  2978. const void* struct_ptr, CvAttrList /*attr*/ )
  2979. {
  2980. const CvMat* mat = (const CvMat*)struct_ptr;
  2981. char dt[16];
  2982. CvSize size;
  2983. int y;
  2984. assert( CV_IS_MAT_HDR_Z(mat) );
  2985. cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MAT );
  2986. cvWriteInt( fs, "rows", mat->rows );
  2987. cvWriteInt( fs, "cols", mat->cols );
  2988. cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
  2989. cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
  2990. size = cvGetSize(mat);
  2991. if( size.height > 0 && size.width > 0 && mat->data.ptr )
  2992. {
  2993. if( CV_IS_MAT_CONT(mat->type) )
  2994. {
  2995. size.width *= size.height;
  2996. size.height = 1;
  2997. }
  2998. for( y = 0; y < size.height; y++ )
  2999. cvWriteRawData( fs, mat->data.ptr + (size_t)y*mat->step, size.width, dt );
  3000. }
  3001. cvEndWriteStruct( fs );
  3002. cvEndWriteStruct( fs );
  3003. }
  3004. static int
  3005. icvFileNodeSeqLen( CvFileNode* node )
  3006. {
  3007. return CV_NODE_IS_COLLECTION(node->tag) ? node->data.seq->total :
  3008. CV_NODE_TYPE(node->tag) != CV_NODE_NONE;
  3009. }
  3010. static void*
  3011. icvReadMat( CvFileStorage* fs, CvFileNode* node )
  3012. {
  3013. void* ptr = 0;
  3014. CvMat* mat;
  3015. const char* dt;
  3016. CvFileNode* data;
  3017. int rows, cols, elem_type;
  3018. rows = cvReadIntByName( fs, node, "rows", -1 );
  3019. cols = cvReadIntByName( fs, node, "cols", -1 );
  3020. dt = cvReadStringByName( fs, node, "dt", 0 );
  3021. if( rows < 0 || cols < 0 || !dt )
  3022. CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
  3023. elem_type = icvDecodeSimpleFormat( dt );
  3024. data = cvGetFileNodeByName( fs, node, "data" );
  3025. if( !data )
  3026. CV_Error( CV_StsError, "The matrix data is not found in file storage" );
  3027. int nelems = icvFileNodeSeqLen( data );
  3028. if( nelems > 0 && nelems != rows*cols*CV_MAT_CN(elem_type) )
  3029. CV_Error( CV_StsUnmatchedSizes,
  3030. "The matrix size does not match to the number of stored elements" );
  3031. if( nelems > 0 )
  3032. {
  3033. mat = cvCreateMat( rows, cols, elem_type );
  3034. cvReadRawData( fs, data, mat->data.ptr, dt );
  3035. }
  3036. else if( rows == 0 && cols == 0 )
  3037. mat = cvCreateMatHeader( 0, 1, elem_type );
  3038. else
  3039. mat = cvCreateMatHeader( rows, cols, elem_type );
  3040. ptr = mat;
  3041. return ptr;
  3042. }
  3043. /******************************* CvMatND ******************************/
  3044. static int
  3045. icvIsMatND( const void* ptr )
  3046. {
  3047. return CV_IS_MATND_HDR(ptr);
  3048. }
  3049. static void
  3050. icvWriteMatND( CvFileStorage* fs, const char* name,
  3051. const void* struct_ptr, CvAttrList /*attr*/ )
  3052. {
  3053. CvMatND* mat = (CvMatND*)struct_ptr;
  3054. CvMatND stub;
  3055. CvNArrayIterator iterator;
  3056. int dims, sizes[CV_MAX_DIM];
  3057. char dt[16];
  3058. assert( CV_IS_MATND_HDR(mat) );
  3059. cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MATND );
  3060. dims = cvGetDims( mat, sizes );
  3061. cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
  3062. cvWriteRawData( fs, sizes, dims, "i" );
  3063. cvEndWriteStruct( fs );
  3064. cvWriteString( fs, "dt", icvEncodeFormat( cvGetElemType(mat), dt ), 0 );
  3065. cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
  3066. if( mat->dim[0].size > 0 && mat->data.ptr )
  3067. {
  3068. cvInitNArrayIterator( 1, (CvArr**)&mat, 0, &stub, &iterator );
  3069. do
  3070. cvWriteRawData( fs, iterator.ptr[0], iterator.size.width, dt );
  3071. while( cvNextNArraySlice( &iterator ));
  3072. }
  3073. cvEndWriteStruct( fs );
  3074. cvEndWriteStruct( fs );
  3075. }
  3076. static void*
  3077. icvReadMatND( CvFileStorage* fs, CvFileNode* node )
  3078. {
  3079. void* ptr = 0;
  3080. CvMatND* mat;
  3081. const char* dt;
  3082. CvFileNode* data;
  3083. CvFileNode* sizes_node;
  3084. int sizes[CV_MAX_DIM], dims, elem_type;
  3085. int i, total_size;
  3086. sizes_node = cvGetFileNodeByName( fs, node, "sizes" );
  3087. dt = cvReadStringByName( fs, node, "dt", 0 );
  3088. if( !sizes_node || !dt )
  3089. CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
  3090. dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
  3091. CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
  3092. if( dims <= 0 || dims > CV_MAX_DIM )
  3093. CV_Error( CV_StsParseError, "Could not determine the matrix dimensionality" );
  3094. cvReadRawData( fs, sizes_node, sizes, "i" );
  3095. elem_type = icvDecodeSimpleFormat( dt );
  3096. data = cvGetFileNodeByName( fs, node, "data" );
  3097. if( !data )
  3098. CV_Error( CV_StsError, "The matrix data is not found in file storage" );
  3099. for( total_size = CV_MAT_CN(elem_type), i = 0; i < dims; i++ )
  3100. total_size *= sizes[i];
  3101. int nelems = icvFileNodeSeqLen( data );
  3102. if( nelems > 0 && nelems != total_size )
  3103. CV_Error( CV_StsUnmatchedSizes,
  3104. "The matrix size does not match to the number of stored elements" );
  3105. if( nelems > 0 )
  3106. {
  3107. mat = cvCreateMatND( dims, sizes, elem_type );
  3108. cvReadRawData( fs, data, mat->data.ptr, dt );
  3109. }
  3110. else
  3111. mat = cvCreateMatNDHeader( dims, sizes, elem_type );
  3112. ptr = mat;
  3113. return ptr;
  3114. }
  3115. /******************************* CvSparseMat ******************************/
  3116. static int
  3117. icvIsSparseMat( const void* ptr )
  3118. {
  3119. return CV_IS_SPARSE_MAT(ptr);
  3120. }
  3121. static int
  3122. icvSortIdxCmpFunc( const void* _a, const void* _b, void* userdata )
  3123. {
  3124. int i, dims = *(int*)userdata;
  3125. const int* a = *(const int**)_a;
  3126. const int* b = *(const int**)_b;
  3127. for( i = 0; i < dims; i++ )
  3128. {
  3129. int delta = a[i] - b[i];
  3130. if( delta )
  3131. return delta;
  3132. }
  3133. return 0;
  3134. }
  3135. static void
  3136. icvWriteSparseMat( CvFileStorage* fs, const char* name,
  3137. const void* struct_ptr, CvAttrList /*attr*/ )
  3138. {
  3139. CvMemStorage* memstorage = 0;
  3140. const CvSparseMat* mat = (const CvSparseMat*)struct_ptr;
  3141. CvSparseMatIterator iterator;
  3142. CvSparseNode* node;
  3143. CvSeq* elements;
  3144. CvSeqReader reader;
  3145. int i, dims;
  3146. int *prev_idx = 0;
  3147. char dt[16];
  3148. assert( CV_IS_SPARSE_MAT(mat) );
  3149. memstorage = cvCreateMemStorage();
  3150. cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SPARSE_MAT );
  3151. dims = cvGetDims( mat, 0 );
  3152. cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
  3153. cvWriteRawData( fs, mat->size, dims, "i" );
  3154. cvEndWriteStruct( fs );
  3155. cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
  3156. cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
  3157. elements = cvCreateSeq( CV_SEQ_ELTYPE_PTR, sizeof(CvSeq), sizeof(int*), memstorage );
  3158. node = cvInitSparseMatIterator( mat, &iterator );
  3159. while( node )
  3160. {
  3161. int* idx = CV_NODE_IDX( mat, node );
  3162. cvSeqPush( elements, &idx );
  3163. node = cvGetNextSparseNode( &iterator );
  3164. }
  3165. cvSeqSort( elements, icvSortIdxCmpFunc, &dims );
  3166. cvStartReadSeq( elements, &reader, 0 );
  3167. for( i = 0; i < elements->total; i++ )
  3168. {
  3169. int* idx;
  3170. void* val;
  3171. int k = 0;
  3172. CV_READ_SEQ_ELEM( idx, reader );
  3173. if( i > 0 )
  3174. {
  3175. for( ; idx[k] == prev_idx[k]; k++ )
  3176. assert( k < dims );
  3177. if( k < dims - 1 )
  3178. fs->write_int( fs, 0, k - dims + 1 );
  3179. }
  3180. for( ; k < dims; k++ )
  3181. fs->write_int( fs, 0, idx[k] );
  3182. prev_idx = idx;
  3183. node = (CvSparseNode*)((uchar*)idx - mat->idxoffset );
  3184. val = CV_NODE_VAL( mat, node );
  3185. cvWriteRawData( fs, val, 1, dt );
  3186. }
  3187. cvEndWriteStruct( fs );
  3188. cvEndWriteStruct( fs );
  3189. cvReleaseMemStorage( &memstorage );
  3190. }
  3191. static void*
  3192. icvReadSparseMat( CvFileStorage* fs, CvFileNode* node )
  3193. {
  3194. void* ptr = 0;
  3195. CvSparseMat* mat;
  3196. const char* dt;
  3197. CvFileNode* data;
  3198. CvFileNode* sizes_node;
  3199. CvSeqReader reader;
  3200. CvSeq* elements;
  3201. int sizes[CV_MAX_DIM_HEAP], dims, elem_type, cn;
  3202. int i;
  3203. sizes_node = cvGetFileNodeByName( fs, node, "sizes" );
  3204. dt = cvReadStringByName( fs, node, "dt", 0 );
  3205. if( !sizes_node || !dt )
  3206. CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
  3207. dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
  3208. CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
  3209. if( dims <= 0 || dims > CV_MAX_DIM_HEAP )
  3210. CV_Error( CV_StsParseError, "Could not determine sparse matrix dimensionality" );
  3211. cvReadRawData( fs, sizes_node, sizes, "i" );
  3212. elem_type = icvDecodeSimpleFormat( dt );
  3213. data = cvGetFileNodeByName( fs, node, "data" );
  3214. if( !data || !CV_NODE_IS_SEQ(data->tag) )
  3215. CV_Error( CV_StsError, "The matrix data is not found in file storage" );
  3216. mat = cvCreateSparseMat( dims, sizes, elem_type );
  3217. cn = CV_MAT_CN(elem_type);
  3218. int idx[CV_MAX_DIM_HEAP];
  3219. elements = data->data.seq;
  3220. cvStartReadRawData( fs, data, &reader );
  3221. for( i = 0; i < elements->total; )
  3222. {
  3223. CvFileNode* elem = (CvFileNode*)reader.ptr;
  3224. uchar* val;
  3225. int k;
  3226. if( !CV_NODE_IS_INT(elem->tag ))
  3227. CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" );
  3228. k = elem->data.i;
  3229. if( i > 0 && k >= 0 )
  3230. idx[dims-1] = k;
  3231. else
  3232. {
  3233. if( i > 0 )
  3234. k = dims + k - 1;
  3235. else
  3236. idx[0] = k, k = 1;
  3237. for( ; k < dims; k++ )
  3238. {
  3239. CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
  3240. i++;
  3241. elem = (CvFileNode*)reader.ptr;
  3242. if( !CV_NODE_IS_INT(elem->tag ) || elem->data.i < 0 )
  3243. CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" );
  3244. idx[k] = elem->data.i;
  3245. }
  3246. }
  3247. CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
  3248. i++;
  3249. val = cvPtrND( mat, idx, 0, 1, 0 );
  3250. cvReadRawDataSlice( fs, &reader, cn, val, dt );
  3251. i += cn;
  3252. }
  3253. ptr = mat;
  3254. return ptr;
  3255. }
  3256. /******************************* IplImage ******************************/
  3257. static int
  3258. icvIsImage( const void* ptr )
  3259. {
  3260. return CV_IS_IMAGE_HDR(ptr);
  3261. }
  3262. static void
  3263. icvWriteImage( CvFileStorage* fs, const char* name,
  3264. const void* struct_ptr, CvAttrList /*attr*/ )
  3265. {
  3266. const IplImage* image = (const IplImage*)struct_ptr;
  3267. char dt_buf[16], *dt;
  3268. CvSize size;
  3269. int y, depth;
  3270. assert( CV_IS_IMAGE(image) );
  3271. if( image->dataOrder == IPL_DATA_ORDER_PLANE )
  3272. CV_Error( CV_StsUnsupportedFormat,
  3273. "Images with planar data layout are not supported" );
  3274. cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_IMAGE );
  3275. cvWriteInt( fs, "width", image->width );
  3276. cvWriteInt( fs, "height", image->height );
  3277. cvWriteString( fs, "origin", image->origin == IPL_ORIGIN_TL
  3278. ? "top-left" : "bottom-left", 0 );
  3279. cvWriteString( fs, "layout", image->dataOrder == IPL_DATA_ORDER_PLANE
  3280. ? "planar" : "interleaved", 0 );
  3281. if( image->roi )
  3282. {
  3283. cvStartWriteStruct( fs, "roi", CV_NODE_MAP + CV_NODE_FLOW );
  3284. cvWriteInt( fs, "x", image->roi->xOffset );
  3285. cvWriteInt( fs, "y", image->roi->yOffset );
  3286. cvWriteInt( fs, "width", image->roi->width );
  3287. cvWriteInt( fs, "height", image->roi->height );
  3288. cvWriteInt( fs, "coi", image->roi->coi );
  3289. cvEndWriteStruct( fs );
  3290. }
  3291. depth = IPL2CV_DEPTH(image->depth);
  3292. sprintf( dt_buf, "%d%c", image->nChannels, icvTypeSymbol[depth] );
  3293. dt = dt_buf + (dt_buf[2] == '\0' && dt_buf[0] == '1');
  3294. cvWriteString( fs, "dt", dt, 0 );
  3295. size = cvSize(image->width, image->height);
  3296. if( size.width*image->nChannels*CV_ELEM_SIZE(depth) == image->widthStep )
  3297. {
  3298. size.width *= size.height;
  3299. size.height = 1;
  3300. }
  3301. cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
  3302. for( y = 0; y < size.height; y++ )
  3303. cvWriteRawData( fs, image->imageData + y*image->widthStep, size.width, dt );
  3304. cvEndWriteStruct( fs );
  3305. cvEndWriteStruct( fs );
  3306. }
  3307. static void*
  3308. icvReadImage( CvFileStorage* fs, CvFileNode* node )
  3309. {
  3310. void* ptr = 0;
  3311. IplImage* image;
  3312. const char* dt;
  3313. CvFileNode* data;
  3314. CvFileNode* roi_node;
  3315. CvSeqReader reader;
  3316. CvRect roi;
  3317. int y, width, height, elem_type, coi, depth;
  3318. const char* origin, *data_order;
  3319. width = cvReadIntByName( fs, node, "width", 0 );
  3320. height = cvReadIntByName( fs, node, "height", 0 );
  3321. dt = cvReadStringByName( fs, node, "dt", 0 );
  3322. origin = cvReadStringByName( fs, node, "origin", 0 );
  3323. if( width == 0 || height == 0 || dt == 0 || origin == 0 )
  3324. CV_Error( CV_StsError, "Some of essential image attributes are absent" );
  3325. elem_type = icvDecodeSimpleFormat( dt );
  3326. data_order = cvReadStringByName( fs, node, "layout", "interleaved" );
  3327. if( strcmp( data_order, "interleaved" ) != 0 )
  3328. CV_Error( CV_StsError, "Only interleaved images can be read" );
  3329. data = cvGetFileNodeByName( fs, node, "data" );
  3330. if( !data )
  3331. CV_Error( CV_StsError, "The image data is not found in file storage" );
  3332. if( icvFileNodeSeqLen( data ) != width*height*CV_MAT_CN(elem_type) )
  3333. CV_Error( CV_StsUnmatchedSizes,
  3334. "The matrix size does not match to the number of stored elements" );
  3335. depth = cvIplDepth(elem_type);
  3336. image = cvCreateImage( cvSize(width,height), depth, CV_MAT_CN(elem_type) );
  3337. roi_node = cvGetFileNodeByName( fs, node, "roi" );
  3338. if( roi_node )
  3339. {
  3340. roi.x = cvReadIntByName( fs, roi_node, "x", 0 );
  3341. roi.y = cvReadIntByName( fs, roi_node, "y", 0 );
  3342. roi.width = cvReadIntByName( fs, roi_node, "width", 0 );
  3343. roi.height = cvReadIntByName( fs, roi_node, "height", 0 );
  3344. coi = cvReadIntByName( fs, roi_node, "coi", 0 );
  3345. cvSetImageROI( image, roi );
  3346. cvSetImageCOI( image, coi );
  3347. }
  3348. if( width*CV_ELEM_SIZE(elem_type) == image->widthStep )
  3349. {
  3350. width *= height;
  3351. height = 1;
  3352. }
  3353. width *= CV_MAT_CN(elem_type);
  3354. cvStartReadRawData( fs, data, &reader );
  3355. for( y = 0; y < height; y++ )
  3356. {
  3357. cvReadRawDataSlice( fs, &reader, width,
  3358. image->imageData + y*image->widthStep, dt );
  3359. }
  3360. ptr = image;
  3361. return ptr;
  3362. }
  3363. /******************************* CvSeq ******************************/
  3364. static int
  3365. icvIsSeq( const void* ptr )
  3366. {
  3367. return CV_IS_SEQ(ptr);
  3368. }
  3369. static void
  3370. icvReleaseSeq( void** ptr )
  3371. {
  3372. if( !ptr )
  3373. CV_Error( CV_StsNullPtr, "NULL double pointer" );
  3374. *ptr = 0; // it's impossible now to release seq, so just clear the pointer
  3375. }
  3376. static void*
  3377. icvCloneSeq( const void* ptr )
  3378. {
  3379. return cvSeqSlice( (CvSeq*)ptr, CV_WHOLE_SEQ,
  3380. 0 /* use the same storage as for the original sequence */, 1 );
  3381. }
  3382. static void
  3383. icvWriteHeaderData( CvFileStorage* fs, const CvSeq* seq,
  3384. CvAttrList* attr, int initial_header_size )
  3385. {
  3386. char header_dt_buf[128];
  3387. const char* header_dt = cvAttrValue( attr, "header_dt" );
  3388. if( header_dt )
  3389. {
  3390. int dt_header_size;
  3391. dt_header_size = icvCalcElemSize( header_dt, initial_header_size );
  3392. if( dt_header_size > seq->header_size )
  3393. CV_Error( CV_StsUnmatchedSizes,
  3394. "The size of header calculated from \"header_dt\" is greater than header_size" );
  3395. }
  3396. else if( seq->header_size > initial_header_size )
  3397. {
  3398. if( CV_IS_SEQ(seq) && CV_IS_SEQ_POINT_SET(seq) &&
  3399. seq->header_size == sizeof(CvPoint2DSeq) &&
  3400. seq->elem_size == sizeof(int)*2 )
  3401. {
  3402. CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
  3403. cvStartWriteStruct( fs, "rect", CV_NODE_MAP + CV_NODE_FLOW );
  3404. cvWriteInt( fs, "x", point_seq->rect.x );
  3405. cvWriteInt( fs, "y", point_seq->rect.y );
  3406. cvWriteInt( fs, "width", point_seq->rect.width );
  3407. cvWriteInt( fs, "height", point_seq->rect.height );
  3408. cvEndWriteStruct( fs );
  3409. cvWriteInt( fs, "color", point_seq->color );
  3410. }
  3411. else if( CV_IS_SEQ(seq) && CV_IS_SEQ_CHAIN(seq) &&
  3412. CV_MAT_TYPE(seq->flags) == CV_8UC1 )
  3413. {
  3414. CvChain* chain = (CvChain*)seq;
  3415. cvStartWriteStruct( fs, "origin", CV_NODE_MAP + CV_NODE_FLOW );
  3416. cvWriteInt( fs, "x", chain->origin.x );
  3417. cvWriteInt( fs, "y", chain->origin.y );
  3418. cvEndWriteStruct( fs );
  3419. }
  3420. else
  3421. {
  3422. unsigned extra_size = seq->header_size - initial_header_size;
  3423. // a heuristic to provide nice defaults for sequences of int's & float's
  3424. if( extra_size % sizeof(int) == 0 )
  3425. sprintf( header_dt_buf, "%ui", (unsigned)(extra_size/sizeof(int)) );
  3426. else
  3427. sprintf( header_dt_buf, "%uu", extra_size );
  3428. header_dt = header_dt_buf;
  3429. }
  3430. }
  3431. if( header_dt )
  3432. {
  3433. cvWriteString( fs, "header_dt", header_dt, 0 );
  3434. cvStartWriteStruct( fs, "header_user_data", CV_NODE_SEQ + CV_NODE_FLOW );
  3435. cvWriteRawData( fs, (uchar*)seq + sizeof(CvSeq), 1, header_dt );
  3436. cvEndWriteStruct( fs );
  3437. }
  3438. }
  3439. static char*
  3440. icvGetFormat( const CvSeq* seq, const char* dt_key, CvAttrList* attr,
  3441. int initial_elem_size, char* dt_buf )
  3442. {
  3443. char* dt = 0;
  3444. dt = (char*)cvAttrValue( attr, dt_key );
  3445. if( dt )
  3446. {
  3447. int dt_elem_size;
  3448. dt_elem_size = icvCalcElemSize( dt, initial_elem_size );
  3449. if( dt_elem_size != seq->elem_size )
  3450. CV_Error( CV_StsUnmatchedSizes,
  3451. "The size of element calculated from \"dt\" and "
  3452. "the elem_size do not match" );
  3453. }
  3454. else if( CV_MAT_TYPE(seq->flags) != 0 || seq->elem_size == 1 )
  3455. {
  3456. if( CV_ELEM_SIZE(seq->flags) != seq->elem_size )
  3457. CV_Error( CV_StsUnmatchedSizes,
  3458. "Size of sequence element (elem_size) is inconsistent with seq->flags" );
  3459. dt = icvEncodeFormat( CV_MAT_TYPE(seq->flags), dt_buf );
  3460. }
  3461. else if( seq->elem_size > initial_elem_size )
  3462. {
  3463. unsigned extra_elem_size = seq->elem_size - initial_elem_size;
  3464. // a heuristic to provide nice defaults for sequences of int's & float's
  3465. if( extra_elem_size % sizeof(int) == 0 )
  3466. sprintf( dt_buf, "%ui", (unsigned)(extra_elem_size/sizeof(int)) );
  3467. else
  3468. sprintf( dt_buf, "%uu", extra_elem_size );
  3469. dt = dt_buf;
  3470. }
  3471. return dt;
  3472. }
  3473. static void
  3474. icvWriteSeq( CvFileStorage* fs, const char* name,
  3475. const void* struct_ptr,
  3476. CvAttrList attr, int level )
  3477. {
  3478. const CvSeq* seq = (CvSeq*)struct_ptr;
  3479. CvSeqBlock* block;
  3480. char buf[128];
  3481. char dt_buf[128], *dt;
  3482. assert( CV_IS_SEQ( seq ));
  3483. cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ );
  3484. if( level >= 0 )
  3485. cvWriteInt( fs, "level", level );
  3486. dt = icvGetFormat( seq, "dt", &attr, 0, dt_buf );
  3487. strcpy(buf, "");
  3488. if( CV_IS_SEQ_CLOSED(seq) )
  3489. strcat(buf, " closed");
  3490. if( CV_IS_SEQ_HOLE(seq) )
  3491. strcat(buf, " hole");
  3492. if( CV_IS_SEQ_CURVE(seq) )
  3493. strcat(buf, " curve");
  3494. if( CV_SEQ_ELTYPE(seq) == 0 && seq->elem_size != 1 )
  3495. strcat(buf, " untyped");
  3496. cvWriteString( fs, "flags", buf + (buf[0] ? 1 : 0), 1 );
  3497. cvWriteInt( fs, "count", seq->total );
  3498. cvWriteString( fs, "dt", dt, 0 );
  3499. icvWriteHeaderData( fs, seq, &attr, sizeof(CvSeq) );
  3500. cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
  3501. for( block = seq->first; block; block = block->next )
  3502. {
  3503. cvWriteRawData( fs, block->data, block->count, dt );
  3504. if( block == seq->first->prev )
  3505. break;
  3506. }
  3507. cvEndWriteStruct( fs );
  3508. cvEndWriteStruct( fs );
  3509. }
  3510. static void
  3511. icvWriteSeqTree( CvFileStorage* fs, const char* name,
  3512. const void* struct_ptr, CvAttrList attr )
  3513. {
  3514. const CvSeq* seq = (CvSeq*)struct_ptr;
  3515. const char* recursive_value = cvAttrValue( &attr, "recursive" );
  3516. int is_recursive = recursive_value &&
  3517. strcmp(recursive_value,"0") != 0 &&
  3518. strcmp(recursive_value,"false") != 0 &&
  3519. strcmp(recursive_value,"False") != 0 &&
  3520. strcmp(recursive_value,"FALSE") != 0;
  3521. assert( CV_IS_SEQ( seq ));
  3522. if( !is_recursive )
  3523. {
  3524. icvWriteSeq( fs, name, seq, attr, -1 );
  3525. }
  3526. else
  3527. {
  3528. CvTreeNodeIterator tree_iterator;
  3529. cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ_TREE );
  3530. cvStartWriteStruct( fs, "sequences", CV_NODE_SEQ );
  3531. cvInitTreeNodeIterator( &tree_iterator, seq, INT_MAX );
  3532. for(;;)
  3533. {
  3534. if( !tree_iterator.node )
  3535. break;
  3536. icvWriteSeq( fs, 0, tree_iterator.node, attr, tree_iterator.level );
  3537. cvNextTreeNode( &tree_iterator );
  3538. }
  3539. cvEndWriteStruct( fs );
  3540. cvEndWriteStruct( fs );
  3541. }
  3542. }
  3543. static void*
  3544. icvReadSeq( CvFileStorage* fs, CvFileNode* node )
  3545. {
  3546. void* ptr = 0;
  3547. CvSeq* seq;
  3548. CvSeqBlock* block;
  3549. CvFileNode *data, *header_node, *rect_node, *origin_node;
  3550. CvSeqReader reader;
  3551. int total, flags;
  3552. int elem_size, header_size = sizeof(CvSeq);
  3553. int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
  3554. int items_per_elem = 0;
  3555. const char* flags_str;
  3556. const char* header_dt;
  3557. const char* dt;
  3558. char* endptr = 0;
  3559. flags_str = cvReadStringByName( fs, node, "flags", 0 );
  3560. total = cvReadIntByName( fs, node, "count", -1 );
  3561. dt = cvReadStringByName( fs, node, "dt", 0 );
  3562. if( !flags_str || total == -1 || !dt )
  3563. CV_Error( CV_StsError, "Some of essential sequence attributes are absent" );
  3564. flags = CV_SEQ_MAGIC_VAL;
  3565. if( cv_isdigit(flags_str[0]) )
  3566. {
  3567. const int OLD_SEQ_ELTYPE_BITS = 9;
  3568. const int OLD_SEQ_ELTYPE_MASK = (1 << OLD_SEQ_ELTYPE_BITS) - 1;
  3569. const int OLD_SEQ_KIND_BITS = 3;
  3570. const int OLD_SEQ_KIND_MASK = ((1 << OLD_SEQ_KIND_BITS) - 1) << OLD_SEQ_ELTYPE_BITS;
  3571. const int OLD_SEQ_KIND_CURVE = 1 << OLD_SEQ_ELTYPE_BITS;
  3572. const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS;
  3573. const int OLD_SEQ_FLAG_CLOSED = 1 << OLD_SEQ_FLAG_SHIFT;
  3574. const int OLD_SEQ_FLAG_HOLE = 8 << OLD_SEQ_FLAG_SHIFT;
  3575. int flags0 = (int)strtol( flags_str, &endptr, 16 );
  3576. if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SEQ_MAGIC_VAL )
  3577. CV_Error( CV_StsError, "The sequence flags are invalid" );
  3578. if( (flags0 & OLD_SEQ_KIND_MASK) == OLD_SEQ_KIND_CURVE )
  3579. flags |= CV_SEQ_KIND_CURVE;
  3580. if( flags0 & OLD_SEQ_FLAG_CLOSED )
  3581. flags |= CV_SEQ_FLAG_CLOSED;
  3582. if( flags0 & OLD_SEQ_FLAG_HOLE )
  3583. flags |= CV_SEQ_FLAG_HOLE;
  3584. flags |= flags0 & OLD_SEQ_ELTYPE_MASK;
  3585. }
  3586. else
  3587. {
  3588. if( strstr(flags_str, "curve") )
  3589. flags |= CV_SEQ_KIND_CURVE;
  3590. if( strstr(flags_str, "closed") )
  3591. flags |= CV_SEQ_FLAG_CLOSED;
  3592. if( strstr(flags_str, "hole") )
  3593. flags |= CV_SEQ_FLAG_HOLE;
  3594. if( !strstr(flags_str, "untyped") )
  3595. {
  3596. try
  3597. {
  3598. flags |= icvDecodeSimpleFormat(dt);
  3599. }
  3600. catch(...)
  3601. {
  3602. }
  3603. }
  3604. }
  3605. header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
  3606. header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
  3607. if( (header_dt != 0) ^ (header_node != 0) )
  3608. CV_Error( CV_StsError,
  3609. "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
  3610. rect_node = cvGetFileNodeByName( fs, node, "rect" );
  3611. origin_node = cvGetFileNodeByName( fs, node, "origin" );
  3612. if( (header_node != 0) + (rect_node != 0) + (origin_node != 0) > 1 )
  3613. CV_Error( CV_StsError, "Only one of \"header_user_data\", \"rect\" and \"origin\" tags may occur" );
  3614. if( header_dt )
  3615. {
  3616. header_size = icvCalcElemSize( header_dt, header_size );
  3617. }
  3618. else if( rect_node )
  3619. header_size = sizeof(CvPoint2DSeq);
  3620. else if( origin_node )
  3621. header_size = sizeof(CvChain);
  3622. elem_size = icvCalcElemSize( dt, 0 );
  3623. seq = cvCreateSeq( flags, header_size, elem_size, fs->dststorage );
  3624. if( header_node )
  3625. {
  3626. cvReadRawData( fs, header_node, (char*)seq + sizeof(CvSeq), header_dt );
  3627. }
  3628. else if( rect_node )
  3629. {
  3630. CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
  3631. point_seq->rect.x = cvReadIntByName( fs, rect_node, "x", 0 );
  3632. point_seq->rect.y = cvReadIntByName( fs, rect_node, "y", 0 );
  3633. point_seq->rect.width = cvReadIntByName( fs, rect_node, "width", 0 );
  3634. point_seq->rect.height = cvReadIntByName( fs, rect_node, "height", 0 );
  3635. point_seq->color = cvReadIntByName( fs, node, "color", 0 );
  3636. }
  3637. else if( origin_node )
  3638. {
  3639. CvChain* chain = (CvChain*)seq;
  3640. chain->origin.x = cvReadIntByName( fs, origin_node, "x", 0 );
  3641. chain->origin.y = cvReadIntByName( fs, origin_node, "y", 0 );
  3642. }
  3643. cvSeqPushMulti( seq, 0, total, 0 );
  3644. fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
  3645. fmt_pair_count *= 2;
  3646. for( i = 0; i < fmt_pair_count; i += 2 )
  3647. items_per_elem += fmt_pairs[i];
  3648. data = cvGetFileNodeByName( fs, node, "data" );
  3649. if( !data )
  3650. CV_Error( CV_StsError, "The image data is not found in file storage" );
  3651. if( icvFileNodeSeqLen( data ) != total*items_per_elem )
  3652. CV_Error( CV_StsError, "The number of stored elements does not match to \"count\"" );
  3653. cvStartReadRawData( fs, data, &reader );
  3654. for( block = seq->first; block; block = block->next )
  3655. {
  3656. int delta = block->count*items_per_elem;
  3657. cvReadRawDataSlice( fs, &reader, delta, block->data, dt );
  3658. if( block == seq->first->prev )
  3659. break;
  3660. }
  3661. ptr = seq;
  3662. return ptr;
  3663. }
  3664. static void*
  3665. icvReadSeqTree( CvFileStorage* fs, CvFileNode* node )
  3666. {
  3667. void* ptr = 0;
  3668. CvFileNode *sequences_node = cvGetFileNodeByName( fs, node, "sequences" );
  3669. CvSeq* sequences;
  3670. CvSeq* root = 0;
  3671. CvSeq* parent = 0;
  3672. CvSeq* prev_seq = 0;
  3673. CvSeqReader reader;
  3674. int i, total;
  3675. int prev_level = 0;
  3676. if( !sequences_node || !CV_NODE_IS_SEQ(sequences_node->tag) )
  3677. CV_Error( CV_StsParseError,
  3678. "opencv-sequence-tree instance should contain a field \"sequences\" that should be a sequence" );
  3679. sequences = sequences_node->data.seq;
  3680. total = sequences->total;
  3681. cvStartReadSeq( sequences, &reader, 0 );
  3682. for( i = 0; i < total; i++ )
  3683. {
  3684. CvFileNode* elem = (CvFileNode*)reader.ptr;
  3685. CvSeq* seq;
  3686. int level;
  3687. seq = (CvSeq*)cvRead( fs, elem );
  3688. level = cvReadIntByName( fs, elem, "level", -1 );
  3689. if( level < 0 )
  3690. CV_Error( CV_StsParseError, "All the sequence tree nodes should contain \"level\" field" );
  3691. if( !root )
  3692. root = seq;
  3693. if( level > prev_level )
  3694. {
  3695. assert( level == prev_level + 1 );
  3696. parent = prev_seq;
  3697. prev_seq = 0;
  3698. if( parent )
  3699. parent->v_next = seq;
  3700. }
  3701. else if( level < prev_level )
  3702. {
  3703. for( ; prev_level > level; prev_level-- )
  3704. prev_seq = prev_seq->v_prev;
  3705. parent = prev_seq->v_prev;
  3706. }
  3707. seq->h_prev = prev_seq;
  3708. if( prev_seq )
  3709. prev_seq->h_next = seq;
  3710. seq->v_prev = parent;
  3711. prev_seq = seq;
  3712. prev_level = level;
  3713. CV_NEXT_SEQ_ELEM( sequences->elem_size, reader );
  3714. }
  3715. ptr = root;
  3716. return ptr;
  3717. }
  3718. /******************************* CvGraph ******************************/
  3719. static int
  3720. icvIsGraph( const void* ptr )
  3721. {
  3722. return CV_IS_GRAPH(ptr);
  3723. }
  3724. static void
  3725. icvReleaseGraph( void** ptr )
  3726. {
  3727. if( !ptr )
  3728. CV_Error( CV_StsNullPtr, "NULL double pointer" );
  3729. *ptr = 0; // it's impossible now to release graph, so just clear the pointer
  3730. }
  3731. static void*
  3732. icvCloneGraph( const void* ptr )
  3733. {
  3734. return cvCloneGraph( (const CvGraph*)ptr, 0 );
  3735. }
  3736. static void
  3737. icvWriteGraph( CvFileStorage* fs, const char* name,
  3738. const void* struct_ptr, CvAttrList attr )
  3739. {
  3740. int* flag_buf = 0;
  3741. char* write_buf = 0;
  3742. const CvGraph* graph = (const CvGraph*)struct_ptr;
  3743. CvSeqReader reader;
  3744. char buf[128];
  3745. int i, k, vtx_count, edge_count;
  3746. char vtx_dt_buf[128], *vtx_dt;
  3747. char edge_dt_buf[128], *edge_dt;
  3748. int write_buf_size;
  3749. assert( CV_IS_GRAPH(graph) );
  3750. vtx_count = cvGraphGetVtxCount( graph );
  3751. edge_count = cvGraphGetEdgeCount( graph );
  3752. flag_buf = (int*)cvAlloc( vtx_count*sizeof(flag_buf[0]));
  3753. // count vertices
  3754. cvStartReadSeq( (CvSeq*)graph, &reader );
  3755. for( i = 0, k = 0; i < graph->total; i++ )
  3756. {
  3757. if( CV_IS_SET_ELEM( reader.ptr ))
  3758. {
  3759. CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
  3760. flag_buf[k] = vtx->flags;
  3761. vtx->flags = k++;
  3762. }
  3763. CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
  3764. }
  3765. // write header
  3766. cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_GRAPH );
  3767. cvWriteString(fs, "flags", CV_IS_GRAPH_ORIENTED(graph) ? "oriented" : "", 1);
  3768. cvWriteInt( fs, "vertex_count", vtx_count );
  3769. vtx_dt = icvGetFormat( (CvSeq*)graph, "vertex_dt",
  3770. &attr, sizeof(CvGraphVtx), vtx_dt_buf );
  3771. if( vtx_dt )
  3772. cvWriteString( fs, "vertex_dt", vtx_dt, 0 );
  3773. cvWriteInt( fs, "edge_count", edge_count );
  3774. edge_dt = icvGetFormat( (CvSeq*)graph->edges, "edge_dt",
  3775. &attr, sizeof(CvGraphEdge), buf );
  3776. sprintf( edge_dt_buf, "2if%s", edge_dt ? edge_dt : "" );
  3777. edge_dt = edge_dt_buf;
  3778. cvWriteString( fs, "edge_dt", edge_dt, 0 );
  3779. icvWriteHeaderData( fs, (CvSeq*)graph, &attr, sizeof(CvGraph) );
  3780. write_buf_size = MAX( 3*graph->elem_size, 1 << 16 );
  3781. write_buf_size = MAX( 3*graph->edges->elem_size, write_buf_size );
  3782. write_buf = (char*)cvAlloc( write_buf_size );
  3783. // as vertices and edges are written in similar way,
  3784. // do it as a parametrized 2-iteration loop
  3785. for( k = 0; k < 2; k++ )
  3786. {
  3787. const char* dt = k == 0 ? vtx_dt : edge_dt;
  3788. if( dt )
  3789. {
  3790. CvSet* data = k == 0 ? (CvSet*)graph : graph->edges;
  3791. int elem_size = data->elem_size;
  3792. int write_elem_size = icvCalcElemSize( dt, 0 );
  3793. char* src_ptr = write_buf;
  3794. int write_max = write_buf_size / write_elem_size, write_count = 0;
  3795. // alignment of user part of the edge data following 2if
  3796. int edge_user_align = sizeof(float);
  3797. if( k == 1 )
  3798. {
  3799. int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
  3800. fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
  3801. if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[2*2+1]) >= (int)sizeof(double))
  3802. edge_user_align = sizeof(double);
  3803. }
  3804. cvStartWriteStruct( fs, k == 0 ? "vertices" : "edges",
  3805. CV_NODE_SEQ + CV_NODE_FLOW );
  3806. cvStartReadSeq( (CvSeq*)data, &reader );
  3807. for( i = 0; i < data->total; i++ )
  3808. {
  3809. if( CV_IS_SET_ELEM( reader.ptr ))
  3810. {
  3811. if( k == 0 ) // vertices
  3812. memcpy( src_ptr, reader.ptr + sizeof(CvGraphVtx), write_elem_size );
  3813. else
  3814. {
  3815. CvGraphEdge* edge = (CvGraphEdge*)reader.ptr;
  3816. src_ptr = (char*)cvAlignPtr( src_ptr, sizeof(int) );
  3817. ((int*)src_ptr)[0] = edge->vtx[0]->flags;
  3818. ((int*)src_ptr)[1] = edge->vtx[1]->flags;
  3819. *(float*)(src_ptr + sizeof(int)*2) = edge->weight;
  3820. if( elem_size > (int)sizeof(CvGraphEdge) )
  3821. {
  3822. char* src_ptr2 = (char*)cvAlignPtr( src_ptr + 2*sizeof(int)
  3823. + sizeof(float), edge_user_align );
  3824. memcpy( src_ptr2, edge + 1, elem_size - sizeof(CvGraphEdge) );
  3825. }
  3826. }
  3827. src_ptr += write_elem_size;
  3828. if( ++write_count >= write_max )
  3829. {
  3830. cvWriteRawData( fs, write_buf, write_count, dt );
  3831. write_count = 0;
  3832. src_ptr = write_buf;
  3833. }
  3834. }
  3835. CV_NEXT_SEQ_ELEM( data->elem_size, reader );
  3836. }
  3837. if( write_count > 0 )
  3838. cvWriteRawData( fs, write_buf, write_count, dt );
  3839. cvEndWriteStruct( fs );
  3840. }
  3841. }
  3842. cvEndWriteStruct( fs );
  3843. // final stage. restore the graph flags
  3844. cvStartReadSeq( (CvSeq*)graph, &reader );
  3845. vtx_count = 0;
  3846. for( i = 0; i < graph->total; i++ )
  3847. {
  3848. if( CV_IS_SET_ELEM( reader.ptr ))
  3849. ((CvGraphVtx*)reader.ptr)->flags = flag_buf[vtx_count++];
  3850. CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
  3851. }
  3852. cvFree( &write_buf );
  3853. cvFree( &flag_buf );
  3854. }
  3855. static void*
  3856. icvReadGraph( CvFileStorage* fs, CvFileNode* node )
  3857. {
  3858. void* ptr = 0;
  3859. char* read_buf = 0;
  3860. CvGraphVtx** vtx_buf = 0;
  3861. CvGraph* graph;
  3862. CvFileNode *header_node, *vtx_node, *edge_node;
  3863. int flags, vtx_count, edge_count;
  3864. int vtx_size = sizeof(CvGraphVtx), edge_size, header_size = sizeof(CvGraph);
  3865. int src_vtx_size = 0, src_edge_size;
  3866. int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
  3867. int vtx_items_per_elem = 0, edge_items_per_elem = 0;
  3868. int edge_user_align = sizeof(float);
  3869. int read_buf_size;
  3870. int i, k;
  3871. const char* flags_str;
  3872. const char* header_dt;
  3873. const char* vtx_dt;
  3874. const char* edge_dt;
  3875. char* endptr = 0;
  3876. flags_str = cvReadStringByName( fs, node, "flags", 0 );
  3877. vtx_dt = cvReadStringByName( fs, node, "vertex_dt", 0 );
  3878. edge_dt = cvReadStringByName( fs, node, "edge_dt", 0 );
  3879. vtx_count = cvReadIntByName( fs, node, "vertex_count", -1 );
  3880. edge_count = cvReadIntByName( fs, node, "edge_count", -1 );
  3881. if( !flags_str || vtx_count == -1 || edge_count == -1 || !edge_dt )
  3882. CV_Error( CV_StsError, "Some of essential graph attributes are absent" );
  3883. flags = CV_SET_MAGIC_VAL + CV_GRAPH;
  3884. if( isxdigit(flags_str[0]) )
  3885. {
  3886. const int OLD_SEQ_ELTYPE_BITS = 9;
  3887. const int OLD_SEQ_KIND_BITS = 3;
  3888. const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS;
  3889. const int OLD_GRAPH_FLAG_ORIENTED = 1 << OLD_SEQ_FLAG_SHIFT;
  3890. int flags0 = (int)strtol( flags_str, &endptr, 16 );
  3891. if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SET_MAGIC_VAL )
  3892. CV_Error( CV_StsError, "The sequence flags are invalid" );
  3893. if( flags0 & OLD_GRAPH_FLAG_ORIENTED )
  3894. flags |= CV_GRAPH_FLAG_ORIENTED;
  3895. }
  3896. else
  3897. {
  3898. if( strstr(flags_str, "oriented") )
  3899. flags |= CV_GRAPH_FLAG_ORIENTED;
  3900. }
  3901. header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
  3902. header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
  3903. if( (header_dt != 0) ^ (header_node != 0) )
  3904. CV_Error( CV_StsError,
  3905. "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
  3906. if( header_dt )
  3907. header_size = icvCalcElemSize( header_dt, header_size );
  3908. if( vtx_dt )
  3909. {
  3910. src_vtx_size = icvCalcElemSize( vtx_dt, 0 );
  3911. vtx_size = icvCalcElemSize( vtx_dt, vtx_size );
  3912. fmt_pair_count = icvDecodeFormat( edge_dt,
  3913. fmt_pairs, CV_FS_MAX_FMT_PAIRS );
  3914. fmt_pair_count *= 2;
  3915. for( i = 0; i < fmt_pair_count; i += 2 )
  3916. vtx_items_per_elem += fmt_pairs[i];
  3917. }
  3918. {
  3919. char dst_edge_dt_buf[128];
  3920. const char* dst_edge_dt = 0;
  3921. fmt_pair_count = icvDecodeFormat( edge_dt,
  3922. fmt_pairs, CV_FS_MAX_FMT_PAIRS );
  3923. if( fmt_pair_count < 2 ||
  3924. fmt_pairs[0] != 2 || fmt_pairs[1] != CV_32S ||
  3925. fmt_pairs[2] < 1 || fmt_pairs[3] != CV_32F )
  3926. CV_Error( CV_StsBadArg,
  3927. "Graph edges should start with 2 integers and a float" );
  3928. // alignment of user part of the edge data following 2if
  3929. if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[5]) >= (int)sizeof(double))
  3930. edge_user_align = sizeof(double);
  3931. fmt_pair_count *= 2;
  3932. for( i = 0; i < fmt_pair_count; i += 2 )
  3933. edge_items_per_elem += fmt_pairs[i];
  3934. if( edge_dt[2] == 'f' || (edge_dt[2] == '1' && edge_dt[3] == 'f') )
  3935. dst_edge_dt = edge_dt + 3 + cv_isdigit(edge_dt[2]);
  3936. else
  3937. {
  3938. int val = (int)strtol( edge_dt + 2, &endptr, 10 );
  3939. sprintf( dst_edge_dt_buf, "%df%s", val-1, endptr );
  3940. dst_edge_dt = dst_edge_dt_buf;
  3941. }
  3942. edge_size = icvCalcElemSize( dst_edge_dt, sizeof(CvGraphEdge) );
  3943. src_edge_size = icvCalcElemSize( edge_dt, 0 );
  3944. }
  3945. graph = cvCreateGraph( flags, header_size, vtx_size, edge_size, fs->dststorage );
  3946. if( header_node )
  3947. cvReadRawData( fs, header_node, (char*)graph + sizeof(CvGraph), header_dt );
  3948. read_buf_size = MAX( src_vtx_size*3, 1 << 16 );
  3949. read_buf_size = MAX( src_edge_size*3, read_buf_size );
  3950. read_buf = (char*)cvAlloc( read_buf_size );
  3951. vtx_buf = (CvGraphVtx**)cvAlloc( vtx_count * sizeof(vtx_buf[0]) );
  3952. vtx_node = cvGetFileNodeByName( fs, node, "vertices" );
  3953. edge_node = cvGetFileNodeByName( fs, node, "edges" );
  3954. if( !edge_node )
  3955. CV_Error( CV_StsBadArg, "No edges data" );
  3956. if( vtx_dt && !vtx_node )
  3957. CV_Error( CV_StsBadArg, "No vertices data" );
  3958. // as vertices and edges are read in similar way,
  3959. // do it as a parametrized 2-iteration loop
  3960. for( k = 0; k < 2; k++ )
  3961. {
  3962. const char* dt = k == 0 ? vtx_dt : edge_dt;
  3963. int elem_size = k == 0 ? vtx_size : edge_size;
  3964. int src_elem_size = k == 0 ? src_vtx_size : src_edge_size;
  3965. int items_per_elem = k == 0 ? vtx_items_per_elem : edge_items_per_elem;
  3966. int elem_count = k == 0 ? vtx_count : edge_count;
  3967. char* dst_ptr = read_buf;
  3968. int read_max = read_buf_size /MAX(src_elem_size, 1), read_count = 0;
  3969. CvSeqReader reader;
  3970. if(dt)
  3971. cvStartReadRawData( fs, k == 0 ? vtx_node : edge_node, &reader );
  3972. for( i = 0; i < elem_count; i++ )
  3973. {
  3974. if( read_count == 0 && dt )
  3975. {
  3976. int count = MIN( elem_count - i, read_max )*items_per_elem;
  3977. cvReadRawDataSlice( fs, &reader, count, read_buf, dt );
  3978. read_count = count;
  3979. dst_ptr = read_buf;
  3980. }
  3981. if( k == 0 )
  3982. {
  3983. CvGraphVtx* vtx;
  3984. cvGraphAddVtx( graph, 0, &vtx );
  3985. vtx_buf[i] = vtx;
  3986. if( dt )
  3987. memcpy( vtx + 1, dst_ptr, src_elem_size );
  3988. }
  3989. else
  3990. {
  3991. CvGraphEdge* edge = 0;
  3992. int vtx1 = ((int*)dst_ptr)[0];
  3993. int vtx2 = ((int*)dst_ptr)[1];
  3994. int result;
  3995. if( (unsigned)vtx1 >= (unsigned)vtx_count ||
  3996. (unsigned)vtx2 >= (unsigned)vtx_count )
  3997. CV_Error( CV_StsOutOfRange,
  3998. "Some of stored vertex indices are out of range" );
  3999. result = cvGraphAddEdgeByPtr( graph,
  4000. vtx_buf[vtx1], vtx_buf[vtx2], 0, &edge );
  4001. if( result == 0 )
  4002. CV_Error( CV_StsBadArg, "Duplicated edge has occured" );
  4003. edge->weight = *(float*)(dst_ptr + sizeof(int)*2);
  4004. if( elem_size > (int)sizeof(CvGraphEdge) )
  4005. {
  4006. char* dst_ptr2 = (char*)cvAlignPtr( dst_ptr + sizeof(int)*2 +
  4007. sizeof(float), edge_user_align );
  4008. memcpy( edge + 1, dst_ptr2, elem_size - sizeof(CvGraphEdge) );
  4009. }
  4010. }
  4011. dst_ptr += src_elem_size;
  4012. read_count--;
  4013. }
  4014. }
  4015. ptr = graph;
  4016. cvFree( &read_buf );
  4017. cvFree( &vtx_buf );
  4018. return ptr;
  4019. }
  4020. /****************************************************************************************\
  4021. * RTTI Functions *
  4022. \****************************************************************************************/
  4023. CvTypeInfo *CvType::first = 0, *CvType::last = 0;
  4024. CvType::CvType( const char* type_name,
  4025. CvIsInstanceFunc is_instance, CvReleaseFunc release,
  4026. CvReadFunc read, CvWriteFunc write, CvCloneFunc clone )
  4027. {
  4028. CvTypeInfo _info;
  4029. _info.flags = 0;
  4030. _info.header_size = sizeof(_info);
  4031. _info.type_name = type_name;
  4032. _info.prev = _info.next = 0;
  4033. _info.is_instance = is_instance;
  4034. _info.release = release;
  4035. _info.clone = clone;
  4036. _info.read = read;
  4037. _info.write = write;
  4038. cvRegisterType( &_info );
  4039. info = first;
  4040. }
  4041. CvType::~CvType()
  4042. {
  4043. cvUnregisterType( info->type_name );
  4044. }
  4045. CvType seq_type( CV_TYPE_NAME_SEQ, icvIsSeq, icvReleaseSeq, icvReadSeq,
  4046. icvWriteSeqTree /* this is the entry point for
  4047. writing a single sequence too */, icvCloneSeq );
  4048. CvType seq_tree_type( CV_TYPE_NAME_SEQ_TREE, icvIsSeq, icvReleaseSeq,
  4049. icvReadSeqTree, icvWriteSeqTree, icvCloneSeq );
  4050. CvType seq_graph_type( CV_TYPE_NAME_GRAPH, icvIsGraph, icvReleaseGraph,
  4051. icvReadGraph, icvWriteGraph, icvCloneGraph );
  4052. CvType sparse_mat_type( CV_TYPE_NAME_SPARSE_MAT, icvIsSparseMat,
  4053. (CvReleaseFunc)cvReleaseSparseMat, icvReadSparseMat,
  4054. icvWriteSparseMat, (CvCloneFunc)cvCloneSparseMat );
  4055. CvType image_type( CV_TYPE_NAME_IMAGE, icvIsImage, (CvReleaseFunc)cvReleaseImage,
  4056. icvReadImage, icvWriteImage, (CvCloneFunc)cvCloneImage );
  4057. CvType mat_type( CV_TYPE_NAME_MAT, icvIsMat, (CvReleaseFunc)cvReleaseMat,
  4058. icvReadMat, icvWriteMat, (CvCloneFunc)cvCloneMat );
  4059. CvType matnd_type( CV_TYPE_NAME_MATND, icvIsMatND, (CvReleaseFunc)cvReleaseMatND,
  4060. icvReadMatND, icvWriteMatND, (CvCloneFunc)cvCloneMatND );
  4061. CV_IMPL void
  4062. cvRegisterType( const CvTypeInfo* _info )
  4063. {
  4064. CvTypeInfo* info = 0;
  4065. int i, len;
  4066. char c;
  4067. //if( !CvType::first )
  4068. // icvCreateStandardTypes();
  4069. if( !_info || _info->header_size != sizeof(CvTypeInfo) )
  4070. CV_Error( CV_StsBadSize, "Invalid type info" );
  4071. if( !_info->is_instance || !_info->release ||
  4072. !_info->read || !_info->write )
  4073. CV_Error( CV_StsNullPtr,
  4074. "Some of required function pointers "
  4075. "(is_instance, release, read or write) are NULL");
  4076. c = _info->type_name[0];
  4077. if( !cv_isalpha(c) && c != '_' )
  4078. CV_Error( CV_StsBadArg, "Type name should start with a letter or _" );
  4079. len = (int)strlen(_info->type_name);
  4080. for( i = 0; i < len; i++ )
  4081. {
  4082. c = _info->type_name[i];
  4083. if( !cv_isalnum(c) && c != '-' && c != '_' )
  4084. CV_Error( CV_StsBadArg,
  4085. "Type name should contain only letters, digits, - and _" );
  4086. }
  4087. info = (CvTypeInfo*)malloc( sizeof(*info) + len + 1 );
  4088. *info = *_info;
  4089. info->type_name = (char*)(info + 1);
  4090. memcpy( (char*)info->type_name, _info->type_name, len + 1 );
  4091. info->flags = 0;
  4092. info->next = CvType::first;
  4093. info->prev = 0;
  4094. if( CvType::first )
  4095. CvType::first->prev = info;
  4096. else
  4097. CvType::last = info;
  4098. CvType::first = info;
  4099. }
  4100. CV_IMPL void
  4101. cvUnregisterType( const char* type_name )
  4102. {
  4103. CvTypeInfo* info;
  4104. info = cvFindType( type_name );
  4105. if( info )
  4106. {
  4107. if( info->prev )
  4108. info->prev->next = info->next;
  4109. else
  4110. CvType::first = info->next;
  4111. if( info->next )
  4112. info->next->prev = info->prev;
  4113. else
  4114. CvType::last = info->prev;
  4115. if( !CvType::first || !CvType::last )
  4116. CvType::first = CvType::last = 0;
  4117. free( info );
  4118. }
  4119. }
  4120. CV_IMPL CvTypeInfo*
  4121. cvFirstType( void )
  4122. {
  4123. return CvType::first;
  4124. }
  4125. CV_IMPL CvTypeInfo*
  4126. cvFindType( const char* type_name )
  4127. {
  4128. CvTypeInfo* info = 0;
  4129. if (type_name)
  4130. for( info = CvType::first; info != 0; info = info->next )
  4131. if( strcmp( info->type_name, type_name ) == 0 )
  4132. break;
  4133. return info;
  4134. }
  4135. CV_IMPL CvTypeInfo*
  4136. cvTypeOf( const void* struct_ptr )
  4137. {
  4138. CvTypeInfo* info = 0;
  4139. if( struct_ptr )
  4140. {
  4141. for( info = CvType::first; info != 0; info = info->next )
  4142. if( info->is_instance( struct_ptr ))
  4143. break;
  4144. }
  4145. return info;
  4146. }
  4147. /* universal functions */
  4148. CV_IMPL void
  4149. cvRelease( void** struct_ptr )
  4150. {
  4151. CvTypeInfo* info;
  4152. if( !struct_ptr )
  4153. CV_Error( CV_StsNullPtr, "NULL double pointer" );
  4154. if( *struct_ptr )
  4155. {
  4156. info = cvTypeOf( *struct_ptr );
  4157. if( !info )
  4158. CV_Error( CV_StsError, "Unknown object type" );
  4159. if( !info->release )
  4160. CV_Error( CV_StsError, "release function pointer is NULL" );
  4161. info->release( struct_ptr );
  4162. *struct_ptr = 0;
  4163. }
  4164. }
  4165. void* cvClone( const void* struct_ptr )
  4166. {
  4167. void* struct_copy = 0;
  4168. CvTypeInfo* info;
  4169. if( !struct_ptr )
  4170. CV_Error( CV_StsNullPtr, "NULL structure pointer" );
  4171. info = cvTypeOf( struct_ptr );
  4172. if( !info )
  4173. CV_Error( CV_StsError, "Unknown object type" );
  4174. if( !info->clone )
  4175. CV_Error( CV_StsError, "clone function pointer is NULL" );
  4176. struct_copy = info->clone( struct_ptr );
  4177. return struct_copy;
  4178. }
  4179. /* reads matrix, image, sequence, graph etc. */
  4180. CV_IMPL void*
  4181. cvRead( CvFileStorage* fs, CvFileNode* node, CvAttrList* list )
  4182. {
  4183. void* obj = 0;
  4184. CV_CHECK_FILE_STORAGE( fs );
  4185. if( !node )
  4186. return 0;
  4187. if( !CV_NODE_IS_USER(node->tag) || !node->info )
  4188. CV_Error( CV_StsError, "The node does not represent a user object (unknown type?)" );
  4189. obj = node->info->read( fs, node );
  4190. if( list )
  4191. *list = cvAttrList(0,0);
  4192. return obj;
  4193. }
  4194. /* writes matrix, image, sequence, graph etc. */
  4195. CV_IMPL void
  4196. cvWrite( CvFileStorage* fs, const char* name,
  4197. const void* ptr, CvAttrList attributes )
  4198. {
  4199. CvTypeInfo* info;
  4200. CV_CHECK_OUTPUT_FILE_STORAGE( fs );
  4201. if( !ptr )
  4202. CV_Error( CV_StsNullPtr, "Null pointer to the written object" );
  4203. info = cvTypeOf( ptr );
  4204. if( !info )
  4205. CV_Error( CV_StsBadArg, "Unknown object" );
  4206. if( !info->write )
  4207. CV_Error( CV_StsBadArg, "The object does not have write function" );
  4208. info->write( fs, name, ptr, attributes );
  4209. }
  4210. /* simple API for reading/writing data */
  4211. CV_IMPL void
  4212. cvSave( const char* filename, const void* struct_ptr,
  4213. const char* _name, const char* comment, CvAttrList attributes )
  4214. {
  4215. CvFileStorage* fs = 0;
  4216. if( !struct_ptr )
  4217. CV_Error( CV_StsNullPtr, "NULL object pointer" );
  4218. fs = cvOpenFileStorage( filename, 0, CV_STORAGE_WRITE );
  4219. if( !fs )
  4220. CV_Error( CV_StsError, "Could not open the file storage. Check the path and permissions" );
  4221. cv::String name = _name ? cv::String(_name) : cv::FileStorage::getDefaultObjectName(filename);
  4222. if( comment )
  4223. cvWriteComment( fs, comment, 0 );
  4224. cvWrite( fs, name.c_str(), struct_ptr, attributes );
  4225. cvReleaseFileStorage( &fs );
  4226. }
  4227. CV_IMPL void*
  4228. cvLoad( const char* filename, CvMemStorage* memstorage,
  4229. const char* name, const char** _real_name )
  4230. {
  4231. void* ptr = 0;
  4232. const char* real_name = 0;
  4233. cv::FileStorage fs(cvOpenFileStorage(filename, memstorage, CV_STORAGE_READ));
  4234. CvFileNode* node = 0;
  4235. if( !fs.isOpened() )
  4236. return 0;
  4237. if( name )
  4238. {
  4239. node = cvGetFileNodeByName( *fs, 0, name );
  4240. }
  4241. else
  4242. {
  4243. int i, k;
  4244. for( k = 0; k < (*fs)->roots->total; k++ )
  4245. {
  4246. CvSeq* seq;
  4247. CvSeqReader reader;
  4248. node = (CvFileNode*)cvGetSeqElem( (*fs)->roots, k );
  4249. if( !CV_NODE_IS_MAP( node->tag ))
  4250. return 0;
  4251. seq = node->data.seq;
  4252. node = 0;
  4253. cvStartReadSeq( seq, &reader, 0 );
  4254. // find the first element in the map
  4255. for( i = 0; i < seq->total; i++ )
  4256. {
  4257. if( CV_IS_SET_ELEM( reader.ptr ))
  4258. {
  4259. node = (CvFileNode*)reader.ptr;
  4260. goto stop_search;
  4261. }
  4262. CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
  4263. }
  4264. }
  4265. stop_search:
  4266. ;
  4267. }
  4268. if( !node )
  4269. CV_Error( CV_StsObjectNotFound, "Could not find the/an object in file storage" );
  4270. real_name = cvGetFileNodeName( node );
  4271. ptr = cvRead( *fs, node, 0 );
  4272. // sanity check
  4273. if( !memstorage && (CV_IS_SEQ( ptr ) || CV_IS_SET( ptr )) )
  4274. CV_Error( CV_StsNullPtr,
  4275. "NULL memory storage is passed - the loaded dynamic structure can not be stored" );
  4276. if( cvGetErrStatus() < 0 )
  4277. {
  4278. cvRelease( (void**)&ptr );
  4279. real_name = 0;
  4280. }
  4281. if( _real_name)
  4282. {
  4283. if (real_name)
  4284. {
  4285. *_real_name = (const char*)cvAlloc(strlen(real_name));
  4286. memcpy((void*)*_real_name, real_name, strlen(real_name));
  4287. } else {
  4288. *_real_name = 0;
  4289. }
  4290. }
  4291. return ptr;
  4292. }
  4293. ///////////////////////// new C++ interface for CvFileStorage ///////////////////////////
  4294. namespace cv
  4295. {
  4296. static void getElemSize( const String& fmt, size_t& elemSize, size_t& cn )
  4297. {
  4298. const char* dt = fmt.c_str();
  4299. cn = 1;
  4300. if( cv_isdigit(dt[0]) )
  4301. {
  4302. cn = dt[0] - '0';
  4303. dt++;
  4304. }
  4305. char c = dt[0];
  4306. elemSize = cn*(c == 'u' || c == 'c' ? sizeof(uchar) : c == 'w' || c == 's' ? sizeof(ushort) :
  4307. c == 'i' ? sizeof(int) : c == 'f' ? sizeof(float) : c == 'd' ? sizeof(double) :
  4308. c == 'r' ? sizeof(void*) : (size_t)0);
  4309. }
  4310. FileStorage::FileStorage()
  4311. {
  4312. state = UNDEFINED;
  4313. }
  4314. FileStorage::FileStorage(const String& filename, int flags, const String& encoding)
  4315. {
  4316. state = UNDEFINED;
  4317. open( filename, flags, encoding );
  4318. }
  4319. FileStorage::FileStorage(CvFileStorage* _fs, bool owning)
  4320. {
  4321. if (owning) fs.reset(_fs);
  4322. else fs = Ptr<CvFileStorage>(Ptr<CvFileStorage>(), _fs);
  4323. state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
  4324. }
  4325. FileStorage::~FileStorage()
  4326. {
  4327. while( structs.size() > 0 )
  4328. {
  4329. cvEndWriteStruct(fs);
  4330. structs.pop_back();
  4331. }
  4332. }
  4333. bool FileStorage::open(const String& filename, int flags, const String& encoding)
  4334. {
  4335. release();
  4336. fs.reset(cvOpenFileStorage( filename.c_str(), 0, flags,
  4337. !encoding.empty() ? encoding.c_str() : 0));
  4338. bool ok = isOpened();
  4339. state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
  4340. return ok;
  4341. }
  4342. bool FileStorage::isOpened() const
  4343. {
  4344. return fs && fs->is_opened;
  4345. }
  4346. void FileStorage::release()
  4347. {
  4348. fs.release();
  4349. structs.clear();
  4350. state = UNDEFINED;
  4351. }
  4352. String FileStorage::releaseAndGetString()
  4353. {
  4354. String buf;
  4355. if( fs && fs->outbuf )
  4356. icvClose(fs, &buf);
  4357. release();
  4358. return buf;
  4359. }
  4360. FileNode FileStorage::root(int streamidx) const
  4361. {
  4362. return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode();
  4363. }
  4364. FileStorage& operator << (FileStorage& fs, const String& str)
  4365. {
  4366. enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED,
  4367. VALUE_EXPECTED = FileStorage::VALUE_EXPECTED,
  4368. INSIDE_MAP = FileStorage::INSIDE_MAP };
  4369. const char* _str = str.c_str();
  4370. if( !fs.isOpened() || !_str )
  4371. return fs;
  4372. if( *_str == '}' || *_str == ']' )
  4373. {
  4374. if( fs.structs.empty() )
  4375. CV_Error_( CV_StsError, ("Extra closing '%c'", *_str) );
  4376. if( (*_str == ']' ? '[' : '{') != fs.structs.back() )
  4377. CV_Error_( CV_StsError,
  4378. ("The closing '%c' does not match the opening '%c'", *_str, fs.structs.back()));
  4379. fs.structs.pop_back();
  4380. fs.state = fs.structs.empty() || fs.structs.back() == '{' ?
  4381. INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED;
  4382. cvEndWriteStruct( *fs );
  4383. fs.elname = String();
  4384. }
  4385. else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
  4386. {
  4387. if( !cv_isalpha(*_str) )
  4388. CV_Error_( CV_StsError, ("Incorrect element name %s", _str) );
  4389. fs.elname = str;
  4390. fs.state = VALUE_EXPECTED + INSIDE_MAP;
  4391. }
  4392. else if( (fs.state & 3) == VALUE_EXPECTED )
  4393. {
  4394. if( *_str == '{' || *_str == '[' )
  4395. {
  4396. fs.structs.push_back(*_str);
  4397. int flags = *_str++ == '{' ? CV_NODE_MAP : CV_NODE_SEQ;
  4398. fs.state = flags == CV_NODE_MAP ? INSIDE_MAP +
  4399. NAME_EXPECTED : VALUE_EXPECTED;
  4400. if( *_str == ':' )
  4401. {
  4402. flags |= CV_NODE_FLOW;
  4403. _str++;
  4404. }
  4405. cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0,
  4406. flags, *_str ? _str : 0 );
  4407. fs.elname = String();
  4408. }
  4409. else
  4410. {
  4411. write( fs, fs.elname, (_str[0] == '\\' && (_str[1] == '{' || _str[1] == '}' ||
  4412. _str[1] == '[' || _str[1] == ']')) ? String(_str+1) : str );
  4413. if( fs.state == INSIDE_MAP + VALUE_EXPECTED )
  4414. fs.state = INSIDE_MAP + NAME_EXPECTED;
  4415. }
  4416. }
  4417. else
  4418. CV_Error( CV_StsError, "Invalid fs.state" );
  4419. return fs;
  4420. }
  4421. void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len )
  4422. {
  4423. if( !isOpened() )
  4424. return;
  4425. size_t elemSize, cn;
  4426. getElemSize( fmt, elemSize, cn );
  4427. CV_Assert( len % elemSize == 0 );
  4428. cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str());
  4429. }
  4430. void FileStorage::writeObj( const String& name, const void* obj )
  4431. {
  4432. if( !isOpened() )
  4433. return;
  4434. cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj );
  4435. }
  4436. FileNode FileStorage::operator[](const String& nodename) const
  4437. {
  4438. return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str()));
  4439. }
  4440. FileNode FileStorage::operator[](const char* nodename) const
  4441. {
  4442. return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename));
  4443. }
  4444. FileNode FileNode::operator[](const String& nodename) const
  4445. {
  4446. return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str()));
  4447. }
  4448. FileNode FileNode::operator[](const char* nodename) const
  4449. {
  4450. return FileNode(fs, cvGetFileNodeByName(fs, node, nodename));
  4451. }
  4452. FileNode FileNode::operator[](int i) const
  4453. {
  4454. return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) :
  4455. i == 0 ? *this : FileNode();
  4456. }
  4457. String FileNode::name() const
  4458. {
  4459. const char* str;
  4460. return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str);
  4461. }
  4462. void* FileNode::readObj() const
  4463. {
  4464. if( !fs || !node )
  4465. return 0;
  4466. return cvRead( (CvFileStorage*)fs, (CvFileNode*)node );
  4467. }
  4468. FileNodeIterator::FileNodeIterator()
  4469. {
  4470. fs = 0;
  4471. container = 0;
  4472. reader.ptr = 0;
  4473. remaining = 0;
  4474. }
  4475. FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs,
  4476. const CvFileNode* _node, size_t _ofs)
  4477. {
  4478. if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE )
  4479. {
  4480. int node_type = _node->tag & FileNode::TYPE_MASK;
  4481. fs = _fs;
  4482. container = _node;
  4483. if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) )
  4484. {
  4485. cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader );
  4486. remaining = FileNode(_fs, _node).size();
  4487. }
  4488. else
  4489. {
  4490. reader.ptr = (schar*)_node;
  4491. reader.seq = 0;
  4492. remaining = 1;
  4493. }
  4494. (*this) += (int)_ofs;
  4495. }
  4496. else
  4497. {
  4498. fs = 0;
  4499. container = 0;
  4500. reader.ptr = 0;
  4501. remaining = 0;
  4502. }
  4503. }
  4504. FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
  4505. {
  4506. fs = it.fs;
  4507. container = it.container;
  4508. reader = it.reader;
  4509. remaining = it.remaining;
  4510. }
  4511. FileNodeIterator& FileNodeIterator::operator ++()
  4512. {
  4513. if( remaining > 0 )
  4514. {
  4515. if( reader.seq )
  4516. {
  4517. if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max )
  4518. {
  4519. cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 );
  4520. }
  4521. }
  4522. remaining--;
  4523. }
  4524. return *this;
  4525. }
  4526. FileNodeIterator FileNodeIterator::operator ++(int)
  4527. {
  4528. FileNodeIterator it = *this;
  4529. ++(*this);
  4530. return it;
  4531. }
  4532. FileNodeIterator& FileNodeIterator::operator --()
  4533. {
  4534. if( remaining < FileNode(fs, container).size() )
  4535. {
  4536. if( reader.seq )
  4537. {
  4538. if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min )
  4539. {
  4540. cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 );
  4541. }
  4542. }
  4543. remaining++;
  4544. }
  4545. return *this;
  4546. }
  4547. FileNodeIterator FileNodeIterator::operator --(int)
  4548. {
  4549. FileNodeIterator it = *this;
  4550. --(*this);
  4551. return it;
  4552. }
  4553. FileNodeIterator& FileNodeIterator::operator += (int ofs)
  4554. {
  4555. if( ofs == 0 )
  4556. return *this;
  4557. if( ofs > 0 )
  4558. ofs = std::min(ofs, (int)remaining);
  4559. else
  4560. {
  4561. size_t count = FileNode(fs, container).size();
  4562. ofs = (int)(remaining - std::min(remaining - ofs, count));
  4563. }
  4564. remaining -= ofs;
  4565. if( reader.seq )
  4566. cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 );
  4567. return *this;
  4568. }
  4569. FileNodeIterator& FileNodeIterator::operator -= (int ofs)
  4570. {
  4571. return operator += (-ofs);
  4572. }
  4573. FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount )
  4574. {
  4575. if( fs && container && remaining > 0 )
  4576. {
  4577. size_t elem_size, cn;
  4578. getElemSize( fmt, elem_size, cn );
  4579. CV_Assert( elem_size > 0 );
  4580. size_t count = std::min(remaining, maxCount);
  4581. if( reader.seq )
  4582. {
  4583. cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() );
  4584. remaining -= count*cn;
  4585. }
  4586. else
  4587. {
  4588. cvReadRawData( fs, container, vec, fmt.c_str() );
  4589. remaining = 0;
  4590. }
  4591. }
  4592. return *this;
  4593. }
  4594. void write( FileStorage& fs, const String& name, int value )
  4595. { cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); }
  4596. void write( FileStorage& fs, const String& name, float value )
  4597. { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
  4598. void write( FileStorage& fs, const String& name, double value )
  4599. { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
  4600. void write( FileStorage& fs, const String& name, const String& value )
  4601. { cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); }
  4602. void writeScalar(FileStorage& fs, int value )
  4603. { cvWriteInt( *fs, 0, value ); }
  4604. void writeScalar(FileStorage& fs, float value )
  4605. { cvWriteReal( *fs, 0, value ); }
  4606. void writeScalar(FileStorage& fs, double value )
  4607. { cvWriteReal( *fs, 0, value ); }
  4608. void writeScalar(FileStorage& fs, const String& value )
  4609. { cvWriteString( *fs, 0, value.c_str() ); }
  4610. void write( FileStorage& fs, const String& name, const Mat& value )
  4611. {
  4612. if( value.dims <= 2 )
  4613. {
  4614. CvMat mat = value;
  4615. cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
  4616. }
  4617. else
  4618. {
  4619. CvMatND mat = value;
  4620. cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
  4621. }
  4622. }
  4623. // TODO: the 4 functions below need to be implemented more efficiently
  4624. void write( FileStorage& fs, const String& name, const SparseMat& value )
  4625. {
  4626. Ptr<CvSparseMat> mat(cvCreateSparseMat(value));
  4627. cvWrite( *fs, name.size() ? name.c_str() : 0, mat );
  4628. }
  4629. internal::WriteStructContext::WriteStructContext(FileStorage& _fs,
  4630. const String& name, int flags, const String& typeName) : fs(&_fs)
  4631. {
  4632. cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags,
  4633. !typeName.empty() ? typeName.c_str() : 0);
  4634. }
  4635. internal::WriteStructContext::~WriteStructContext()
  4636. {
  4637. cvEndWriteStruct(**fs);
  4638. }
  4639. void read( const FileNode& node, Mat& mat, const Mat& default_mat )
  4640. {
  4641. if( node.empty() )
  4642. {
  4643. default_mat.copyTo(mat);
  4644. return;
  4645. }
  4646. void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node);
  4647. if(CV_IS_MAT_HDR_Z(obj))
  4648. {
  4649. cvarrToMat(obj).copyTo(mat);
  4650. cvReleaseMat((CvMat**)&obj);
  4651. }
  4652. else if(CV_IS_MATND_HDR(obj))
  4653. {
  4654. cvarrToMat(obj).copyTo(mat);
  4655. cvReleaseMatND((CvMatND**)&obj);
  4656. }
  4657. else
  4658. {
  4659. cvRelease(&obj);
  4660. CV_Error(CV_StsBadArg, "Unknown array type");
  4661. }
  4662. }
  4663. void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat )
  4664. {
  4665. if( node.empty() )
  4666. {
  4667. default_mat.copyTo(mat);
  4668. return;
  4669. }
  4670. Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node));
  4671. CV_Assert(CV_IS_SPARSE_MAT(m));
  4672. m->copyToSparseMat(mat);
  4673. }
  4674. void write(FileStorage& fs, const String& objname, const std::vector<KeyPoint>& keypoints)
  4675. {
  4676. internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);
  4677. int i, npoints = (int)keypoints.size();
  4678. for( i = 0; i < npoints; i++ )
  4679. {
  4680. const KeyPoint& kpt = keypoints[i];
  4681. cv::write(fs, kpt.pt.x);
  4682. cv::write(fs, kpt.pt.y);
  4683. cv::write(fs, kpt.size);
  4684. cv::write(fs, kpt.angle);
  4685. cv::write(fs, kpt.response);
  4686. cv::write(fs, kpt.octave);
  4687. cv::write(fs, kpt.class_id);
  4688. }
  4689. }
  4690. void read(const FileNode& node, std::vector<KeyPoint>& keypoints)
  4691. {
  4692. keypoints.resize(0);
  4693. FileNodeIterator it = node.begin(), it_end = node.end();
  4694. for( ; it != it_end; )
  4695. {
  4696. KeyPoint kpt;
  4697. it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
  4698. keypoints.push_back(kpt);
  4699. }
  4700. }
  4701. int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); }
  4702. bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; }
  4703. size_t FileNode::size() const
  4704. {
  4705. int t = type();
  4706. return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count :
  4707. t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone();
  4708. }
  4709. void read(const FileNode& node, int& value, int default_value)
  4710. {
  4711. value = !node.node ? default_value :
  4712. CV_NODE_IS_INT(node.node->tag) ? node.node->data.i :
  4713. CV_NODE_IS_REAL(node.node->tag) ? cvRound(node.node->data.f) : 0x7fffffff;
  4714. }
  4715. void read(const FileNode& node, float& value, float default_value)
  4716. {
  4717. value = !node.node ? default_value :
  4718. CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i :
  4719. CV_NODE_IS_REAL(node.node->tag) ? (float)node.node->data.f : 1e30f;
  4720. }
  4721. void read(const FileNode& node, double& value, double default_value)
  4722. {
  4723. value = !node.node ? default_value :
  4724. CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i :
  4725. CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : 1e300;
  4726. }
  4727. void read(const FileNode& node, String& value, const String& default_value)
  4728. {
  4729. value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String();
  4730. }
  4731. }
  4732. /* End of file. */