1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html
7 #include "persistence.hpp"
9 ///////////////////////// new C++ interface for CvFileStorage ///////////////////////////
14 static void getElemSize( const String& fmt, size_t& elemSize, size_t& cn )
16 const char* dt = fmt.c_str();
18 if( cv_isdigit(dt[0]) )
24 elemSize = cn*(c == 'u' || c == 'c' ? sizeof(uchar) : c == 'w' || c == 's' ? sizeof(ushort) :
25 c == 'i' ? sizeof(int) : c == 'f' ? sizeof(float) : c == 'd' ? sizeof(double) :
26 c == 'r' ? sizeof(void*) : (size_t)0);
29 FileStorage::FileStorage()
34 FileStorage::FileStorage(const String& filename, int flags, const String& encoding)
37 open( filename, flags, encoding );
40 FileStorage::FileStorage(CvFileStorage* _fs, bool owning)
42 if (owning) fs.reset(_fs);
43 else fs = Ptr<CvFileStorage>(Ptr<CvFileStorage>(), _fs);
45 state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
48 FileStorage::~FileStorage()
50 while( structs.size() > 0 )
57 bool FileStorage::open(const String& filename, int flags, const String& encoding)
59 CV_INSTRUMENT_REGION()
62 fs.reset(cvOpenFileStorage( filename.c_str(), 0, flags,
63 !encoding.empty() ? encoding.c_str() : 0));
65 state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
69 bool FileStorage::isOpened() const
71 return fs && fs->is_opened;
74 void FileStorage::release()
81 String FileStorage::releaseAndGetString()
84 if( fs && fs->outbuf )
91 FileNode FileStorage::root(int streamidx) const
93 return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode();
96 int FileStorage::getFormat() const
98 CV_Assert(!fs.empty());
99 return fs->fmt & FORMAT_MASK;
102 FileStorage& operator << (FileStorage& fs, const String& str)
104 CV_TRACE_REGION_VERBOSE();
106 enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED,
107 VALUE_EXPECTED = FileStorage::VALUE_EXPECTED,
108 INSIDE_MAP = FileStorage::INSIDE_MAP };
109 const char* _str = str.c_str();
110 if( !fs.isOpened() || !_str )
112 if( *_str == '}' || *_str == ']' )
114 if( fs.structs.empty() )
115 CV_Error_( CV_StsError, ("Extra closing '%c'", *_str) );
116 if( (*_str == ']' ? '[' : '{') != fs.structs.back() )
117 CV_Error_( CV_StsError,
118 ("The closing '%c' does not match the opening '%c'", *_str, fs.structs.back()));
119 fs.structs.pop_back();
120 fs.state = fs.structs.empty() || fs.structs.back() == '{' ?
121 INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED;
122 cvEndWriteStruct( *fs );
123 fs.elname = String();
125 else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
127 if (!cv_isalpha(*_str) && *_str != '_')
128 CV_Error_( CV_StsError, ("Incorrect element name %s", _str) );
130 fs.state = VALUE_EXPECTED + INSIDE_MAP;
132 else if( (fs.state & 3) == VALUE_EXPECTED )
134 if( *_str == '{' || *_str == '[' )
136 fs.structs.push_back(*_str);
137 int flags = *_str++ == '{' ? CV_NODE_MAP : CV_NODE_SEQ;
138 fs.state = flags == CV_NODE_MAP ? INSIDE_MAP +
139 NAME_EXPECTED : VALUE_EXPECTED;
142 flags |= CV_NODE_FLOW;
145 cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0,
146 flags, *_str ? _str : 0 );
147 fs.elname = String();
151 write( fs, fs.elname, (_str[0] == '\\' && (_str[1] == '{' || _str[1] == '}' ||
152 _str[1] == '[' || _str[1] == ']')) ? String(_str+1) : str );
153 if( fs.state == INSIDE_MAP + VALUE_EXPECTED )
154 fs.state = INSIDE_MAP + NAME_EXPECTED;
158 CV_Error( CV_StsError, "Invalid fs.state" );
163 void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len )
168 getElemSize( fmt, elemSize, cn );
169 CV_Assert( len % elemSize == 0 );
170 cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str());
174 void FileStorage::writeObj( const String& name, const void* obj )
178 cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj );
182 void FileStorage::write( const String& name, int val )
184 *this << name << val;
187 void FileStorage::write( const String& name, double val )
189 *this << name << val;
192 void FileStorage::write( const String& name, const String& val )
194 *this << name << val;
197 void FileStorage::write( const String& name, InputArray val )
199 *this << name << val.getMat();
202 void FileStorage::writeComment( const String& comment, bool append )
204 cvWriteComment(fs, comment.c_str(), append ? 1 : 0);
207 String FileStorage::getDefaultObjectName(const String& _filename)
209 static const char* stubname = "unnamed";
210 const char* filename = _filename.c_str();
211 const char* ptr2 = filename + _filename.size();
212 const char* ptr = ptr2 - 1;
213 cv::AutoBuffer<char> name_buf(_filename.size()+1);
215 while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
217 if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) )
223 CV_Error( CV_StsBadArg, "Invalid filename" );
225 char* name = name_buf.data();
227 // name must start with letter or '_'
228 if( !cv_isalpha(*ptr) && *ptr!= '_' ){
235 if( !cv_isalnum(c) && c != '-' && c != '_' )
240 name = name_buf.data();
241 if( strcmp( name, "_" ) == 0 )
242 strcpy( name, stubname );
246 FileNode FileStorage::operator[](const String& nodename) const
248 return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str()));
251 FileNode FileStorage::operator[](const char* nodename) const
253 return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename));
256 FileNode FileNode::operator[](const String& nodename) const
258 return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str()));
261 FileNode FileNode::operator[](const char* nodename) const
263 return FileNode(fs, cvGetFileNodeByName(fs, node, nodename));
266 FileNode FileNode::operator[](int i) const
268 return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) :
269 i == 0 ? *this : FileNode();
272 String FileNode::name() const
275 return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str);
278 void* FileNode::readObj() const
282 return cvRead( (CvFileStorage*)fs, (CvFileNode*)node );
285 static const FileNodeIterator::SeqReader emptyReader = {0, 0, 0, 0, 0, 0, 0, 0};
287 FileNodeIterator::FileNodeIterator()
291 reader = emptyReader;
295 FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs,
296 const CvFileNode* _node, size_t _ofs)
298 reader = emptyReader;
299 if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE )
301 int node_type = _node->tag & FileNode::TYPE_MASK;
304 if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) )
306 cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader );
307 remaining = FileNode(_fs, _node).size();
311 reader.ptr = (schar*)_node;
315 (*this) += (int)_ofs;
325 FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
328 container = it.container;
330 remaining = it.remaining;
333 FileNodeIterator& FileNodeIterator::operator ++()
339 if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max )
341 cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 );
349 FileNodeIterator FileNodeIterator::operator ++(int)
351 FileNodeIterator it = *this;
356 FileNodeIterator& FileNodeIterator::operator --()
358 if( remaining < FileNode(fs, container).size() )
362 if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min )
364 cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 );
372 FileNodeIterator FileNodeIterator::operator --(int)
374 FileNodeIterator it = *this;
379 FileNodeIterator& FileNodeIterator::operator += (int ofs)
384 ofs = std::min(ofs, (int)remaining);
387 size_t count = FileNode(fs, container).size();
388 ofs = (int)(remaining - std::min(remaining - ofs, count));
392 cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 );
396 FileNodeIterator& FileNodeIterator::operator -= (int ofs)
398 return operator += (-ofs);
402 FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount )
404 if( fs && container && remaining > 0 )
406 size_t elem_size, cn;
407 getElemSize( fmt, elem_size, cn );
408 CV_Assert( elem_size > 0 );
409 size_t count = std::min(remaining, maxCount);
413 cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() );
414 remaining -= count*cn;
418 cvReadRawData( fs, container, vec, fmt.c_str() );
426 void write( FileStorage& fs, const String& name, int value )
427 { cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); }
429 void write( FileStorage& fs, const String& name, float value )
430 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
432 void write( FileStorage& fs, const String& name, double value )
433 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
435 void write( FileStorage& fs, const String& name, const String& value )
436 { cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); }
438 void writeScalar(FileStorage& fs, int value )
439 { cvWriteInt( *fs, 0, value ); }
441 void writeScalar(FileStorage& fs, float value )
442 { cvWriteReal( *fs, 0, value ); }
444 void writeScalar(FileStorage& fs, double value )
445 { cvWriteReal( *fs, 0, value ); }
447 void writeScalar(FileStorage& fs, const String& value )
448 { cvWriteString( *fs, 0, value.c_str() ); }
451 void write( FileStorage& fs, const String& name, const Mat& value )
453 if( value.dims <= 2 )
456 cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
461 cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
465 // TODO: the 4 functions below need to be implemented more efficiently
466 void write( FileStorage& fs, const String& name, const SparseMat& value )
468 Ptr<CvSparseMat> mat(cvCreateSparseMat(value));
469 cvWrite( *fs, name.size() ? name.c_str() : 0, mat );
473 internal::WriteStructContext::WriteStructContext(FileStorage& _fs,
474 const String& name, int flags, const String& typeName) : fs(&_fs)
476 cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags,
477 !typeName.empty() ? typeName.c_str() : 0);
478 fs->elname = String();
479 if ((flags & FileNode::TYPE_MASK) == FileNode::SEQ)
481 fs->state = FileStorage::VALUE_EXPECTED;
482 fs->structs.push_back('[');
486 fs->state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
487 fs->structs.push_back('{');
491 internal::WriteStructContext::~WriteStructContext()
493 cvEndWriteStruct(**fs);
494 fs->structs.pop_back();
495 fs->state = fs->structs.empty() || fs->structs.back() == '{' ?
496 FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP :
497 FileStorage::VALUE_EXPECTED;
498 fs->elname = String();
502 void read( const FileNode& node, Mat& mat, const Mat& default_mat )
506 default_mat.copyTo(mat);
509 void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node);
510 if(CV_IS_MAT_HDR_Z(obj))
512 cvarrToMat(obj).copyTo(mat);
513 cvReleaseMat((CvMat**)&obj);
515 else if(CV_IS_MATND_HDR(obj))
517 cvarrToMat(obj).copyTo(mat);
518 cvReleaseMatND((CvMatND**)&obj);
523 CV_Error(CV_StsBadArg, "Unknown array type");
527 void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat )
531 default_mat.copyTo(mat);
534 Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node));
535 CV_Assert(CV_IS_SPARSE_MAT(m));
536 m->copyToSparseMat(mat);
539 CV_EXPORTS void read(const FileNode& node, KeyPoint& value, const KeyPoint& default_value)
543 value = default_value;
549 CV_EXPORTS void read(const FileNode& node, DMatch& value, const DMatch& default_value)
553 value = default_value;
559 #ifdef CV__LEGACY_PERSISTENCE
560 void write( FileStorage& fs, const String& name, const std::vector<KeyPoint>& vec)
562 // from template implementation
563 cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
567 void read(const FileNode& node, std::vector<KeyPoint>& keypoints)
569 FileNode first_node = *(node.begin());
570 if (first_node.isSeq())
573 #ifdef OPENCV_TRAITS_ENABLE_DEPRECATED
574 FileNodeIterator it = node.begin();
575 size_t total = (size_t)it.remaining;
576 keypoints.resize(total);
577 for (size_t i = 0; i < total; ++i, ++it)
579 (*it) >> keypoints[i];
582 FileNodeIterator it = node.begin();
588 FileNodeIterator it = node.begin(), it_end = node.end();
589 for( ; it != it_end; )
592 it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
593 keypoints.push_back(kpt);
597 void write( FileStorage& fs, const String& name, const std::vector<DMatch>& vec)
599 // from template implementation
600 cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
604 void read(const FileNode& node, std::vector<DMatch>& matches)
606 FileNode first_node = *(node.begin());
607 if (first_node.isSeq())
610 #ifdef OPENCV_TRAITS_ENABLE_DEPRECATED
611 FileNodeIterator it = node.begin();
612 size_t total = (size_t)it.remaining;
613 matches.resize(total);
614 for (size_t i = 0; i < total; ++i, ++it)
619 FileNodeIterator it = node.begin();
625 FileNodeIterator it = node.begin(), it_end = node.end();
626 for( ; it != it_end; )
629 it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance;
630 matches.push_back(m);
635 int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); }
636 bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; }
638 size_t FileNode::size() const
641 return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count :
642 t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone();
645 void read(const FileNode& node, int& value, int default_value)
647 value = !node.node ? default_value :
648 CV_NODE_IS_INT(node.node->tag) ? node.node->data.i : std::numeric_limits<int>::max();
651 void read(const FileNode& node, float& value, float default_value)
653 value = !node.node ? default_value :
654 CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i :
655 CV_NODE_IS_REAL(node.node->tag) ? saturate_cast<float>(node.node->data.f) : std::numeric_limits<float>::max();
658 void read(const FileNode& node, double& value, double default_value)
660 value = !node.node ? default_value :
661 CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i :
662 CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : std::numeric_limits<double>::max();
665 void read(const FileNode& node, String& value, const String& default_value)
667 value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String();
670 void read(const FileNode& node, std::string& value, const std::string& default_value)
672 value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? std::string(node.node->data.str.ptr) : default_value;