From 4ea8526e9f4d39d433a1484dcbd9d310ca2acaf3 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 15 Jul 2019 21:30:35 +0000 Subject: [PATCH] core(persistence): fix writeRaw() / readRaw() struct support - writeRaw(): support structs - readRaw(): 'len' is buffer limit in bytes (documentation is fixed) --- .../core/include/opencv2/core/persistence.hpp | 11 ++-- modules/core/src/persistence.cpp | 2 +- modules/core/src/persistence.hpp | 2 +- modules/core/src/persistence_cpp.cpp | 50 +++++++++---------- modules/core/test/test_io.cpp | 12 ++--- 5 files changed, 37 insertions(+), 40 deletions(-) diff --git a/modules/core/include/opencv2/core/persistence.hpp b/modules/core/include/opencv2/core/persistence.hpp index 126393fae1..d5bffb894d 100644 --- a/modules/core/include/opencv2/core/persistence.hpp +++ b/modules/core/include/opencv2/core/persistence.hpp @@ -597,8 +597,8 @@ public: Usually it is more convenient to use operator `>>` instead of this method. @param fmt Specification of each array element. See @ref format_spec "format specification" @param vec Pointer to the destination array. - @param len Number of elements to read. If it is greater than number of remaining elements then all - of them will be read. + @param len Number of bytes to read (buffer size limit). If it is greater than number of + remaining elements then all of them will be read. */ void readRaw( const String& fmt, uchar* vec, size_t len ) const; @@ -668,11 +668,12 @@ public: Usually it is more convenient to use operator `>>` instead of this method. @param fmt Specification of each array element. See @ref format_spec "format specification" @param vec Pointer to the destination array. - @param maxCount Number of elements to read. If it is greater than number of remaining elements then - all of them will be read. + @param len Number of bytes to read (buffer size limit). If it is greater than number of + remaining elements then all of them will be read. + */ FileNodeIterator& readRaw( const String& fmt, uchar* vec, - size_t maxCount=(size_t)INT_MAX ); + size_t len=(size_t)INT_MAX ); struct SeqReader { diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp index 9b67a97e80..4231336a8d 100644 --- a/modules/core/src/persistence.cpp +++ b/modules/core/src/persistence.cpp @@ -145,7 +145,7 @@ CvGenericHash* cvCreateMap( int flags, int header_size, int elem_size, CvMemStor return map; } -void icvParseError( CvFileStorage* fs, const char* func_name, +void icvParseError(const CvFileStorage* fs, const char* func_name, const char* err_msg, const char* source_file, int source_line ) { cv::String msg = cv::format("%s(%d): %s", fs->filename, fs->lineno, err_msg); diff --git a/modules/core/src/persistence.hpp b/modules/core/src/persistence.hpp index a331bb52fe..0cdab6e742 100644 --- a/modules/core/src/persistence.hpp +++ b/modules/core/src/persistence.hpp @@ -262,7 +262,7 @@ void icvFSCreateCollection( CvFileStorage* fs, int tag, CvFileNode* collection ) char* icvFSResizeWriteBuffer( CvFileStorage* fs, char* ptr, int len ); int icvCalcStructSize( const char* dt, int initial_size ); int icvCalcElemSize( const char* dt, int initial_size ); -void CV_NORETURN icvParseError( CvFileStorage* fs, const char* func_name, const char* err_msg, const char* source_file, int source_line ); +void CV_NORETURN icvParseError(const CvFileStorage* fs, const char* func_name, const char* err_msg, const char* source_file, int source_line); char* icvEncodeFormat( int elem_type, char* dt ); int icvDecodeFormat( const char* dt, int* fmt_pairs, int max_len ); int icvDecodeSimpleFormat( const char* dt ); diff --git a/modules/core/src/persistence_cpp.cpp b/modules/core/src/persistence_cpp.cpp index 4b2fbb52d0..12626f2f65 100644 --- a/modules/core/src/persistence_cpp.cpp +++ b/modules/core/src/persistence_cpp.cpp @@ -11,21 +11,6 @@ namespace cv { -static void getElemSize( const String& fmt, size_t& elemSize, size_t& cn ) -{ - const char* dt = fmt.c_str(); - cn = 1; - if( cv_isdigit(dt[0]) ) - { - cn = dt[0] - '0'; - dt++; - } - char c = dt[0]; - elemSize = cn*(c == 'u' || c == 'c' ? sizeof(uchar) : c == 'w' || c == 's' ? sizeof(ushort) : - c == 'i' ? sizeof(int) : c == 'f' ? sizeof(float) : c == 'd' ? sizeof(double) : - c == 'r' ? sizeof(void*) : (size_t)0); -} - FileStorage::FileStorage() { state = UNDEFINED; @@ -164,8 +149,8 @@ void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len ) { if( !isOpened() ) return; - size_t elemSize, cn; - getElemSize( fmt, elemSize, cn ); + CV_Assert(!fmt.empty()); + size_t elemSize = ::icvCalcStructSize(fmt.c_str(), 0); CV_Assert( len % elemSize == 0 ); cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str()); } @@ -412,19 +397,30 @@ FileNodeIterator& FileNodeIterator::operator -= (int ofs) } -FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount ) +FileNodeIterator& FileNodeIterator::readRaw(const String& fmt, uchar* vec, size_t len) { - if( fs && container && remaining > 0 ) + CV_Assert(!fmt.empty()); + if( fs && container && remaining > 0 && len > 0) { - size_t elem_size, cn; - getElemSize( fmt, elem_size, cn ); - CV_Assert( elem_size > 0 ); - size_t count = std::min(remaining, maxCount); - - if( reader.seq ) + if (reader.seq) { - cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() ); - remaining -= count*cn; + size_t step = ::icvCalcStructSize(fmt.c_str(), 0); + if (len % step && len != (size_t)INT_MAX) // TODO remove compatibility hack + { + CV_PARSE_ERROR("readRaw: total byte size not match elememt size"); + } + size_t maxCount = len / step; + int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2] = {}; + int fmt_pair_count = icvDecodeFormat(fmt.c_str(), fmt_pairs, CV_FS_MAX_FMT_PAIRS); + int vecElems = 0; + for (int k = 0; k < fmt_pair_count; k++) + { + vecElems += fmt_pairs[k*2]; + } + CV_Assert(vecElems > 0); + size_t count = std::min((size_t)remaining, (size_t)maxCount * vecElems); + cvReadRawDataSlice(fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str()); + remaining -= count; } else { diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp index 91c269b9d9..a2a601600b 100644 --- a/modules/core/test/test_io.cpp +++ b/modules/core/test/test_io.cpp @@ -724,10 +724,10 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo fs << "empty_2d_mat" << _em_out; fs << "random_mat" << _rd_out; - cvStartWriteStruct( *fs, "rawdata", CV_NODE_SEQ | CV_NODE_FLOW, "binary" ); + fs << "rawdata" << "[:"; for (int i = 0; i < (int)rawdata_N/10; i++) - cvWriteRawData(*fs, rawdata.data() + i * 10, 10, data_t::signature()); - cvEndWriteStruct( *fs ); + fs.writeRaw(data_t::signature(), (const uchar*)&rawdata[i * 10], sizeof(data_t) * 10); + fs << "]"; size_t sz = 0; if (useMemory) @@ -763,7 +763,7 @@ static void test_filestorage_basic(int write_flags, const char* suffix_name, boo /* raw data */ std::vector(rawdata_N).swap(rawdata); - cvReadRawData(*fs, fs["rawdata"].node, rawdata.data(), data_t::signature()); + fs["rawdata"].readRaw(data_t::signature(), (uchar*)&rawdata[0], rawdata.size() * sizeof(data_t)); fs.release(); } @@ -925,7 +925,7 @@ TEST(Core_InputOutput, filestorage_base64_valid_call) { cv::FileStorage fs(file_name, cv::FileStorage::READ); std::vector data_in(rawdata.size()); - fs["manydata"][0].readRaw("i", (uchar *)data_in.data(), data_in.size()); + fs["manydata"][0].readRaw("i", (uchar *)data_in.data(), data_in.size() * sizeof(data_in[0])); EXPECT_TRUE(fs["manydata"][0].isSeq()); EXPECT_TRUE(std::equal(rawdata.begin(), rawdata.end(), data_in.begin())); cv::String str_in; @@ -957,7 +957,7 @@ TEST(Core_InputOutput, filestorage_base64_valid_call) EXPECT_TRUE(fs["manydata"][0].isString()); EXPECT_EQ(str_in, str_out); std::vector data_in(rawdata.size()); - fs["manydata"][1].readRaw("i", (uchar *)data_in.data(), data_in.size()); + fs["manydata"][1].readRaw("i", (uchar *)data_in.data(), data_in.size() * sizeof(data_in[0])); EXPECT_TRUE(fs["manydata"][1].isSeq()); EXPECT_TRUE(std::equal(rawdata.begin(), rawdata.end(), data_in.begin())); fs.release();