diff --git a/xbmc/playlists/PlayListASX.cpp b/xbmc/playlists/PlayListASX.cpp index a3f39164768b5..1ee018394f305 100644 --- a/xbmc/playlists/PlayListASX.cpp +++ b/xbmc/playlists/PlayListASX.cpp @@ -12,7 +12,7 @@ #include "PlayListFactory.h" #include "filesystem/File.h" #include "utils/StringUtils.h" -#include "utils/XBMCTinyXML.h" +#include "utils/XBMCTinyXML2.h" #include "utils/XMLUtils.h" #include "utils/log.h" #include "video/VideoFileItemClassify.h" @@ -21,6 +21,8 @@ #include #include +#include + using namespace XFILE; namespace KODI::PLAYLIST @@ -83,79 +85,73 @@ bool CPlayListASX::LoadData(std::istream& stream) else { std::string asxStream(std::istreambuf_iterator(stream), {}); - CXBMCTinyXML xmlDoc; - xmlDoc.Parse(asxStream, TIXML_DEFAULT_ENCODING); + + CXBMCTinyXML2 xmlDoc; + xmlDoc.Parse(asxStream); if (xmlDoc.Error()) { - CLog::Log(LOGERROR, "Unable to parse ASX info Error: {}", xmlDoc.ErrorDesc()); + CLog::Log(LOGERROR, "Unable to parse ASX info Error: {}", xmlDoc.ErrorStr()); return false; } - TiXmlElement* pRootElement = xmlDoc.RootElement(); + auto* srcRootElement = xmlDoc.RootElement(); - if (!pRootElement) + if (!srcRootElement) return false; - // lowercase every element - TiXmlNode* pNode = pRootElement; - TiXmlNode* pChild = NULL; - std::string value; - value = pNode->Value(); + // lowercase every element - copy to second temp doc + tinyxml2::XMLDocument targetDoc; + std::string value = srcRootElement->Value(); + StringUtils::ToLower(value); - pNode->SetValue(value); - while (pNode) + auto targetRootElement = targetDoc.NewElement(value.c_str()); + + auto* rootAttrib = srcRootElement->ToElement()->FirstAttribute(); + while (rootAttrib) { - pChild = pNode->IterateChildren(pChild); - if (pChild) - { - if (pChild->Type() == TiXmlNode::TINYXML_ELEMENT) - { - value = pChild->Value(); - StringUtils::ToLower(value); - pChild->SetValue(value); - - TiXmlAttribute* pAttr = pChild->ToElement()->FirstAttribute(); - while (pAttr) - { - value = pAttr->Name(); - StringUtils::ToLower(value); - pAttr->SetName(value); - pAttr = pAttr->Next(); - } - } + std::string attribName = rootAttrib->Name(); + auto attribValue = rootAttrib->Value(); + StringUtils::ToLower(attribName); + targetRootElement->SetAttribute(attribName.c_str(), attribValue); + rootAttrib = rootAttrib->Next(); + } - pNode = pChild; - pChild = NULL; - continue; - } + auto* sourceNode = srcRootElement->FirstChild(); + while (sourceNode) + { + // Function to check all child elements and lowercase the elem/attrib names + recurseLowercaseNames(*targetRootElement, sourceNode); - pChild = pNode; - pNode = pNode->Parent(); + sourceNode = sourceNode->NextSiblingElement(); } + + targetDoc.InsertFirstChild(targetRootElement); + + // now data is lowercased, we can parse contents std::string roottitle; - TiXmlElement* pElement = pRootElement->FirstChildElement(); - while (pElement) + auto* element = targetDoc.RootElement()->FirstChildElement(); + while (element) { - value = pElement->Value(); - if (value == "title" && !pElement->NoChildren()) + value = element->Value(); + if (value == "title" && !element->NoChildren()) { - roottitle = pElement->FirstChild()->ValueStr(); + roottitle = element->FirstChild()->Value(); } else if (value == "entry") { std::string title(roottitle); - TiXmlElement* pRef = pElement->FirstChildElement("ref"); - TiXmlElement* pTitle = pElement->FirstChildElement("title"); + auto* refElement = element->FirstChildElement("ref"); + auto* titleElement = element->FirstChildElement("title"); - if (pTitle && !pTitle->NoChildren()) - title = pTitle->FirstChild()->ValueStr(); + if (titleElement && !titleElement->NoChildren()) + title = titleElement->FirstChild()->Value(); - while (pRef) + while (refElement) { // multiple references may appear for one entry // duration may exist on this level too - value = XMLUtils::GetAttribute(pRef, "href"); + value = XMLUtils::GetAttribute(refElement, "href"); if (!value.empty()) { if (title.empty()) @@ -166,12 +162,12 @@ bool CPlayListASX::LoadData(std::istream& stream) newItem->SetPath(value); Add(newItem); } - pRef = pRef->NextSiblingElement("ref"); + refElement = refElement->NextSiblingElement("ref"); } } else if (value == "entryref") { - value = XMLUtils::GetAttribute(pElement, "href"); + value = XMLUtils::GetAttribute(element, "href"); if (!value.empty()) { // found an entryref, let's try loading that url std::unique_ptr playlist(CPlayListFactory::Create(value)); @@ -180,10 +176,61 @@ bool CPlayListASX::LoadData(std::istream& stream) Add(*playlist); } } - pElement = pElement->NextSiblingElement(); + element = element->NextSiblingElement(); } } return true; } + +void CPlayListASX::recurseLowercaseNames(tinyxml2::XMLNode& targetNode, + tinyxml2::XMLNode* sourceNode) +{ + if (sourceNode->ToElement()) + { + std::string strNodeValue = sourceNode->Value(); + StringUtils::ToLower(strNodeValue); + auto* targetElement = targetNode.GetDocument()->NewElement(strNodeValue.c_str()); + + auto* attrib = sourceNode->ToElement()->FirstAttribute(); + while (attrib) + { + std::string attribName = attrib->Name(); + auto attribValue = attrib->Value(); + StringUtils::ToLower(attribName); + targetElement->SetAttribute(attribName.c_str(), attribValue); + attrib = attrib->Next(); + } + + if (!sourceNode->NoChildren()) + { + for (auto* child = sourceNode->FirstChild(); child != nullptr; child = child->NextSibling()) + { + recurseLowercaseNames(*targetElement, child); + } + } + + targetNode.InsertEndChild(targetElement); + return; + } + else if (sourceNode->ToText()) + { + auto* sourceTextElement = sourceNode->ToText(); + auto* sourceText = sourceTextElement->Value(); + auto* targetText = targetNode.GetDocument()->NewText(sourceText); + + if (!sourceNode->NoChildren()) + { + for (auto* child = sourceNode->FirstChildElement(); child != nullptr; + child = child->NextSiblingElement()) + { + recurseLowercaseNames(*targetText, child); + } + } + + targetNode.InsertEndChild(targetText); + return; + } +} + } // namespace KODI::PLAYLIST diff --git a/xbmc/playlists/PlayListASX.h b/xbmc/playlists/PlayListASX.h index f49d713b9db7a..e282091f86db1 100644 --- a/xbmc/playlists/PlayListASX.h +++ b/xbmc/playlists/PlayListASX.h @@ -12,6 +12,12 @@ #include +namespace tinyxml2 +{ +class XMLDocument; +class XMLNode; +} // namespace tinyxml2 + namespace KODI::PLAYLIST { class CPlayListASX : public CPlayList @@ -21,5 +27,12 @@ class CPlayListASX : public CPlayList private: bool LoadAsxIniInfo(std::istream& stream); + + /* recurseLowercaseNames + * Function allows recursive iteration of a source element to lowercase all + * element and attrib Names, and save to a targetNode. + * targetNode must be a separate XMLDocument to sourceNode XMLDocument + */ + void recurseLowercaseNames(tinyxml2::XMLNode& targetNode, tinyxml2::XMLNode* sourceNode); }; } // namespace KODI::PLAYLIST