tag/IcyMetadataParser: pass std::string_view to icy_parse_tag()

This commit is contained in:
Max Kellermann 2023-12-20 20:00:21 +01:00
parent e443ee357a
commit 58fc857a2d
2 changed files with 30 additions and 49 deletions

View File

@ -4,6 +4,7 @@
#include "IcyMetaDataParser.hxx" #include "IcyMetaDataParser.hxx"
#include "tag/Builder.hxx" #include "tag/Builder.hxx"
#include "util/AllocatedString.hxx" #include "util/AllocatedString.hxx"
#include "util/StringSplit.hxx"
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
@ -99,24 +100,21 @@ icy_parse_tag_item(TagBuilder &tag,
* of the string). If that fails, return the first single quote. If * of the string). If that fails, return the first single quote. If
* that also fails, return #end. * that also fails, return #end.
*/ */
static const char * static constexpr std::pair<std::string_view, std::string_view>
find_end_quote(const char *p, const char *const end) noexcept SplitEndQuote(std::string_view s) noexcept
{ {
const char *fallback = std::find(p, end, '\''); auto quote = s.find('\'');
if (fallback >= end - 1 || fallback[1] == ';') if (quote == s.npos)
return fallback; return {};
p = fallback + 1; if (const auto i = s.find("';"sv, quote); i != s.npos)
while (true) { quote = i;
p = std::find(p, end, '\''); else
if (p == end) quote = s.rfind('\'');
return fallback;
if (p == end - 1 || p[1] == ';') assert(quote != s.npos);
return p;
++p; return {s.substr(0, quote), s.substr(quote + 1)};
}
} }
static std::unique_ptr<Tag> static std::unique_ptr<Tag>
@ -124,52 +122,35 @@ icy_parse_tag(
#ifdef HAVE_ICU_CONVERTER #ifdef HAVE_ICU_CONVERTER
const IcuConverter *icu_converter, const IcuConverter *icu_converter,
#endif #endif
const char *p, const char *const end) noexcept std::string_view src) noexcept
{ {
assert(p != nullptr);
assert(end != nullptr);
assert(p <= end);
TagBuilder tag; TagBuilder tag;
while (p != end) { while (!src.empty()) {
const char *eq = std::find(p, end, '='); const auto [name, rest] = Split(src, '=');
if (eq == end) if (rest.empty())
break; break;
const std::string_view name{p, eq}; if (rest.front() != '\'') {
p = eq + 1;
if (*p != '\'') {
/* syntax error; skip to the next semicolon, /* syntax error; skip to the next semicolon,
try to recover */ try to recover */
const char *semicolon = std::find(p, end, ';'); src = Split(rest, ';').second;
if (semicolon == end)
break;
p = semicolon + 1;
continue; continue;
} }
++p; src = rest.substr(1);
const char *quote = find_end_quote(p, end); const auto [value, after_value] = SplitEndQuote(rest.substr(1));
if (quote == end) if (after_value.data() == nullptr)
break; break;
const std::string_view value{p, quote};
p = quote + 1;
icy_parse_tag_item(tag, icy_parse_tag_item(tag,
#ifdef HAVE_ICU_CONVERTER #ifdef HAVE_ICU_CONVERTER
icu_converter, icu_converter,
#endif #endif
name, value); name, value);
const char *semicolon = std::find(p, end, ';'); src = Split(after_value, ';').second;
if (semicolon == end)
break;
p = semicolon + 1;
} }
return tag.CommitNew(); return tag.CommitNew();
@ -223,7 +204,7 @@ IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
#ifdef HAVE_ICU_CONVERTER #ifdef HAVE_ICU_CONVERTER
icu_converter.get(), icu_converter.get(),
#endif #endif
meta_data, meta_data + meta_size); {meta_data, meta_size});
delete[] meta_data; delete[] meta_data;
/* change back to normal data mode */ /* change back to normal data mode */

View File

@ -11,16 +11,16 @@
#include <string.h> #include <string.h>
static std::unique_ptr<Tag>
icy_parse_tag(const char *p)
{
return icy_parse_tag(
#ifdef HAVE_ICU_CONVERTER #ifdef HAVE_ICU_CONVERTER
nullptr,
#endif static std::unique_ptr<Tag>
p, p + strlen(p)); icy_parse_tag(std::string_view p) noexcept
{
return icy_parse_tag(nullptr, p);
} }
#endif
static void static void
CompareTagTitle(const Tag &tag, const std::string &title) CompareTagTitle(const Tag &tag, const std::string &title)
{ {