diff --git a/app/exiv2.cpp b/app/exiv2.cpp index 874f11cb..c13d80f1 100644 --- a/app/exiv2.cpp +++ b/app/exiv2.cpp @@ -10,6 +10,7 @@ #include "convert.hpp" #include "getopt.hpp" #include "i18n.h" // NLS support. +#include "utils.hpp" #include "xmp_exiv2.hpp" #include @@ -1119,7 +1120,7 @@ bool parseTime(const std::string& ts, int64_t& time) { hh *= -1; } // check for the -0 special case - if (hh == 0 && hstr.find('-') != std::string::npos) + if (hh == 0 && Exiv2::Internal::contains(hstr, '-')) sign = -1; // MM part, if there is one if (!mstr.empty()) { diff --git a/src/bmffimage.cpp b/src/bmffimage.cpp index b40bde17..b2bbe713 100644 --- a/src/bmffimage.cpp +++ b/src/bmffimage.cpp @@ -14,6 +14,7 @@ #include "tiffimage.hpp" #include "tiffimage_int.hpp" #include "types.hpp" +#include "utils.hpp" #ifdef EXV_HAVE_BROTLI #include // for JXL brob @@ -349,11 +350,10 @@ uint64_t BmffImage::boxHandler(std::ostream& out /* = std::cout*/, Exiv2::PrintS const size_t maxlen = data.size() - skip; Internal::enforce(maxlen > 0 && strnlen(str, maxlen) < maxlen, Exiv2::ErrorCode::kerCorruptedMetadata); std::string name(str); - if (name.find("Exif") != std::string::npos) { // "Exif" or "ExifExif" + if (Internal::contains(name, "Exif")) { // "Exif" or "ExifExif" exifID_ = ID; id = " *** Exif ***"; - } else if (name.find("mime\0xmp") != std::string::npos || - name.find("mime\0application/rdf+xml") != std::string::npos) { + } else if (Internal::contains(name, "mime\0xmp") || Internal::contains(name, "mime\0application/rdf+xml")) { xmpID_ = ID; id = " *** XMP ***"; } diff --git a/src/canonmn_int.cpp b/src/canonmn_int.cpp index 9da55f92..f241209c 100644 --- a/src/canonmn_int.cpp +++ b/src/canonmn_int.cpp @@ -14,6 +14,7 @@ #include "makernote_int.hpp" #include "tags_int.hpp" #include "types.hpp" +#include "utils.hpp" #include "value.hpp" // + standard includes @@ -2531,8 +2532,8 @@ std::ostream& CanonMakerNote::printFiFileNumber(std::ostream& os, const Value& v // Ported from Exiftool std::string model = pos->toString(); - if (model.find("20D") != std::string::npos || model.find("350D") != std::string::npos || - model.substr(model.size() - 8, 8) == "REBEL XT" || model.find("Kiss Digital N") != std::string::npos) { + if (Internal::contains(model, "20D") || Internal::contains(model, "350D") || + model.substr(model.size() - 8, 8) == "REBEL XT" || Internal::contains(model, "Kiss Digital N")) { uint32_t val = value.toUint32(); uint32_t dn = (val & 0xffc0) >> 6; uint32_t fn = ((val >> 16) & 0xff) + ((val & 0x3f) << 8); @@ -2540,9 +2541,8 @@ std::ostream& CanonMakerNote::printFiFileNumber(std::ostream& os, const Value& v os.flags(f); return os; } - if (model.find("30D") != std::string::npos || model.find("400D") != std::string::npos || - model.find("REBEL XTi") != std::string::npos || model.find("Kiss Digital X") != std::string::npos || - model.find("K236") != std::string::npos) { + if (Internal::contains(model, "30D") || Internal::contains(model, "400D") || Internal::contains(model, "REBEL XTi") || + Internal::contains(model, "Kiss Digital X") || Internal::contains(model, "K236")) { uint32_t val = value.toUint32(); uint32_t dn = (val & 0xffc00) >> 10; while (dn < 100) diff --git a/src/easyaccess.cpp b/src/easyaccess.cpp index af950a2e..647758ea 100644 --- a/src/easyaccess.cpp +++ b/src/easyaccess.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // included header files #include "easyaccess.hpp" +#include "utils.hpp" // ***************************************************************************** namespace { @@ -97,7 +98,7 @@ ExifData::const_iterator isoSpeed(const ExifData& ed) { std::ostringstream os; md->write(os, &ed); bool ok = false; - if (os.str().find("inf") != std::string::npos) + if (Internal::contains(os.str(), "inf")) break; iso_val = parseInt64(os.str(), ok); if (ok && iso_val > 0) diff --git a/src/makernote_int.cpp b/src/makernote_int.cpp index 6ffcb42e..525838b4 100644 --- a/src/makernote_int.cpp +++ b/src/makernote_int.cpp @@ -944,7 +944,7 @@ DataBuf nikonCrypt(uint16_t tag, const byte* pData, size_t size, TiffComponent* std::string model = getExifModel(pRoot); if (model.empty()) return buf; - if (model.find("D50") != std::string::npos) { + if (Internal::contains(model, "D50")) { serial = 0x22; } else { serial = 0x60; @@ -961,7 +961,7 @@ int sonyCsSelector(uint16_t /*tag*/, const byte* /*pData*/, size_t /*size*/, Tif if (model.empty()) return -1; int idx = 0; - if (model.find("DSLR-A330") != std::string::npos || model.find("DSLR-A380") != std::string::npos) { + if (Internal::contains(model, "DSLR-A330") || Internal::contains(model, "DSLR-A380")) { idx = 1; } return idx; diff --git a/src/nikonmn_int.cpp b/src/nikonmn_int.cpp index d733883b..621b8c5b 100644 --- a/src/nikonmn_int.cpp +++ b/src/nikonmn_int.cpp @@ -7,6 +7,7 @@ #include "i18n.h" // NLS support. #include "makernote_int.hpp" #include "tags_int.hpp" +#include "utils.hpp" #include "value.hpp" // + standard includes @@ -1834,7 +1835,7 @@ std::ostream& Nikon3MakerNote::printAfPointsInFocus(std::ostream& os, const Valu auto pos = metadata->findKey(ExifKey("Exif.Image.Model")); if (pos != metadata->end() && pos->count() != 0) { std::string model = pos->toString(); - if (model.find("NIKON D") != std::string::npos) { + if (Internal::contains(model, "NIKON D")) { dModel = true; } } @@ -1867,7 +1868,7 @@ std::ostream& Nikon3MakerNote::print0x0089(std::ostream& os, const Value& value, auto pos = metadata->findKey(key); if (pos != metadata->end() && pos->count() != 0) { std::string model = pos->toString(); - if (model.find("D70") != std::string::npos) { + if (Internal::contains(model, "D70")) { d70 = true; } } diff --git a/src/olympusmn_int.cpp b/src/olympusmn_int.cpp index 9937e5aa..daee3ba6 100644 --- a/src/olympusmn_int.cpp +++ b/src/olympusmn_int.cpp @@ -8,6 +8,7 @@ #include "i18n.h" // NLS support. #include "makernote_int.hpp" #include "tags_int.hpp" +#include "utils.hpp" #include "value.hpp" #include @@ -1586,7 +1587,7 @@ std::ostream& OlympusMakerNote::print0x0308(std::ostream& os, const Value& value auto pos = metadata->findKey(ExifKey("Exif.Image.Model")); if (pos != metadata->end() && pos->count() != 0) { std::string model = pos->toString(); - if (model.find("E-3 ") != std::string::npos || model.find("E-30 ") != std::string::npos) { + if (Internal::contains(model, "E-3 ") || Internal::contains(model, "E-30 ")) { E3_E30model = true; } } diff --git a/src/sonymn_int.cpp b/src/sonymn_int.cpp index 4442dcda..e8548c6c 100644 --- a/src/sonymn_int.cpp +++ b/src/sonymn_int.cpp @@ -646,7 +646,7 @@ static auto getModel(const ExifData* metadata, std::string& val) { pos = metadata->findKey(ExifKey("Exif.Sony1.SonyModelID")); if (pos != metadata->end() && pos->size() != 0 && pos->typeId() == unsignedShort) { std::string temp = pos->print(metadata); - if (temp.find(' ') == std::string::npos) { + if (!Internal::contains(temp, ' ')) { val = temp; return true; } @@ -656,7 +656,7 @@ static auto getModel(const ExifData* metadata, std::string& val) { pos = metadata->findKey(ExifKey("Exif.Sony2.SonyModelID")); if (pos != metadata->end() && pos->size() != 0 && pos->typeId() == unsignedShort) { std::string temp = pos->print(metadata); - if (temp.find(' ') == std::string::npos) { + if (!Internal::contains(temp, ' ')) { val = temp; return true; } @@ -1969,7 +1969,7 @@ std::ostream& SonyMakerNote::printSonyMisc2bLensZoomPosition(std::ostream& os, c // Models that do not support this tag for (auto& m : {"SLT-", "HV", "ILCA-"}) { - if (model.find(m) != std::string::npos) + if (Internal::contains(model, m)) return os << N_("n/a"); } @@ -1991,7 +1991,7 @@ std::ostream& SonyMakerNote::printSonyMisc2bFocusPosition2(std::ostream& os, con // Models that do not support this tag for (auto& m : {"SLT-", "HV", "ILCA-"}) { - if (model.find(m) != std::string::npos) + if (Internal::contains(model, m)) return os << N_("n/a"); } diff --git a/src/utils.hpp b/src/utils.hpp index ffb0fffd..8a9de207 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -15,6 +15,15 @@ constexpr bool startsWith(std::string_view s, T start) { #endif } +template +constexpr bool contains(std::string_view s, T c) { +#ifdef __cpp_lib_string_contains + return s.contains(c); +#else + return s.find(c) != std::string_view::npos; +#endif +} + /// @brief Returns the uppercase version of \b str std::string upper(const std::string& str); diff --git a/src/value.cpp b/src/value.cpp index 36b80451..710c6c8c 100644 --- a/src/value.cpp +++ b/src/value.cpp @@ -390,8 +390,10 @@ std::string CommentValue::comment(const char* encoding) const { } bool bAscii = charsetId() == undefined || charsetId() == ascii; // # 1266 Remove trailing nulls - if (bAscii && c.find('\0') != std::string::npos) { - c.resize(c.find('\0')); + if (bAscii) { + auto n = c.find('\0'); + if (n != std::string::npos) + c.resize(n); } return c; } diff --git a/src/xmp.cpp b/src/xmp.cpp index fc80da22..84a2e495 100644 --- a/src/xmp.cpp +++ b/src/xmp.cpp @@ -580,8 +580,8 @@ static XMP_Status nsDumper(void* refCon, XMP_StringPtr buffer, XMP_StringLen buf // remove blanks: http://stackoverflow.com/questions/83439/remove-spaces-from-stdstring-in-c out.erase(std::remove_if(out.begin(), out.end(), isspace), out.end()); - bool bURI = out.find("http://") != std::string::npos; - bool bNS = out.find(':') != std::string::npos && !bURI; + bool bURI = Internal::contains(out, "http://"); + bool bNS = Internal::contains(out, ':') && !bURI; // pop trailing ':' on a namespace if (bNS && !out.empty() && out.back() == ':') diff --git a/src/xmpsidecar.cpp b/src/xmpsidecar.cpp index 56b2133b..181f7c27 100644 --- a/src/xmpsidecar.cpp +++ b/src/xmpsidecar.cpp @@ -71,7 +71,7 @@ void XmpSidecar::readMetadata() { // #1112 - store dates to deal with loss of TZ information during conversions for (const auto& xmp : xmpData_) { std::string key(xmp.key()); - if (key.find("Date") != std::string::npos) { + if (Internal::contains(key, "Date")) { std::string value(xmp.value().toString()); dates_[key] = value; } @@ -82,7 +82,7 @@ void XmpSidecar::readMetadata() { } // XmpSidecar::readMetadata static bool matchi(const std::string& key, const char* substr) { - return Internal::lower(key).find(substr) != std::string::npos; + return Internal::contains(Internal::lower(key), substr); } void XmpSidecar::writeMetadata() { @@ -110,7 +110,7 @@ void XmpSidecar::writeMetadata() { if (xmpData_.findKey(key) != xmpData_.end()) { std::string value_now(xmpData_[sKey].value().toString()); // std::cout << key << " -> " << value_now << " => " << value_orig << std::endl; - if (value_orig.find(value_now.substr(0, 10)) != std::string::npos) { + if (Internal::contains(value_orig, value_now.substr(0, 10))) { xmpData_[sKey] = value_orig; } } diff --git a/unitTests/test_futils.cpp b/unitTests/test_futils.cpp index 6124e6f0..09bf0339 100644 --- a/unitTests/test_futils.cpp +++ b/unitTests/test_futils.cpp @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later +#include "utils.hpp" + #include // File under test #include @@ -32,7 +34,7 @@ TEST(strError, returnSuccessAfterClosingFile) { std::ofstream auxFile(tmpFile.c_str()); auxFile.close(); fs::remove(tmpFile.c_str()); - ASSERT_TRUE(strError().find("(errno = 0)") != std::string::npos); + ASSERT_TRUE(Internal::contains(strError(), "(errno = 0)")); } TEST(strError, returnNoSuchFileOrDirectoryWhenTryingToOpenNonExistingFile) { @@ -42,7 +44,7 @@ TEST(strError, returnNoSuchFileOrDirectoryWhenTryingToOpenNonExistingFile) { TEST(strError, doNotRecognizeUnknownError) { errno = 9999; - ASSERT_TRUE(strError().find("(errno = 9999)") != std::string::npos); + ASSERT_TRUE(Internal::contains(strError(), "(errno = 9999)")); } TEST(getEnv, getsDefaultValueWhenExpectedEnvVariableDoesNotExist) {