diff options
author | Max Kellermann <max@duempel.org> | 2014-01-22 08:44:04 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-01-22 08:44:35 +0100 |
commit | b7738e7af342a07f3bf0620d1424313a71c859dd (patch) | |
tree | 3a918c41d1567c48377a2b0ace34f98f7308bd00 | |
parent | 99bebabac97b24e94cad026422e663e97492894b (diff) | |
download | mpd-b7738e7af342a07f3bf0620d1424313a71c859dd.tar.gz mpd-b7738e7af342a07f3bf0620d1424313a71c859dd.tar.xz mpd-b7738e7af342a07f3bf0620d1424313a71c859dd.zip |
db/upnp/Directory: join all CDATA nodes for tag values
Expat can call CharacterData() multiple times if the CDATA contains
entity references. We need to collect all of them in one large
string.
-rw-r--r-- | src/db/upnp/Directory.cxx | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/src/db/upnp/Directory.cxx b/src/db/upnp/Directory.cxx index ada50d052..1108d9878 100644 --- a/src/db/upnp/Directory.cxx +++ b/src/db/upnp/Directory.cxx @@ -89,12 +89,26 @@ class UPnPDirParser final : public CommonExpatParser { UPnPDirContent &m_dir; std::vector<std::string> m_path; + + /** + * If not equal to #TAG_NUM_OF_ITEM_TYPES, then we're + * currently reading an element containing a tag value. The + * value is being constructed in #value. + */ + TagType tag_type; + + /** + * The text inside the current element. + */ + std::string value; + UPnPDirObject m_tobj; TagBuilder tag; public: UPnPDirParser(UPnPDirContent& dir) - :m_dir(dir) + :m_dir(dir), + tag_type(TAG_NUM_OF_ITEM_TYPES) { } @@ -103,6 +117,15 @@ protected: { m_path.push_back(name); + if (m_tobj.type != UPnPDirObject::Type::UNKNOWN && + tag_type == TAG_NUM_OF_ITEM_TYPES) { + tag_type = tag_table_lookup(upnp_tags, name); + if (tag_type != TAG_NUM_OF_ITEM_TYPES) + return; + } else { + assert(tag_type == TAG_NUM_OF_ITEM_TYPES); + } + switch (name[0]) { case 'c': if (!strcmp(name, "container")) { @@ -162,6 +185,19 @@ protected: virtual void EndElement(const XML_Char *name) { + if (tag_type != TAG_NUM_OF_ITEM_TYPES) { + assert(m_tobj.type != UPnPDirObject::Type::UNKNOWN); + + tag.AddItem(tag_type, value.c_str()); + + if (tag_type == TAG_TITLE) + m_tobj.name = titleToPathElt(std::move(value)); + + value.clear(); + tag_type = TAG_NUM_OF_ITEM_TYPES; + return; + } + if ((!strcmp(name, "container") || !strcmp(name, "item")) && checkobjok()) { tag.Commit(m_tobj.tag); @@ -173,20 +209,16 @@ protected: virtual void CharacterData(const XML_Char *s, int len) { - const auto ¤t = m_path.back(); - std::string str = trimstring(s, len); - - TagType type = tag_table_lookup(upnp_tags, - current.c_str()); - if (type != TAG_NUM_OF_ITEM_TYPES) { - tag.AddItem(type, str.c_str()); - - if (type == TAG_TITLE) - m_tobj.name = titleToPathElt(std::move(str)); + if (tag_type != TAG_NUM_OF_ITEM_TYPES) { + assert(m_tobj.type != UPnPDirObject::Type::UNKNOWN); + value.append(s, len); return; } + const auto ¤t = m_path.back(); + std::string str = trimstring(s, len); + switch (current[0]) { case 'r': if (!current.compare("res")) { |