ab1b1f09e8609eed65ae42179c8d31146b342ffb
[platform/upstream/opencv.git] / modules / core / src / persistence_cpp.cpp
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
4
5
6 #include "precomp.hpp"
7 #include "persistence.hpp"
8
9 ///////////////////////// new C++ interface for CvFileStorage ///////////////////////////
10
11 namespace cv
12 {
13
14 static void getElemSize( const String& fmt, size_t& elemSize, size_t& cn )
15 {
16     const char* dt = fmt.c_str();
17     cn = 1;
18     if( cv_isdigit(dt[0]) )
19     {
20         cn = dt[0] - '0';
21         dt++;
22     }
23     char c = 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);
27 }
28
29 FileStorage::FileStorage()
30 {
31     state = UNDEFINED;
32 }
33
34 FileStorage::FileStorage(const String& filename, int flags, const String& encoding)
35 {
36     state = UNDEFINED;
37     open( filename, flags, encoding );
38 }
39
40 FileStorage::FileStorage(CvFileStorage* _fs, bool owning)
41 {
42     if (owning) fs.reset(_fs);
43     else fs = Ptr<CvFileStorage>(Ptr<CvFileStorage>(), _fs);
44
45     state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
46 }
47
48 FileStorage::~FileStorage()
49 {
50     while( structs.size() > 0 )
51     {
52         cvEndWriteStruct(fs);
53         structs.pop_back();
54     }
55 }
56
57 bool FileStorage::open(const String& filename, int flags, const String& encoding)
58 {
59     CV_INSTRUMENT_REGION()
60
61     release();
62     fs.reset(cvOpenFileStorage( filename.c_str(), 0, flags,
63                                 !encoding.empty() ? encoding.c_str() : 0));
64     bool ok = isOpened();
65     state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
66     return ok;
67 }
68
69 bool FileStorage::isOpened() const
70 {
71     return fs && fs->is_opened;
72 }
73
74 void FileStorage::release()
75 {
76     fs.release();
77     structs.clear();
78     state = UNDEFINED;
79 }
80
81 String FileStorage::releaseAndGetString()
82 {
83     String buf;
84     if( fs && fs->outbuf )
85         icvClose(fs, &buf);
86
87     release();
88     return buf;
89 }
90
91 FileNode FileStorage::root(int streamidx) const
92 {
93     return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode();
94 }
95
96 int FileStorage::getFormat() const
97 {
98     CV_Assert(!fs.empty());
99     return fs->fmt & FORMAT_MASK;
100 }
101
102 FileStorage& operator << (FileStorage& fs, const String& str)
103 {
104     CV_TRACE_REGION_VERBOSE();
105
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 )
111         return fs;
112     if( *_str == '}' || *_str == ']' )
113     {
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();
124     }
125     else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
126     {
127         if (!cv_isalpha(*_str) && *_str != '_')
128             CV_Error_( CV_StsError, ("Incorrect element name %s", _str) );
129         fs.elname = str;
130         fs.state = VALUE_EXPECTED + INSIDE_MAP;
131     }
132     else if( (fs.state & 3) == VALUE_EXPECTED )
133     {
134         if( *_str == '{' || *_str == '[' )
135         {
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;
140             if( *_str == ':' )
141             {
142                 flags |= CV_NODE_FLOW;
143                 _str++;
144             }
145             cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0,
146                 flags, *_str ? _str : 0 );
147             fs.elname = String();
148         }
149         else
150         {
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;
155         }
156     }
157     else
158         CV_Error( CV_StsError, "Invalid fs.state" );
159     return fs;
160 }
161
162
163 void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len )
164 {
165     if( !isOpened() )
166         return;
167     size_t elemSize, cn;
168     getElemSize( fmt, elemSize, cn );
169     CV_Assert( len % elemSize == 0 );
170     cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str());
171 }
172
173
174 void FileStorage::writeObj( const String& name, const void* obj )
175 {
176     if( !isOpened() )
177         return;
178     cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj );
179 }
180
181
182 void FileStorage::write( const String& name, int val )
183 {
184     *this << name << val;
185 }
186
187 void FileStorage::write( const String& name, double val )
188 {
189     *this << name << val;
190 }
191
192 void FileStorage::write( const String& name, const String& val )
193 {
194     *this << name << val;
195 }
196
197 void FileStorage::write( const String& name, InputArray val )
198 {
199     *this << name << val.getMat();
200 }
201
202 void FileStorage::writeComment( const String& comment, bool append )
203 {
204     cvWriteComment(fs, comment.c_str(), append ? 1 : 0);
205 }
206
207 String FileStorage::getDefaultObjectName(const String& _filename)
208 {
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);
214
215     while( ptr >= filename && *ptr != '\\' && *ptr != '/' && *ptr != ':' )
216     {
217         if( *ptr == '.' && (!*ptr2 || strncmp(ptr2, ".gz", 3) == 0) )
218             ptr2 = ptr;
219         ptr--;
220     }
221     ptr++;
222     if( ptr == ptr2 )
223         CV_Error( CV_StsBadArg, "Invalid filename" );
224
225     char* name = name_buf.data();
226
227     // name must start with letter or '_'
228     if( !cv_isalpha(*ptr) && *ptr!= '_' ){
229         *name++ = '_';
230     }
231
232     while( ptr < ptr2 )
233     {
234         char c = *ptr++;
235         if( !cv_isalnum(c) && c != '-' && c != '_' )
236             c = '_';
237         *name++ = c;
238     }
239     *name = '\0';
240     name = name_buf.data();
241     if( strcmp( name, "_" ) == 0 )
242         strcpy( name, stubname );
243     return String(name);
244 }
245
246 FileNode FileStorage::operator[](const String& nodename) const
247 {
248     return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str()));
249 }
250
251 FileNode FileStorage::operator[](const char* nodename) const
252 {
253     return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename));
254 }
255
256 FileNode FileNode::operator[](const String& nodename) const
257 {
258     return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str()));
259 }
260
261 FileNode FileNode::operator[](const char* nodename) const
262 {
263     return FileNode(fs, cvGetFileNodeByName(fs, node, nodename));
264 }
265
266 FileNode FileNode::operator[](int i) const
267 {
268     return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) :
269         i == 0 ? *this : FileNode();
270 }
271
272 String FileNode::name() const
273 {
274     const char* str;
275     return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str);
276 }
277
278 void* FileNode::readObj() const
279 {
280     if( !fs || !node )
281         return 0;
282     return cvRead( (CvFileStorage*)fs, (CvFileNode*)node );
283 }
284
285 static const FileNodeIterator::SeqReader emptyReader = {0, 0, 0, 0, 0, 0, 0, 0};
286
287 FileNodeIterator::FileNodeIterator()
288 {
289     fs = 0;
290     container = 0;
291     reader = emptyReader;
292     remaining = 0;
293 }
294
295 FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs,
296                                    const CvFileNode* _node, size_t _ofs)
297 {
298     reader = emptyReader;
299     if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE )
300     {
301         int node_type = _node->tag & FileNode::TYPE_MASK;
302         fs = _fs;
303         container = _node;
304         if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) )
305         {
306             cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader );
307             remaining = FileNode(_fs, _node).size();
308         }
309         else
310         {
311             reader.ptr = (schar*)_node;
312             reader.seq = 0;
313             remaining = 1;
314         }
315         (*this) += (int)_ofs;
316     }
317     else
318     {
319         fs = 0;
320         container = 0;
321         remaining = 0;
322     }
323 }
324
325 FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
326 {
327     fs = it.fs;
328     container = it.container;
329     reader = it.reader;
330     remaining = it.remaining;
331 }
332
333 FileNodeIterator& FileNodeIterator::operator ++()
334 {
335     if( remaining > 0 )
336     {
337         if( reader.seq )
338         {
339             if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max )
340             {
341                 cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 );
342             }
343         }
344         remaining--;
345     }
346     return *this;
347 }
348
349 FileNodeIterator FileNodeIterator::operator ++(int)
350 {
351     FileNodeIterator it = *this;
352     ++(*this);
353     return it;
354 }
355
356 FileNodeIterator& FileNodeIterator::operator --()
357 {
358     if( remaining < FileNode(fs, container).size() )
359     {
360         if( reader.seq )
361         {
362             if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min )
363             {
364                 cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 );
365             }
366         }
367         remaining++;
368     }
369     return *this;
370 }
371
372 FileNodeIterator FileNodeIterator::operator --(int)
373 {
374     FileNodeIterator it = *this;
375     --(*this);
376     return it;
377 }
378
379 FileNodeIterator& FileNodeIterator::operator += (int ofs)
380 {
381     if( ofs == 0 )
382         return *this;
383     if( ofs > 0 )
384         ofs = std::min(ofs, (int)remaining);
385     else
386     {
387         size_t count = FileNode(fs, container).size();
388         ofs = (int)(remaining - std::min(remaining - ofs, count));
389     }
390     remaining -= ofs;
391     if( reader.seq )
392         cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 );
393     return *this;
394 }
395
396 FileNodeIterator& FileNodeIterator::operator -= (int ofs)
397 {
398     return operator += (-ofs);
399 }
400
401
402 FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount )
403 {
404     if( fs && container && remaining > 0 )
405     {
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);
410
411         if( reader.seq )
412         {
413             cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() );
414             remaining -= count*cn;
415         }
416         else
417         {
418             cvReadRawData( fs, container, vec, fmt.c_str() );
419             remaining = 0;
420         }
421     }
422     return *this;
423 }
424
425
426 void write( FileStorage& fs, const String& name, int value )
427 { cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); }
428
429 void write( FileStorage& fs, const String& name, float value )
430 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
431
432 void write( FileStorage& fs, const String& name, double value )
433 { cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
434
435 void write( FileStorage& fs, const String& name, const String& value )
436 { cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); }
437
438 void writeScalar(FileStorage& fs, int value )
439 { cvWriteInt( *fs, 0, value ); }
440
441 void writeScalar(FileStorage& fs, float value )
442 { cvWriteReal( *fs, 0, value ); }
443
444 void writeScalar(FileStorage& fs, double value )
445 { cvWriteReal( *fs, 0, value ); }
446
447 void writeScalar(FileStorage& fs, const String& value )
448 { cvWriteString( *fs, 0, value.c_str() ); }
449
450
451 void write( FileStorage& fs, const String& name, const Mat& value )
452 {
453     if( value.dims <= 2 )
454     {
455         CvMat mat = value;
456         cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
457     }
458     else
459     {
460         CvMatND mat = value;
461         cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
462     }
463 }
464
465 // TODO: the 4 functions below need to be implemented more efficiently
466 void write( FileStorage& fs, const String& name, const SparseMat& value )
467 {
468     Ptr<CvSparseMat> mat(cvCreateSparseMat(value));
469     cvWrite( *fs, name.size() ? name.c_str() : 0, mat );
470 }
471
472
473 internal::WriteStructContext::WriteStructContext(FileStorage& _fs,
474     const String& name, int flags, const String& typeName) : fs(&_fs)
475 {
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)
480     {
481         fs->state = FileStorage::VALUE_EXPECTED;
482         fs->structs.push_back('[');
483     }
484     else
485     {
486         fs->state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
487         fs->structs.push_back('{');
488     }
489 }
490
491 internal::WriteStructContext::~WriteStructContext()
492 {
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();
499 }
500
501
502 void read( const FileNode& node, Mat& mat, const Mat& default_mat )
503 {
504     if( node.empty() )
505     {
506         default_mat.copyTo(mat);
507         return;
508     }
509     void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node);
510     if(CV_IS_MAT_HDR_Z(obj))
511     {
512         cvarrToMat(obj).copyTo(mat);
513         cvReleaseMat((CvMat**)&obj);
514     }
515     else if(CV_IS_MATND_HDR(obj))
516     {
517         cvarrToMat(obj).copyTo(mat);
518         cvReleaseMatND((CvMatND**)&obj);
519     }
520     else
521     {
522         cvRelease(&obj);
523         CV_Error(CV_StsBadArg, "Unknown array type");
524     }
525 }
526
527 void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat )
528 {
529     if( node.empty() )
530     {
531         default_mat.copyTo(mat);
532         return;
533     }
534     Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node));
535     CV_Assert(CV_IS_SPARSE_MAT(m));
536     m->copyToSparseMat(mat);
537 }
538
539 CV_EXPORTS void read(const FileNode& node, KeyPoint& value, const KeyPoint& default_value)
540 {
541     if( node.empty() )
542     {
543         value = default_value;
544         return;
545     }
546     node >> value;
547 }
548
549 CV_EXPORTS void read(const FileNode& node, DMatch& value, const DMatch& default_value)
550 {
551     if( node.empty() )
552     {
553         value = default_value;
554         return;
555     }
556     node >> value;
557 }
558
559 #ifdef CV__LEGACY_PERSISTENCE
560 void write( FileStorage& fs, const String& name, const std::vector<KeyPoint>& vec)
561 {
562     // from template implementation
563     cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
564     write(fs, vec);
565 }
566
567 void read(const FileNode& node, std::vector<KeyPoint>& keypoints)
568 {
569     FileNode first_node = *(node.begin());
570     if (first_node.isSeq())
571     {
572         // modern scheme
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)
578         {
579             (*it) >> keypoints[i];
580         }
581 #else
582         FileNodeIterator it = node.begin();
583         it >> keypoints;
584 #endif
585         return;
586     }
587     keypoints.clear();
588     FileNodeIterator it = node.begin(), it_end = node.end();
589     for( ; it != it_end; )
590     {
591         KeyPoint kpt;
592         it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
593         keypoints.push_back(kpt);
594     }
595 }
596
597 void write( FileStorage& fs, const String& name, const std::vector<DMatch>& vec)
598 {
599     // from template implementation
600     cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
601     write(fs, vec);
602 }
603
604 void read(const FileNode& node, std::vector<DMatch>& matches)
605 {
606     FileNode first_node = *(node.begin());
607     if (first_node.isSeq())
608     {
609         // modern scheme
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)
615         {
616             (*it) >> matches[i];
617         }
618 #else
619         FileNodeIterator it = node.begin();
620         it >> matches;
621 #endif
622         return;
623     }
624     matches.clear();
625     FileNodeIterator it = node.begin(), it_end = node.end();
626     for( ; it != it_end; )
627     {
628         DMatch m;
629         it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance;
630         matches.push_back(m);
631     }
632 }
633 #endif
634
635 int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); }
636 bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; }
637
638 size_t FileNode::size() const
639 {
640     int t = type();
641     return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count :
642         t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone();
643 }
644
645 void read(const FileNode& node, int& value, int default_value)
646 {
647     value = !node.node ? default_value :
648     CV_NODE_IS_INT(node.node->tag) ? node.node->data.i : std::numeric_limits<int>::max();
649 }
650
651 void read(const FileNode& node, float& value, float default_value)
652 {
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();
656 }
657
658 void read(const FileNode& node, double& value, double default_value)
659 {
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();
663 }
664
665 void read(const FileNode& node, String& value, const String& default_value)
666 {
667     value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String();
668 }
669
670 void read(const FileNode& node, std::string& value, const std::string& default_value)
671 {
672     value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? std::string(node.node->data.str.ptr) : default_value;
673 }
674
675 } // cv::