# HG changeset patch # User Sebastien Jodogne # Date 1630311876 -7200 # Node ID add0337b928a46a64945a130a00cc10c7054f8f1 # Parent 9f207131c7f46a9dd0c8a745006bf518a061fe74 refactoring parsing of numbers diff -r 9f207131c7f4 -r add0337b928a OrthancFramework/Sources/DicomFormat/DicomValue.cpp --- a/OrthancFramework/Sources/DicomFormat/DicomValue.cpp Wed Aug 25 17:20:21 2021 +0200 +++ b/OrthancFramework/Sources/DicomFormat/DicomValue.cpp Mon Aug 30 10:24:36 2021 +0200 @@ -104,102 +104,110 @@ } #endif - // same as ParseValue but in case the value actually contains a sequence, - // it will return the first value - // this has been introduced to support invalid "width/height" DICOM tags in some US - // images where the width is stored as "800\0" ! - template - static bool ParseFirstValue(T& result, - const DicomValue& source) + bool DicomValue::ParseInteger32(int32_t& result) const + { + if (IsBinary() || + IsNull()) + { + return false; + } + else + { + return SerializationToolbox::ParseInteger32(result, GetContent()); + } + } + + bool DicomValue::ParseInteger64(int64_t& result) const { - if (source.IsBinary() || - source.IsNull()) + if (IsBinary() || + IsNull()) + { + return false; + } + else + { + return SerializationToolbox::ParseInteger64(result, GetContent()); + } + } + + bool DicomValue::ParseUnsignedInteger32(uint32_t& result) const + { + if (IsBinary() || + IsNull()) + { + return false; + } + else + { + return SerializationToolbox::ParseUnsignedInteger32(result, GetContent()); + } + } + + bool DicomValue::ParseUnsignedInteger64(uint64_t& result) const + { + if (IsBinary() || + IsNull()) { return false; } - - try + else { - std::string value = Toolbox::StripSpaces(source.GetContent()); - if (value.empty()) - { - return false; - } - - if (!allowSigned && - value[0] == '-') - { - return false; - } + return SerializationToolbox::ParseUnsignedInteger64(result, GetContent()); + } + } - if (value.find("\\") == std::string::npos) - { - result = boost::lexical_cast(value); - return true; - } - else - { - std::vector tokens; - Toolbox::TokenizeString(tokens, value, '\\'); - - if (tokens.size() >= 1) - { - result = boost::lexical_cast(tokens[0]); - return true; - } - - return false; - } - } - catch (boost::bad_lexical_cast&) + bool DicomValue::ParseFloat(float& result) const + { + if (IsBinary() || + IsNull()) { return false; } + else + { + return SerializationToolbox::ParseFloat(result, GetContent()); + } } + bool DicomValue::ParseDouble(double& result) const + { + if (IsBinary() || + IsNull()) + { + return false; + } + else + { + return SerializationToolbox::ParseDouble(result, GetContent()); + } + } - template - static bool ParseValue(T& result, - const DicomValue& source) + bool DicomValue::ParseFirstFloat(float& result) const { - if (source.IsBinary() || - source.IsNull()) + if (IsBinary() || + IsNull()) { return false; } - - try + else { - std::string value = Toolbox::StripSpaces(source.GetContent()); - if (value.empty()) - { - return false; - } + return SerializationToolbox::ParseFirstFloat(result, GetContent()); + } + } - if (!allowSigned && - value[0] == '-') - { - return false; - } - - result = boost::lexical_cast(value); - return true; - } - catch (boost::bad_lexical_cast&) + bool DicomValue::ParseFirstUnsignedInteger(unsigned int& result) const + { + uint64_t value; + + if (IsBinary() || + IsNull()) { return false; } - } - - bool DicomValue::ParseInteger32(int32_t& result) const - { - int64_t tmp; - if (ParseValue(tmp, *this)) + else if (SerializationToolbox::ParseFirstUnsignedInteger64(value, GetContent())) { - result = static_cast(tmp); - return (tmp == static_cast(result)); // Check no overflow occurs + result = static_cast(value); + return (static_cast(result) == value); // Check no overflow } else { @@ -207,50 +215,6 @@ } } - bool DicomValue::ParseInteger64(int64_t& result) const - { - return ParseValue(result, *this); - } - - bool DicomValue::ParseUnsignedInteger32(uint32_t& result) const - { - uint64_t tmp; - if (ParseValue(tmp, *this)) - { - result = static_cast(tmp); - return (tmp == static_cast(result)); // Check no overflow occurs - } - else - { - return false; - } - } - - bool DicomValue::ParseUnsignedInteger64(uint64_t& result) const - { - return ParseValue(result, *this); - } - - bool DicomValue::ParseFloat(float& result) const - { - return ParseValue(result, *this); - } - - bool DicomValue::ParseDouble(double& result) const - { - return ParseValue(result, *this); - } - - bool DicomValue::ParseFirstFloat(float& result) const - { - return ParseFirstValue(result, *this); - } - - bool DicomValue::ParseFirstUnsignedInteger(unsigned int& result) const - { - return ParseFirstValue(result, *this); - } - bool DicomValue::CopyToString(std::string& result, bool allowBinary) const { diff -r 9f207131c7f4 -r add0337b928a OrthancFramework/Sources/SerializationToolbox.cpp --- a/OrthancFramework/Sources/SerializationToolbox.cpp Wed Aug 25 17:20:21 2021 +0200 +++ b/OrthancFramework/Sources/SerializationToolbox.cpp Mon Aug 30 10:24:36 2021 +0200 @@ -24,11 +24,15 @@ #include "SerializationToolbox.h" #include "OrthancException.h" +#include "Toolbox.h" #if ORTHANC_ENABLE_DCMTK == 1 # include "DicomParsing/FromDcmtkBridge.h" #endif +#include + + namespace Orthanc { static bool ParseTagInternal(DicomTag& tag, @@ -445,4 +449,202 @@ value[it->first.Format()] = it->second; } } + + + template + static bool ParseValue(T& target, + const std::string& source) + { + try + { + std::string value = Toolbox::StripSpaces(source); + if (value.empty()) + { + return false; + } + else if (!allowSigned && + value[0] == '-') + { + return false; + } + else + { + target = boost::lexical_cast(value); + return true; + } + } + catch (boost::bad_lexical_cast&) + { + return false; + } + } + + + bool SerializationToolbox::ParseInteger32(int32_t& target, + const std::string& source) + { + int64_t tmp; + if (ParseValue(tmp, source)) + { + target = static_cast(tmp); + return (tmp == static_cast(target)); // Check no overflow occurs + } + else + { + return false; + } + } + + + bool SerializationToolbox::ParseInteger64(int64_t& target, + const std::string& source) + { + return ParseValue(target, source); + } + + + bool SerializationToolbox::ParseUnsignedInteger32(uint32_t& target, + const std::string& source) + { + uint64_t tmp; + if (ParseValue(tmp, source)) + { + target = static_cast(tmp); + return (tmp == static_cast(target)); // Check no overflow occurs + } + else + { + return false; + } + } + + + bool SerializationToolbox::ParseUnsignedInteger64(uint64_t& target, + const std::string& source) + { + return ParseValue(target, source); + } + + + bool SerializationToolbox::ParseFloat(float& target, + const std::string& source) + { + return ParseValue(target, source); + } + + + bool SerializationToolbox::ParseDouble(double& target, + const std::string& source) + { + return ParseValue(target, source); + } + + + static bool GetFirstItem(std::string& target, + const std::string& source) + { + std::vector tokens; + Toolbox::TokenizeString(tokens, source, '\\'); + + if (tokens.empty()) + { + return false; + } + else + { + target = tokens[0]; + return true; + } + } + + + bool SerializationToolbox::ParseFirstInteger32(int32_t& target, + const std::string& source) + { + std::string first; + if (GetFirstItem(first, source)) + { + return ParseInteger32(target, first); + } + else + { + return false; + } + } + + + bool SerializationToolbox::ParseFirstInteger64(int64_t& target, + const std::string& source) + { + std::string first; + if (GetFirstItem(first, source)) + { + return ParseInteger64(target, first); + } + else + { + return false; + } + } + + + bool SerializationToolbox::ParseFirstUnsignedInteger32(uint32_t& target, + const std::string& source) + { + std::string first; + if (GetFirstItem(first, source)) + { + return ParseUnsignedInteger32(target, first); + } + else + { + return false; + } + } + + + bool SerializationToolbox::ParseFirstUnsignedInteger64(uint64_t& target, + const std::string& source) + { + std::string first; + if (GetFirstItem(first, source)) + { + return ParseUnsignedInteger64(target, first); + } + else + { + return false; + } + } + + + bool SerializationToolbox::ParseFirstFloat(float& target, + const std::string& source) + { + std::string first; + if (GetFirstItem(first, source)) + { + return ParseFloat(target, first); + } + else + { + return false; + } + } + + + bool SerializationToolbox::ParseFirstDouble(double& target, + const std::string& source) + { + std::string first; + if (GetFirstItem(first, source)) + { + return ParseDouble(target, first); + } + else + { + return false; + } + } } diff -r 9f207131c7f4 -r add0337b928a OrthancFramework/Sources/SerializationToolbox.h --- a/OrthancFramework/Sources/SerializationToolbox.h Wed Aug 25 17:20:21 2021 +0200 +++ b/OrthancFramework/Sources/SerializationToolbox.h Mon Aug 30 10:24:36 2021 +0200 @@ -101,5 +101,41 @@ static void WriteMapOfTags(Json::Value& target, const std::map& values, const std::string& field); + + static bool ParseInteger32(int32_t& result, + const std::string& value); + + static bool ParseInteger64(int64_t& result, + const std::string& value); + + static bool ParseUnsignedInteger32(uint32_t& result, + const std::string& value); + + static bool ParseUnsignedInteger64(uint64_t& result, + const std::string& value); + + static bool ParseFloat(float& result, + const std::string& value); + + static bool ParseDouble(double& result, + const std::string& value); + + static bool ParseFirstInteger32(int32_t& result, + const std::string& value); + + static bool ParseFirstInteger64(int64_t& result, + const std::string& value); + + static bool ParseFirstUnsignedInteger32(uint32_t& result, + const std::string& value); + + static bool ParseFirstUnsignedInteger64(uint64_t& result, + const std::string& value); + + static bool ParseFirstFloat(float& result, + const std::string& value); + + static bool ParseFirstDouble(double& result, + const std::string& value); }; } diff -r 9f207131c7f4 -r add0337b928a OrthancFramework/UnitTestsSources/JobsTests.cpp --- a/OrthancFramework/UnitTestsSources/JobsTests.cpp Wed Aug 25 17:20:21 2021 +0200 +++ b/OrthancFramework/UnitTestsSources/JobsTests.cpp Mon Aug 30 10:24:36 2021 +0200 @@ -1575,3 +1575,86 @@ ASSERT_FALSE(b.IsRemoteCertificateRequired()); } } + + +TEST(SerializationToolbox, Numbers) +{ + { + int32_t i; + ASSERT_FALSE(SerializationToolbox::ParseInteger32(i, "")); + ASSERT_FALSE(SerializationToolbox::ParseInteger32(i, "ee")); + ASSERT_TRUE(SerializationToolbox::ParseInteger32(i, "42")); ASSERT_EQ(42, i); + ASSERT_TRUE(SerializationToolbox::ParseInteger32(i, "-42")); ASSERT_EQ(-42, i); + ASSERT_TRUE(SerializationToolbox::ParseInteger32(i, "-2147483648")); ASSERT_EQ(-2147483648, i); + ASSERT_TRUE(SerializationToolbox::ParseInteger32(i, "2147483647")); ASSERT_EQ(2147483647, i); + ASSERT_FALSE(SerializationToolbox::ParseInteger32(i, "-2147483649")); + ASSERT_FALSE(SerializationToolbox::ParseInteger32(i, "2147483648")); + ASSERT_FALSE(SerializationToolbox::ParseInteger32(i, "-2\\-3\\-4")); + ASSERT_TRUE(SerializationToolbox::ParseFirstInteger32(i, "-2\\-3\\-4")); ASSERT_EQ(-2, i); + } + + { + uint32_t i; + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger32(i, "")); + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger32(i, "ee")); + ASSERT_TRUE(SerializationToolbox::ParseUnsignedInteger32(i, "42")); ASSERT_EQ(42u, i); + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger32(i, "-42")); + ASSERT_TRUE(SerializationToolbox::ParseUnsignedInteger32(i, "4294967295")); ASSERT_EQ(4294967295u, i); + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger32(i, "4294967296")); + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger32(i, "2\\3\\4")); + ASSERT_TRUE(SerializationToolbox::ParseFirstUnsignedInteger32(i, "2\\3\\4")); ASSERT_EQ(2u, i); + } + + { + int64_t i; + ASSERT_FALSE(SerializationToolbox::ParseInteger64(i, "")); + ASSERT_FALSE(SerializationToolbox::ParseInteger64(i, "ee")); + ASSERT_TRUE(SerializationToolbox::ParseInteger64(i, "42")); ASSERT_EQ(42, i); + ASSERT_TRUE(SerializationToolbox::ParseInteger64(i, "-42")); ASSERT_EQ(-42, i); + ASSERT_TRUE(SerializationToolbox::ParseInteger64(i, "-2147483649")); ASSERT_EQ(-2147483649ll, i); + ASSERT_TRUE(SerializationToolbox::ParseInteger64(i, "2147483648")); ASSERT_EQ(2147483648ll, i); + ASSERT_FALSE(SerializationToolbox::ParseInteger64(i, "-2\\-3\\-4")); + ASSERT_TRUE(SerializationToolbox::ParseFirstInteger64(i, "-2\\-3\\-4")); ASSERT_EQ(-2, i); + } + + { + uint64_t i; + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger64(i, "")); + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger64(i, "ee")); + ASSERT_TRUE(SerializationToolbox::ParseUnsignedInteger64(i, "42")); ASSERT_EQ(42u, i); + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger64(i, "-42")); + ASSERT_TRUE(SerializationToolbox::ParseUnsignedInteger64(i, "4294967296")); ASSERT_EQ(4294967296llu, i); + ASSERT_FALSE(SerializationToolbox::ParseUnsignedInteger64(i, "2\\3\\4")); + ASSERT_TRUE(SerializationToolbox::ParseFirstUnsignedInteger64(i, "2\\3\\4")); ASSERT_EQ(2u, i); + } + + { + float i; + ASSERT_FALSE(SerializationToolbox::ParseFloat(i, "")); + ASSERT_FALSE(SerializationToolbox::ParseFloat(i, "ee")); + ASSERT_TRUE(SerializationToolbox::ParseFloat(i, "42")); ASSERT_FLOAT_EQ(42.0f, i); + ASSERT_TRUE(SerializationToolbox::ParseFloat(i, "-42")); ASSERT_FLOAT_EQ(-42.0f, i); + ASSERT_FALSE(SerializationToolbox::ParseFloat(i, "2\\3\\4")); + ASSERT_TRUE(SerializationToolbox::ParseFirstFloat(i, "1.367\\2.367\\3.367")); ASSERT_FLOAT_EQ(1.367f, i); + + ASSERT_TRUE(SerializationToolbox::ParseFloat(i, "1.2")); ASSERT_FLOAT_EQ(1.2f, i); + ASSERT_TRUE(SerializationToolbox::ParseFloat(i, "-1.2e+2")); ASSERT_FLOAT_EQ(-120.0f, i); + ASSERT_TRUE(SerializationToolbox::ParseFloat(i, "-1e-2")); ASSERT_FLOAT_EQ(-0.01f, i); + ASSERT_TRUE(SerializationToolbox::ParseFloat(i, "1.3671875")); ASSERT_FLOAT_EQ(1.3671875f, i); + } + + { + double i; + ASSERT_FALSE(SerializationToolbox::ParseDouble(i, "")); + ASSERT_FALSE(SerializationToolbox::ParseDouble(i, "ee")); + ASSERT_TRUE(SerializationToolbox::ParseDouble(i, "42")); ASSERT_DOUBLE_EQ(42.0, i); + ASSERT_TRUE(SerializationToolbox::ParseDouble(i, "-42")); ASSERT_DOUBLE_EQ(-42.0, i); + ASSERT_FALSE(SerializationToolbox::ParseDouble(i, "2\\3\\4")); + ASSERT_TRUE(SerializationToolbox::ParseFirstDouble(i, "1.367\\2.367\\3.367")); ASSERT_DOUBLE_EQ(1.367, i); + + ASSERT_TRUE(SerializationToolbox::ParseDouble(i, "1.2")); ASSERT_DOUBLE_EQ(1.2, i); + ASSERT_TRUE(SerializationToolbox::ParseDouble(i, "-1.2e+2")); ASSERT_DOUBLE_EQ(-120.0, i); + ASSERT_TRUE(SerializationToolbox::ParseDouble(i, "-1e-2")); ASSERT_DOUBLE_EQ(-0.01, i); + ASSERT_TRUE(SerializationToolbox::ParseDouble(i, "1.3671875")); ASSERT_DOUBLE_EQ(1.3671875, i); + } +}