From 5db91fc5b5fd05b58130cdf93de84f738d312243 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 2 Feb 2024 22:58:37 +0100 Subject: [PATCH] Limit to the first 4 digits when parsing years badly encoded as YYYYMMDD --- src/libs/metadata/impl/TagLibParser.cpp | 8 +++--- src/libs/metadata/impl/Utils.cpp | 32 +++++++++++++++++++++ src/libs/metadata/impl/Utils.hpp | 2 ++ src/libs/metadata/test/Utils.cpp | 37 +++++++++++++++++++++++++ src/libs/utils/test/String.cpp | 3 ++ 5 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/libs/metadata/impl/TagLibParser.cpp b/src/libs/metadata/impl/TagLibParser.cpp index b821bd66..2bfe2f1d 100644 --- a/src/libs/metadata/impl/TagLibParser.cpp +++ b/src/libs/metadata/impl/TagLibParser.cpp @@ -336,19 +336,19 @@ namespace MetaData if (const Wt::WDate date{ Utils::parseDate(value) }; date.isValid()) track.date = date; else if (!track.year) - track.year = StringUtils::readAs(value); + track.year = Utils::parseYear(value); } else if (tag == "YEAR") - track.year = StringUtils::readAs(value); + track.year = Utils::parseYear(value); else if (tag == "ORIGINALDATE") { if (const Wt::WDate date{ Utils::parseDate(value) }; date.isValid()) track.originalDate = date; else if (!track.originalYear) - track.originalYear = StringUtils::readAs(value); + track.originalYear = Utils::parseYear(value); } else if (tag == "ORIGINALYEAR") - track.originalYear = StringUtils::readAs(value); + track.originalYear = Utils::parseYear(value); else if (tag == "METADATA_BLOCK_PICTURE") track.hasCover = true; else if (tag == "COPYRIGHT") diff --git a/src/libs/metadata/impl/Utils.cpp b/src/libs/metadata/impl/Utils.cpp index a0354cbe..b8a0877b 100644 --- a/src/libs/metadata/impl/Utils.cpp +++ b/src/libs/metadata/impl/Utils.cpp @@ -64,6 +64,38 @@ namespace MetaData::Utils return {}; } + std::optional parseYear(std::string_view yearStr) + { + // limit to first 4 digit, accept leading '-' + if (yearStr.empty()) + return std::nullopt; + + int sign; + if (yearStr.front() == '-') + { + sign = -1; + yearStr.remove_prefix(1); + } + else + { + sign = 1; + } + + if (yearStr.empty() || !std::isdigit(yearStr.front())) + return std::nullopt; + + int result{}; + for (std::size_t i{}; i < yearStr.size() && i < 4; ++i) + { + if (!std::isdigit(yearStr[i])) { + break; + } + result = result * 10 + (yearStr[i] - '0'); + } + + return result * sign; + } + std::string_view readStyleToString(ParserReadStyle readStyle) { switch (readStyle) diff --git a/src/libs/metadata/impl/Utils.hpp b/src/libs/metadata/impl/Utils.hpp index e1de14b8..d566cf7d 100644 --- a/src/libs/metadata/impl/Utils.hpp +++ b/src/libs/metadata/impl/Utils.hpp @@ -20,6 +20,7 @@ #pragma once +#include #include #include @@ -28,6 +29,7 @@ namespace MetaData::Utils { Wt::WDate parseDate(std::string_view dateStr); + std::optional parseYear(std::string_view yearStr); std::string_view readStyleToString(ParserReadStyle readStyle); struct PerformerArtist diff --git a/src/libs/metadata/test/Utils.cpp b/src/libs/metadata/test/Utils.cpp index 50b1ff3a..71e4aa44 100644 --- a/src/libs/metadata/test/Utils.cpp +++ b/src/libs/metadata/test/Utils.cpp @@ -76,6 +76,43 @@ TEST(MetaData, parseDate) } } +TEST(MetaData, parseYear) +{ + using namespace MetaData::Utils; + + struct TestCase + { + std::string str; + std::optional result; + } testCases[] + { + { "1995-05-09", 1995 }, + { "1995", 1995 }, + { "-0", 0 }, + { "0", 0 }, + { "00", 0 }, + { "05", 5 }, + { "050", 50 }, + { "00005", 0 }, + { "-50", -50 }, + { "-", std::nullopt }, + { "", std::nullopt }, + { "a", std::nullopt }, + { "1a", 1 }, + { "12a", 12 }, + { "123a", 123 }, + { "1234a", 1234 }, + { "19951123", 1995 }, + { "199511", 1995 }, + }; + + for (const TestCase& testCase : testCases) + { + const std::optional parsed{ parseYear(testCase.str) }; + EXPECT_EQ(parsed, testCase.result) << " str was '" << testCase.str << "'"; + } +} + TEST(MetaData, extractPerformerAndRole) { using namespace MetaData::Utils; diff --git a/src/libs/utils/test/String.cpp b/src/libs/utils/test/String.cpp index fff9c076..0a8769d1 100644 --- a/src/libs/utils/test/String.cpp +++ b/src/libs/utils/test/String.cpp @@ -173,9 +173,12 @@ TEST(StringUtils, readAs_int) EXPECT_EQ(StringUtils::readAs("-1"), -1); EXPECT_EQ(StringUtils::readAs(""), std::nullopt); EXPECT_EQ(StringUtils::readAs("a"), std::nullopt); + EXPECT_EQ(StringUtils::readAs("-"), std::nullopt); EXPECT_EQ(StringUtils::readAs("1024-1"), 1024); EXPECT_EQ(StringUtils::readAs("1024-"), 1024); EXPECT_EQ(StringUtils::readAs("1024/5"), 1024); + EXPECT_EQ(StringUtils::readAs("1024a"), 1024); + EXPECT_EQ(StringUtils::readAs("a1024a"), std::nullopt); } TEST(StringUtils, capitalize)