diff --git a/include/exiv2/value.hpp b/include/exiv2/value.hpp index 9a7d2dba95..a754b75384 100644 --- a/include/exiv2/value.hpp +++ b/include/exiv2/value.hpp @@ -1616,7 +1616,7 @@ namespace Exiv2 { std::string ValueType::toString(long n) const { ok_ = true; - return Exiv2::toString(value_[n]); + return Exiv2::toString(value_.at(n)); } // Default implementation @@ -1624,69 +1624,69 @@ namespace Exiv2 { long ValueType::toLong(long n) const { ok_ = true; - return static_cast(value_[n]); + return static_cast(value_.at(n)); } -// #55 crash when value_[n].first == LONG_MIN +// #55 crash when value_.at(n).first == LONG_MIN #define LARGE_INT 1000000 // Specialization for rational template<> inline long ValueType::toLong(long n) const { - ok_ = (value_[n].second != 0 && INT_MIN < value_[n].first && value_[n].first < INT_MAX ); + ok_ = (value_.at(n).second != 0 && INT_MIN < value_.at(n).first && value_.at(n).first < INT_MAX ); if (!ok_) return 0; - return value_[n].first / value_[n].second; + return value_.at(n).first / value_.at(n).second; } // Specialization for unsigned rational template<> inline long ValueType::toLong(long n) const { - ok_ = (value_[n].second != 0 && value_[n].first < LARGE_INT); + ok_ = (value_.at(n).second != 0 && value_.at(n).first < LARGE_INT); if (!ok_) return 0; - return value_[n].first / value_[n].second; + return value_.at(n).first / value_.at(n).second; } // Default implementation template float ValueType::toFloat(long n) const { ok_ = true; - return static_cast(value_[n]); + return static_cast(value_.at(n)); } // Specialization for rational template<> inline float ValueType::toFloat(long n) const { - ok_ = (value_[n].second != 0); + ok_ = (value_.at(n).second != 0); if (!ok_) return 0.0f; - return static_cast(value_[n].first) / value_[n].second; + return static_cast(value_.at(n).first) / value_.at(n).second; } // Specialization for unsigned rational template<> inline float ValueType::toFloat(long n) const { - ok_ = (value_[n].second != 0); + ok_ = (value_.at(n).second != 0); if (!ok_) return 0.0f; - return static_cast(value_[n].first) / value_[n].second; + return static_cast(value_.at(n).first) / value_.at(n).second; } // Default implementation template Rational ValueType::toRational(long n) const { ok_ = true; - return Rational(value_[n], 1); + return Rational(value_.at(n), 1); } // Specialization for rational template<> inline Rational ValueType::toRational(long n) const { ok_ = true; - return Rational(value_[n].first, value_[n].second); + return Rational(value_.at(n).first, value_.at(n).second); } // Specialization for unsigned rational template<> inline Rational ValueType::toRational(long n) const { ok_ = true; - return Rational(value_[n].first, value_[n].second); + return Rational(value_.at(n).first, value_.at(n).second); } // Specialization for float. template<> @@ -1694,7 +1694,7 @@ namespace Exiv2 { { ok_ = true; // Warning: This is a very simple conversion, see floatToRationalCast() - return floatToRationalCast(value_[n]); + return floatToRationalCast(value_.at(n)); } // Specialization for double. template<> @@ -1702,7 +1702,7 @@ namespace Exiv2 { { ok_ = true; // Warning: This is a very simple conversion, see floatToRationalCast() - return floatToRationalCast(static_cast(value_[n])); + return floatToRationalCast(static_cast(value_.at(n))); } template diff --git a/src/crwimage_int.cpp b/src/crwimage_int.cpp index 7a1003201e..2ce2ff1402 100644 --- a/src/crwimage_int.cpp +++ b/src/crwimage_int.cpp @@ -908,7 +908,7 @@ namespace Exiv2 { assert(pCrwMapping != 0); ULongValue v; v.read(ciffComponent.pData(), 8, byteOrder); - time_t t = v.value_[0]; + time_t t = v.value_.at(0); struct tm* tm = std::localtime(&t); if (tm) { const size_t m = 20; diff --git a/src/exif.cpp b/src/exif.cpp index 2eda4904b8..bb7b69db47 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -229,7 +229,22 @@ namespace Exiv2 { fct = nullptr; } } - if ( fct ) fct(os, value(), pMetadata); + if ( fct ) { + // https://github.com/Exiv2/exiv2/issues/1706 + // Sometimes the type of the value doesn't match what the + // print function expects. (The expected types are stored + // in the TagInfo tables, but they are not enforced when the + // metadata is parsed.) These type mismatches can sometimes + // cause a std::out_of_range exception to be thrown. + try { + fct(os, value(), pMetadata); + } catch (std::out_of_range&) { + os << "Bad value"; +#ifdef EXIV2_DEBUG_MESSAGES + std::cerr << "Caught std::out_of_range exception in Exifdatum::write().\n"; +#endif + } + } return os; } diff --git a/src/value.cpp b/src/value.cpp index eedc20327b..2f21600798 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -203,7 +203,7 @@ namespace Exiv2 { { std::vector::size_type end = value_.size(); for (std::vector::size_type i = 0; i != end; ++i) { - os << static_cast(value_[i]); + os << static_cast(value_.at(i)); if (i < end - 1) os << " "; } return os; @@ -212,7 +212,7 @@ namespace Exiv2 { std::string DataValue::toString(long n) const { std::ostringstream os; - os << static_cast(value_[n]); + os << static_cast(value_.at(n)); ok_ = !os.fail(); return os.str(); } @@ -220,19 +220,19 @@ namespace Exiv2 { long DataValue::toLong(long n) const { ok_ = true; - return value_[n]; + return value_.at(n); } float DataValue::toFloat(long n) const { ok_ = true; - return value_[n]; + return value_.at(n); } Rational DataValue::toRational(long n) const { ok_ = true; - return {value_[n], 1}; + return {value_.at(n), 1}; } StringValueBase::StringValueBase(TypeId typeId) @@ -296,19 +296,19 @@ namespace Exiv2 { long StringValueBase::toLong(long n) const { ok_ = true; - return value_[n]; + return value_.at(n); } float StringValueBase::toFloat(long n) const { ok_ = true; - return value_[n]; + return value_.at(n); } Rational StringValueBase::toRational(long n) const { ok_ = true; - return {value_[n], 1}; + return {value_.at(n), 1}; } StringValue::StringValue() @@ -340,8 +340,9 @@ namespace Exiv2 { { value_ = buf; // ensure count>0 and nul terminated # https://github.com/Exiv2/exiv2/issues/1484 - if (value_.empty() || value_[value_.size() - 1] != '\0') + if (value_.empty() || value_.at(value_.size() - 1) != '\0') { value_ += '\0'; + } return 0; } @@ -740,22 +741,22 @@ namespace Exiv2 { std::string XmpArrayValue::toString(long n) const { ok_ = true; - return value_[n]; + return value_.at(n); } long XmpArrayValue::toLong(long n) const { - return parseLong(value_[n], ok_); + return parseLong(value_.at(n), ok_); } float XmpArrayValue::toFloat(long n) const { - return parseFloat(value_[n], ok_); + return parseFloat(value_.at(n), ok_); } Rational XmpArrayValue::toRational(long n) const { - return parseRational(value_[n], ok_); + return parseRational(value_.at(n), ok_); } XmpArrayValue* XmpArrayValue::clone_() const @@ -1193,4 +1194,4 @@ namespace Exiv2 { return {toLong(n), 1}; } -} // namespace Exiv2 +} // namespace Exiv2 diff --git a/test/data/issue_1706_poc.exv b/test/data/issue_1706_poc.exv new file mode 100644 index 0000000000..375e4fa7cc Binary files /dev/null and b/test/data/issue_1706_poc.exv differ diff --git a/tests/bugfixes/github/test_issue_1706.py b/tests/bugfixes/github/test_issue_1706.py new file mode 100644 index 0000000000..ef31c9bcd8 --- /dev/null +++ b/tests/bugfixes/github/test_issue_1706.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- + +from system_tests import CaseMeta, path + + +class InvalidDateXMP(metaclass=CaseMeta): + """ + Regression test for the bug described in: + https://github.com/Exiv2/exiv2/issues/1706 + """ + url = "https://github.com/Exiv2/exiv2/issues/1706" + + filename = path("$data_path/issue_1706_poc.exv") + commands = ["$exiv2 -PE $filename"] + + stderr = [ +"""Error: Directory Photo with 65280 entries considered invalid; not read. +""" +] + retval = [0] + + def compare_stdout(self, i, command, got_stdout, expected_stdout): + # Check that it printed "Bad value" for the date. + self.assertRegex(got_stdout, "Exif.PentaxDng.Date\\s+Long\\s+1\\s+Bad value")