mirror of
https://github.com/opencv/opencv.git
synced 2026-11-09 18:04:29 -06:00
Merge pull request #30685 from sshivensolanki:core-filestorage-unsigned
core: keep large CV_32U values when reading with FileStorage - #30685 Fixes #30684 ### Problem When a `CV_32U` `Mat` was loaded with `FileStorage`, values above `INT_MAX` came back as `0`, in YAML, XML and JSON, with and without base64. The saved file had the correct values, so only reading was affected. ### Fix - `FileNodeIterator::readRaw` read elements of up to 4 bytes through `(int)node`, so these values turned negative and the `CV_32U` case clamped them to 0. It now always reads the node as `int64_t`. Each case still converts the value to its own type. - The base64 path stored `getInt32()` as signed, so `CV_32U` now uses a new `Base64Decoder::getUInt32()`, like `getUInt8()` and `getUInt16()`. `CV_64U` values above `INT64_MAX` are also lost in the text formats, but that has a different cause, in the parsers' `strtoll`, so it is not part of this PR. ### Tests New `Core_InputOutput.filestorage_32u_large_values` saves values on both sides of `INT_MAX` and loads them back, in YAML, XML and JSON, with and without base64. All 6 combinations fail without the fix, and the test passes with it on Apple M1 Pro. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
@@ -1837,6 +1837,10 @@ ushort FileStorage::Impl::Base64Decoder::getUInt16() {
|
||||
return val;
|
||||
}
|
||||
|
||||
unsigned FileStorage::Impl::Base64Decoder::getUInt32() {
|
||||
return (unsigned)getInt32();
|
||||
}
|
||||
|
||||
int FileStorage::Impl::Base64Decoder::getInt32() {
|
||||
size_t sz = decoded.size();
|
||||
if (ofs + 4 > sz && !readMore(4))
|
||||
@@ -1914,7 +1918,7 @@ char *FileStorage::Impl::parseBase64(char *ptr, int indent, FileNode &collection
|
||||
ival = (short) base64decoder.getUInt16();
|
||||
break;
|
||||
case CV_32U:
|
||||
ival = base64decoder.getInt32();
|
||||
ival = base64decoder.getUInt32();
|
||||
break;
|
||||
case CV_32S:
|
||||
ival = base64decoder.getInt32();
|
||||
@@ -2743,7 +2747,7 @@ FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, void* _data0, si
|
||||
FileNode node = *(*this);
|
||||
if( node.isInt() )
|
||||
{
|
||||
int64_t ival = static_cast<int64_t>(elem_size == 8 ? (int64_t)node : (int)node);
|
||||
int64_t ival = (int64_t)node;
|
||||
switch( elem_type )
|
||||
{
|
||||
case CV_8U:
|
||||
|
||||
@@ -151,6 +151,8 @@ public:
|
||||
|
||||
ushort getUInt16();
|
||||
|
||||
unsigned getUInt32();
|
||||
|
||||
int getInt32();
|
||||
|
||||
int64_t getInt64();
|
||||
|
||||
@@ -2662,4 +2662,28 @@ TEST(Core_InputOutput, filestorage_read_uppercase_exponent)
|
||||
}
|
||||
}
|
||||
|
||||
// CV_32U values above INT_MAX must survive saving and loading, in every format
|
||||
TEST(Core_InputOutput, filestorage_32u_large_values)
|
||||
{
|
||||
const unsigned values[] = { 0u, 1u, 2147483647u, 2147483648u, 4294967295u };
|
||||
const Mat src(1, 5, CV_32U, (void*)values);
|
||||
|
||||
for (const char* ext : { ".yml", ".xml", ".json" })
|
||||
{
|
||||
for (int base64 : { 0, (int)FileStorage::WRITE_BASE64 })
|
||||
{
|
||||
FileStorage writer(ext, FileStorage::WRITE | FileStorage::MEMORY | base64);
|
||||
writer << "m" << src;
|
||||
const std::string text = writer.releaseAndGetString();
|
||||
|
||||
FileStorage reader(text, FileStorage::READ | FileStorage::MEMORY);
|
||||
Mat dst;
|
||||
reader["m"] >> dst;
|
||||
|
||||
EXPECT_EQ(CV_32U, dst.type()) << ext << " base64=" << base64;
|
||||
EXPECT_EQ(0, cv::norm(src, dst, NORM_INF)) << ext << " base64=" << base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
Reference in New Issue
Block a user