diff --git a/include/exiv2/value.hpp b/include/exiv2/value.hpp index f6b0894b32..cd9c2e0a48 100644 --- a/include/exiv2/value.hpp +++ b/include/exiv2/value.hpp @@ -1628,7 +1628,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 @@ -1636,69 +1636,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<> @@ -1706,7 +1706,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<> @@ -1714,7 +1714,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 7b958c26f1..6e89027556 100644 --- a/src/crwimage_int.cpp +++ b/src/crwimage_int.cpp @@ -929,7 +929,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 50ecfa203f..263ab23dd3 100644 --- a/src/exif.cpp +++ b/src/exif.cpp @@ -230,7 +230,22 @@ namespace Exiv2 { fct=NULL; } } - 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 7588869da2..64e4a9f863 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -251,7 +251,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; @@ -260,7 +260,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(); } @@ -268,19 +268,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 Rational(value_[n], 1); + return Rational(value_.at(n), 1); } StringValueBase::StringValueBase(TypeId typeId) @@ -352,19 +352,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 Rational(value_[n], 1); + return Rational(value_.at(n), 1); } StringValue::StringValue() @@ -404,7 +404,7 @@ namespace Exiv2 { { value_ = buf; // ensure count>0 and nul terminated # https://github.com/Exiv2/exiv2/issues/1484 - if (value_.size() == 0 || value_[value_.size()-1] != '\0') value_ += '\0'; + if (value_.size() == 0 || value_.at(value_.size()-1) != '\0') value_ += '\0'; return 0; } @@ -815,22 +815,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 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")