diff options
author | Max Kellermann <max@duempel.org> | 2014-01-27 10:33:42 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-01-27 10:33:42 +0100 |
commit | 30fadaed7fceb242f97776f189fcce1a2214604c (patch) | |
tree | fe055d1d1c959489f0dbb484e4f45e3994c8f89c /src/IcyMetaDataParser.cxx | |
parent | c01282a322f13055cff9f68464b3b1750e59ee4f (diff) | |
parent | 2b10ecfa37e273c752c3f87e2491e2a1a5f0ae58 (diff) | |
download | mpd-30fadaed7fceb242f97776f189fcce1a2214604c.tar.gz mpd-30fadaed7fceb242f97776f189fcce1a2214604c.tar.xz mpd-30fadaed7fceb242f97776f189fcce1a2214604c.zip |
Merge branch 'v0.18.x'
Diffstat (limited to 'src/IcyMetaDataParser.cxx')
-rw-r--r-- | src/IcyMetaDataParser.cxx | 91 |
1 files changed, 70 insertions, 21 deletions
diff --git a/src/IcyMetaDataParser.cxx b/src/IcyMetaDataParser.cxx index d8c12079f..febdb385a 100644 --- a/src/IcyMetaDataParser.cxx +++ b/src/IcyMetaDataParser.cxx @@ -82,32 +82,85 @@ icy_add_item(TagBuilder &tag, TagType type, const char *value) } static void -icy_parse_tag_item(TagBuilder &tag, const char *item) +icy_parse_tag_item(TagBuilder &tag, const char *name, const char *value) { - gchar **p = g_strsplit(item, "=", 0); - - if (p[0] != nullptr && p[1] != nullptr) { - if (strcmp(p[0], "StreamTitle") == 0) - icy_add_item(tag, TAG_TITLE, p[1]); - else - FormatDebug(icy_metadata_domain, - "unknown icy-tag: '%s'", p[0]); - } + if (strcmp(name, "StreamTitle") == 0) + icy_add_item(tag, TAG_TITLE, value); + else + FormatDebug(icy_metadata_domain, + "unknown icy-tag: '%s'", name); +} + +/** + * Find a single quote that is followed by a semicolon (or by the end + * of the string). If that fails, return the first single quote. If + * that also fails, return #end. + */ +static char * +find_end_quote(char *p, char *const end) +{ + char *fallback = std::find(p, end, '\''); + if (fallback >= end - 1 || fallback[1] == ';') + return fallback; + + p = fallback + 1; + while (true) { + p = std::find(p, end, '\''); + if (p == end) + return fallback; - g_strfreev(p); + if (p == end - 1 || p[1] == ';') + return p; + + ++p; + } } static Tag * -icy_parse_tag(const char *p) +icy_parse_tag(char *p, char *const end) { + assert(p != nullptr); + assert(end != nullptr); + assert(p <= end); + TagBuilder tag; - gchar **items = g_strsplit(p, ";", 0); + while (p != end) { + const char *const name = p; + char *eq = std::find(p, end, '='); + if (eq == end) + break; + + *eq = 0; + p = eq + 1; + + if (*p != '\'') { + /* syntax error; skip to the next semicolon, + try to recover */ + char *semicolon = std::find(p, end, ';'); + if (semicolon == end) + break; + p = semicolon + 1; + continue; + } + + ++p; + + const char *const value = p; + char *quote = find_end_quote(p, end); + if (quote == end) + break; - for (unsigned i = 0; items[i] != nullptr; ++i) - icy_parse_tag_item(tag, items[i]); + *quote = 0; + p = quote + 1; - g_strfreev(items); + icy_parse_tag_item(tag, name, value); + + char *semicolon = std::find(p, end, ';'); + if (semicolon == end) + break; + p = semicolon + 1; + } return tag.CommitNew(); } @@ -154,15 +207,11 @@ IcyMetaDataParser::Meta(const void *data, size_t length) ++length; if (meta_position == meta_size) { - /* null-terminate the string */ - - meta_data[meta_size] = 0; - /* parse */ delete tag; - tag = icy_parse_tag(meta_data); + tag = icy_parse_tag(meta_data, meta_data + meta_size); delete[] meta_data; /* change back to normal data mode */ |