From c22a38cfb4f1217a6d544f7b8db918e3b1da2dcc Mon Sep 17 00:00:00 2001 From: clanmills Date: Fri, 23 Nov 2018 07:26:11 +0000 Subject: [PATCH] Fix for https://github.com/Exiv2/exiv2/issues/560 (eraseFamily() crashes in MSVC/Debug). --- include/exiv2/xmp_exiv2.hpp | 4 ++-- src/actions.cpp | 2 +- src/xmp.cpp | 22 +++++++++++++++++----- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/exiv2/xmp_exiv2.hpp b/include/exiv2/xmp_exiv2.hpp index 4e4ae302..029e46ae 100644 --- a/include/exiv2/xmp_exiv2.hpp +++ b/include/exiv2/xmp_exiv2.hpp @@ -219,10 +219,10 @@ namespace Exiv2 { iterator erase(XmpData::iterator pos); /*! @brief Delete the Xmpdatum at iterator position pos and update pos - eraseFamily erases data from the same family + erases all following keys from the same family See: https://github.com/Exiv2/exiv2/issues/521 */ - void eraseFamily(iterator &pos); + void eraseFamily(XmpData::iterator& pos); //! Delete all Xmpdatum instances resulting in an empty container. void clear(); //! Sort metadata by key diff --git a/src/actions.cpp b/src/actions.cpp index 827d2270..34a7a80d 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -1615,7 +1615,7 @@ namespace Action { if (modifyCmd.metadataId_ == xmp) { Exiv2::XmpData::iterator pos; Exiv2::XmpKey xmpKey = Exiv2::XmpKey(modifyCmd.key_); - while((pos = xmpData.findKey(xmpKey)) != xmpData.end()) { + if((pos = xmpData.findKey(xmpKey)) != xmpData.end()) { xmpData.eraseFamily(pos); } } diff --git a/src/xmp.cpp b/src/xmp.cpp index f2728081..a880da33 100644 --- a/src/xmp.cpp +++ b/src/xmp.cpp @@ -386,18 +386,30 @@ namespace Exiv2 { return xmpMetadata_.erase(pos); } - void XmpData::eraseFamily(XmpData::iterator &pos) + void XmpData::eraseFamily(XmpData::iterator& pos) { // https://github.com/Exiv2/exiv2/issues/521 // delete 'children' of XMP composites (XmpSeq and XmpBag) - std::string key = pos->key(); - while ( pos != end() ) { + + // I build a StringVector of keys to remove + // Then I remove them with erase(....) + // erase() has nasty side effects on its argument + // The side effects are avoided by the two-step approach + // https://github.com/Exiv2/exiv2/issues/560 + std::string key(pos->key()); + Exiv2::StringVector keys; + while ( pos != xmpMetadata_.end() ) { if ( pos->key().find(key)==0 ) { - erase(pos); + keys.push_back(pos->key()); + pos++; } else { - break ; + break; } } + // now erase the family! + for ( Exiv2::StringVector_i it = keys.begin() ; it != keys.end() ; it++ ) { + erase(findKey(Exiv2::XmpKey(*it))); + } }