aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-01-22 08:44:04 +0100
committerMax Kellermann <max@duempel.org>2014-01-22 08:44:35 +0100
commitb7738e7af342a07f3bf0620d1424313a71c859dd (patch)
tree3a918c41d1567c48377a2b0ace34f98f7308bd00
parent99bebabac97b24e94cad026422e663e97492894b (diff)
downloadmpd-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.cxx54
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 &current = 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 &current = m_path.back();
+ std::string str = trimstring(s, len);
+
switch (current[0]) {
case 'r':
if (!current.compare("res")) {