diff --git a/include/reader.h b/include/reader.h index 3dcdc441d..dd9f39d94 100644 --- a/include/reader.h +++ b/include/reader.h @@ -235,6 +235,27 @@ class Reader */ string getTags(bool original=false) const; + /** + * Get the value (as a string) of a specific tag. + * + * According to https://wiki.openzim.org/wiki/Tags + * + * @return The value of the specified tag. + * @throw std::out_of_range if the specified tag is not found. + */ + string getTagStr(const std::string& tagName) const; + + /** + * Get the boolean value of a specific tag. + * + * According to https://wiki.openzim.org/wiki/Tags + * + * @return The boolean value of the specified tag. + * @throw std::out_of_range if the specified tag is not found. + * std::domain_error if the value of the tag cannot be convert to bool. + */ + bool getTagBool(const std::string& tagName) const; + /** * Get the relations of the zim file. * diff --git a/src/reader.cpp b/src/reader.cpp index 43b7a1491..87cedc550 100644 --- a/src/reader.cpp +++ b/src/reader.cpp @@ -400,6 +400,48 @@ string Reader::getTags(bool original) const return join(tags, ";"); } +string getTagValueFromTagList(const std::vector& tagList, const std::string& tagName) +{ + for (auto tag: tagList) { + if (tag[0] == '_') { + auto delimPos = tag.find(':'); + if (delimPos == string::npos) { + // No delimiter... what to do ? + continue; + } + auto cTagName = tag.substr(1, delimPos-1); + auto cTagValue = tag.substr(delimPos+1); + if (cTagName == tagName) { + return cTagValue; + } + } + } + std::stringstream ss; + ss << tagName << " cannot be found"; + throw std::out_of_range(ss.str()); +} + +string Reader::getTagStr(const std::string& tagName) const +{ + string tags_str; + getMetadata("Tags", tags_str); + return getTagValueFromTagList(convertTags(tags_str), tagName); +} + +bool Reader::getTagBool(const std::string& tagName) const +{ + auto tagValue = getTagStr(tagName); + if (tagValue == "yes") { + return true; + } else if (tagValue == "no") { + return false; + } else { + std::stringstream ss; + ss << "Tag value '" << tagValue << "' for " << tagName << " cannot be converted to bool."; + throw std::domain_error(ss.str()); + } +} + string Reader::getRelation() const { METADATA("Relation") diff --git a/test/tagParsing.cpp b/test/tagParsing.cpp index c58c1dbe4..9e90519b5 100644 --- a/test/tagParsing.cpp +++ b/test/tagParsing.cpp @@ -60,6 +60,40 @@ TEST(ParseTagTest, convert) } } +TEST(ParseTagTest, valid) +{ + std::string tagStr = "_ftindex:yes;_pictures:no;_videos:no;_details:yes;_category:foo;bar"; + auto tagList = convertTags(tagStr); + + ASSERT_EQ(parse_tag(tagList, "ftindex"), "yes"); + ASSERT_EQ(parse_tag(tagList, "pictures"), "no"); + ASSERT_EQ(parse_tag(tagList, "category"), "foo"); + ASSERT_EQ(parse_tag(tagList, "details"), "yes"); + ASSERT_THROW(parse_tag(tagList, "detail"), std::out_of_range); +} + +TEST(ParseTagTest, compat) +{ + std::string tagStr = "_ftindex;nopic;foo;bar"; + auto tagList = convertTags(tagStr); + + ASSERT_EQ(parse_tag(tagList, "ftindex"), "yes"); + ASSERT_EQ(parse_tag(tagList, "pictures"), "no"); + ASSERT_EQ(parse_tag(tagList, "videos"), "yes"); + ASSERT_EQ(parse_tag(tagList, "details"), "yes"); +} + +TEST(ParseTagTest, invalid) +{ + std::string tagStr = "_ftindex:y;_pictures;_videos:;_details:yes;_details:no;_category:foo;bar"; + auto tagList = convertTags(tagStr); + + ASSERT_EQ(parse_tag(tagList, "ftindex"), "y"); + ASSERT_EQ(parse_tag(tagList, "pictures"), "yes"); + ASSERT_EQ(parse_tag(tagList, "videos"), ""); + ASSERT_EQ(parse_tag(tagList, "details"), "yes"); +} + }; int main(int argc, char** argv) {