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, const Mat& val )
199 *this << name << val;
202 void FileStorage::write( const String& name, const std::vector<String>& val )
204 *this << name << val;
207 void FileStorage::writeComment( const String& comment, bool append )
209 cvWriteComment(fs, comment.c_str(), append ? 1 : 0);
212 String FileStorage::getDefaultObjectName(const String& _filename)
214 static const char* stubname = "unnamed";
215 const char* filename = _filename.c_str();
216 const char* ptr2 = filename + _filename.size();
217 const char* ptr = ptr2 - 1;
218 cv::AutoBuffer<char> name_buf(_filename.size()+1);
220 while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
222 if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) )
228 CV_Error( CV_StsBadArg, "Invalid filename" );
230 char* name = name_buf.data();
232 // name must start with letter or '_'
233 if( !cv_isalpha(*ptr) && *ptr!= '_' ){
240 if( !cv_isalnum(c) && c != '-' && c != '_' )
245 name = name_buf.data();
246 if( strcmp( name, "_" ) == 0 )
247 strcpy( name, stubname );
251 FileNode FileStorage::operator[](const String& nodename) const
253 return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str()));
256 FileNode FileStorage::operator[](const char* nodename) const
258 return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename));
261 FileNode FileNode::operator[](const String& nodename) const
263 return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str()));
266 FileNode FileNode::operator[](const char* nodename) const
268 return FileNode(fs, cvGetFileNodeByName(fs, node, nodename));
271 FileNode FileNode::operator[](int i) const
273 return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) :
274 i == 0 ? *this : FileNode();
277 String FileNode::name() const
280 return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str);
283 void* FileNode::readObj() const
287 return cvRead( (CvFileStorage*)fs, (CvFileNode*)node );
290 static const FileNodeIterator::SeqReader emptyReader = {0, 0, 0, 0, 0, 0, 0, 0};
292 FileNodeIterator::FileNodeIterator()
296 reader = emptyReader;
300 FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs,
301 const CvFileNode* _node, size_t _ofs)
303 reader = emptyReader;
304 if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE )
306 int node_type = _node->tag & FileNode::TYPE_MASK;
309 if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) )
311 cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader );
312 remaining = FileNode(_fs, _node).size();
316 reader.ptr = (schar*)_node;
320 (*this) += (int)_ofs;
330 FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
333 container = it.container;
335 remaining = it.remaining;
338 FileNodeIterator& FileNodeIterator::operator ++()
344 if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max )
346 cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 );
354 FileNodeIterator FileNodeIterator::operator ++(int)
356 FileNodeIterator it = *this;
361 FileNodeIterator& FileNodeIterator::operator --()
363 if( remaining < FileNode(fs, container).size() )
367 if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min )
369 cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 );
377 FileNodeIterator FileNodeIterator::operator --(int)
379 FileNodeIterator it = *this;
384 FileNodeIterator& FileNodeIterator::operator += (int ofs)
389 ofs = std::min(ofs, (int)remaining);
392 size_t count = FileNode(fs, container).size();
393 ofs = (int)(remaining - std::min(remaining - ofs, count));
397 cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 );
401 FileNodeIterator& FileNodeIterator::operator -= (int ofs)
403 return operator += (-ofs);
407 FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount )
409 if( fs && container && remaining > 0 )
411 size_t elem_size, cn;
412 getElemSize( fmt, elem_size, cn );
413 CV_Assert( elem_size > 0 );
414 size_t count = std::min(remaining, maxCount);
418 cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() );
419 remaining -= count*cn;
423 cvReadRawData( fs, container, vec, fmt.c_str() );
431 void write( FileStorage& fs, const String& name, int value )
432 { cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); }
434 void write( FileStorage& fs, const String& name, float value )
435 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
437 void write( FileStorage& fs, const String& name, double value )
438 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
440 void write( FileStorage& fs, const String& name, const String& value )
441 { cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); }
443 void writeScalar(FileStorage& fs, int value )
444 { cvWriteInt( *fs, 0, value ); }
446 void writeScalar(FileStorage& fs, float value )
447 { cvWriteReal( *fs, 0, value ); }
449 void writeScalar(FileStorage& fs, double value )
450 { cvWriteReal( *fs, 0, value ); }
452 void writeScalar(FileStorage& fs, const String& value )
453 { cvWriteString( *fs, 0, value.c_str() ); }
456 void write( FileStorage& fs, const String& name, const Mat& value )
458 if( value.dims <= 2 )
461 cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
466 cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
470 // TODO: the 4 functions below need to be implemented more efficiently
471 void write( FileStorage& fs, const String& name, const SparseMat& value )
473 Ptr<CvSparseMat> mat(cvCreateSparseMat(value));
474 cvWrite( *fs, name.size() ? name.c_str() : 0, mat );
478 internal::WriteStructContext::WriteStructContext(FileStorage& _fs,
479 const String& name, int flags, const String& typeName) : fs(&_fs)
481 cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags,
482 !typeName.empty() ? typeName.c_str() : 0);
483 fs->elname = String();
484 if ((flags & FileNode::TYPE_MASK) == FileNode::SEQ)
486 fs->state = FileStorage::VALUE_EXPECTED;
487 fs->structs.push_back('[');
491 fs->state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
492 fs->structs.push_back('{');
496 internal::WriteStructContext::~WriteStructContext()
498 cvEndWriteStruct(**fs);
499 fs->structs.pop_back();
500 fs->state = fs->structs.empty() || fs->structs.back() == '{' ?
501 FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP :
502 FileStorage::VALUE_EXPECTED;
503 fs->elname = String();
507 void read( const FileNode& node, Mat& mat, const Mat& default_mat )
511 default_mat.copyTo(mat);
514 void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node);
515 if(CV_IS_MAT_HDR_Z(obj))
517 cvarrToMat(obj).copyTo(mat);
518 cvReleaseMat((CvMat**)&obj);
520 else if(CV_IS_MATND_HDR(obj))
522 cvarrToMat(obj).copyTo(mat);
523 cvReleaseMatND((CvMatND**)&obj);
528 CV_Error(CV_StsBadArg, "Unknown array type");
532 void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat )
536 default_mat.copyTo(mat);
539 Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node));
540 CV_Assert(CV_IS_SPARSE_MAT(m));
541 m->copyToSparseMat(mat);
544 CV_EXPORTS void read(const FileNode& node, KeyPoint& value, const KeyPoint& default_value)
548 value = default_value;
554 CV_EXPORTS void read(const FileNode& node, DMatch& value, const DMatch& default_value)
558 value = default_value;
564 #ifdef CV__LEGACY_PERSISTENCE
565 void write( FileStorage& fs, const String& name, const std::vector<KeyPoint>& vec)
567 // from template implementation
568 cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
572 void read(const FileNode& node, std::vector<KeyPoint>& keypoints)
574 FileNode first_node = *(node.begin());
575 if (first_node.isSeq())
578 #ifdef OPENCV_TRAITS_ENABLE_DEPRECATED
579 FileNodeIterator it = node.begin();
580 size_t total = (size_t)it.remaining;
581 keypoints.resize(total);
582 for (size_t i = 0; i < total; ++i, ++it)
584 (*it) >> keypoints[i];
587 FileNodeIterator it = node.begin();
593 FileNodeIterator it = node.begin(), it_end = node.end();
594 for( ; it != it_end; )
597 it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
598 keypoints.push_back(kpt);
602 void write( FileStorage& fs, const String& name, const std::vector<DMatch>& vec)
604 // from template implementation
605 cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
609 void read(const FileNode& node, std::vector<DMatch>& matches)
611 FileNode first_node = *(node.begin());
612 if (first_node.isSeq())
615 #ifdef OPENCV_TRAITS_ENABLE_DEPRECATED
616 FileNodeIterator it = node.begin();
617 size_t total = (size_t)it.remaining;
618 matches.resize(total);
619 for (size_t i = 0; i < total; ++i, ++it)
624 FileNodeIterator it = node.begin();
630 FileNodeIterator it = node.begin(), it_end = node.end();
631 for( ; it != it_end; )
634 it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance;
635 matches.push_back(m);
640 int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); }
641 bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; }
643 size_t FileNode::size() const
646 return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count :
647 t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone();
650 void read(const FileNode& node, int& value, int default_value)
652 value = !node.node ? default_value :
653 CV_NODE_IS_INT(node.node->tag) ? node.node->data.i : std::numeric_limits<int>::max();
656 void read(const FileNode& node, float& value, float default_value)
658 value = !node.node ? default_value :
659 CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i :
660 CV_NODE_IS_REAL(node.node->tag) ? saturate_cast<float>(node.node->data.f) : std::numeric_limits<float>::max();
663 void read(const FileNode& node, double& value, double default_value)
665 value = !node.node ? default_value :
666 CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i :
667 CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : std::numeric_limits<double>::max();
670 void read(const FileNode& node, String& value, const String& default_value)
672 value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String();
675 void read(const FileNode& node, std::string& value, const std::string& default_value)
677 value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? std::string(node.node->data.str.ptr) : default_value;