diff --git a/include/exiv2/datasets.hpp b/include/exiv2/datasets.hpp index 09c512e0..3fcaedea 100644 --- a/include/exiv2/datasets.hpp +++ b/include/exiv2/datasets.hpp @@ -322,10 +322,6 @@ namespace Exiv2 { //! Internal virtual copy constructor. IptcKey* clone_() const override; - // DATA -#ifndef SWIG - static constexpr auto familyName_ = "Iptc"; -#endif uint16_t tag_; //!< Tag value uint16_t record_; //!< Record value std::string key_; //!< Key diff --git a/src/datasets.cpp b/src/datasets.cpp index 9ab765a4..8654e00e 100644 --- a/src/datasets.cpp +++ b/src/datasets.cpp @@ -34,12 +34,14 @@ #include #include +#include #include // ***************************************************************************** // class member definitions namespace Exiv2 { + constexpr const char *familyName_{"Iptc"}; constexpr RecordInfo recordInfo_[] = { {IptcDataSets::invalidRecord, "(invalid)", N_("(invalid)")}, {IptcDataSets::envelope, "Envelope", N_("IIM envelope record")}, @@ -616,29 +618,24 @@ namespace Exiv2 { void IptcKey::decomposeKey() { - /// \todo Use regex to check the expected format. Then process the 3 expected chunks - // Get the family name, record name and dataSet name parts of the key - std::string::size_type pos1 = key_.find('.'); - if (pos1 == std::string::npos) - throw Error(kerInvalidKey, key_); + // Check that the key has the expected format with RE + static const std::regex re(R"((\w+)(\.\w+){2})"); + std::smatch sm; + if (!std::regex_match(key_, sm, re)) { + throw Error(kerInvalidKey, key_); + } - std::string familyName = key_.substr(0, pos1); + // Get the family name, record name and dataSet name parts of the key + auto posDot1 = key_.find('.'); + auto posDot2 = key_.find('.', posDot1+1); + + const std::string familyName = key_.substr(0, posDot1); if (0 != strcmp(familyName.c_str(), familyName_)) { throw Error(kerInvalidKey, key_); } - std::string::size_type pos0 = pos1 + 1; - pos1 = key_.find('.', pos0); - if (pos1 == std::string::npos) - throw Error(kerInvalidKey, key_); - - std::string recordName = key_.substr(pos0, pos1 - pos0); - if (recordName.empty()) - throw Error(kerInvalidKey, key_); - - std::string dataSetName = key_.substr(pos1 + 1); - if (dataSetName.empty()) - throw Error(kerInvalidKey, key_); + std::string recordName = key_.substr(posDot1+1, posDot2 - posDot1 - 1); + std::string dataSetName = key_.substr(posDot2+1); // Use the parts of the key to find dataSet and recordId uint16_t recId = recordId(recordName); diff --git a/unitTests/test_datasets.cpp b/unitTests/test_datasets.cpp index 6eb9588b..781bdda8 100644 --- a/unitTests/test_datasets.cpp +++ b/unitTests/test_datasets.cpp @@ -165,6 +165,51 @@ TEST(IptcDataSets, dataSet_throwWithNonExistingRecordId) // ---------------------- +TEST(IptcDataSets, dataSetType_returnsExpectedTypeWhenRequestingValidDataset) +{ + ASSERT_EQ(unsignedShort, IptcDataSets::dataSetType(IptcDataSets::ModelVersion, IptcDataSets::envelope)); + ASSERT_EQ(Exiv2::string, IptcDataSets::dataSetType(IptcDataSets::Destination, IptcDataSets::envelope)); + + ASSERT_EQ(unsignedShort, IptcDataSets::dataSetType(IptcDataSets::RecordVersion, IptcDataSets::application2)); + ASSERT_EQ(Exiv2::string, IptcDataSets::dataSetType(IptcDataSets::ObjectType, IptcDataSets::application2)); +} + +/// \todo probably better to throw exception here? +TEST(IptcDataSets, dataSetType_returnsStringTypeWhenRecordIdDoesNotExist) +{ + ASSERT_EQ(Exiv2::string, IptcDataSets::dataSetType(1, 5)); +} + +// ---------------------- + +TEST(IptcDataSets, recordName_returnsExpectedNameWhenRequestingValidRecordId) +{ + ASSERT_EQ("Envelope", IptcDataSets::recordName(IptcDataSets::envelope)); + ASSERT_EQ("Application2", IptcDataSets::recordName(IptcDataSets::application2)); +} + +TEST(IptcDataSets, recordName_returnsHexStringWhenRecordIdDoesNotExist) +{ + ASSERT_EQ("0x0000", IptcDataSets::recordName(0)); + ASSERT_EQ("0x0003", IptcDataSets::recordName(3)); +} + +// ---------------------- + +TEST(IptcDataSets, recordDesc_returnsExpectedDescriptionWhenRequestingValidRecordId) +{ + ASSERT_STREQ("IIM envelope record", IptcDataSets::recordDesc(IptcDataSets::envelope)); + ASSERT_STREQ("IIM application record 2", IptcDataSets::recordDesc(IptcDataSets::application2)); +} + +TEST(IptcDataSets, recordDesc_) +{ + ASSERT_STREQ("Unknown dataset", IptcDataSets::recordDesc(0)); + ASSERT_STREQ("Unknown dataset", IptcDataSets::recordDesc(3)); +} + +// ---------------------- + TEST(IptcDataSets, dataSetLists_printDatasetsIntoOstream) { std::ostringstream stream;