Skip to content

Commit

Permalink
Merge pull request xbmc#25274 from fuzzard/tinyxml2_playlistasx
Browse files Browse the repository at this point in the history
[PlayLists] PlayListASX migrate to tinyxml2
  • Loading branch information
fuzzard authored Jun 3, 2024
2 parents 3395d0c + a574094 commit 1df4f58
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 57 deletions.
149 changes: 98 additions & 51 deletions xbmc/playlists/PlayListASX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -21,6 +21,8 @@
#include <iostream>
#include <string>

#include <tinyxml2.h>

using namespace XFILE;

namespace KODI::PLAYLIST
Expand Down Expand Up @@ -83,79 +85,73 @@ bool CPlayListASX::LoadData(std::istream& stream)
else
{
std::string asxStream(std::istreambuf_iterator<char>(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())
Expand All @@ -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<CPlayList> playlist(CPlayListFactory::Create(value));
Expand All @@ -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
13 changes: 13 additions & 0 deletions xbmc/playlists/PlayListASX.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@

#include <iostream>

namespace tinyxml2
{
class XMLDocument;
class XMLNode;
} // namespace tinyxml2

namespace KODI::PLAYLIST
{
class CPlayListASX : public CPlayList
Expand All @@ -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
15 changes: 9 additions & 6 deletions xbmc/playlists/test/test.asx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<asx version="3.0">
<ASX version="3.0">
<title>Example.com Live Stream</title>

<entry>
<title>Short Announcement to Play Before Main Stream</title>
<test>
<something>something test</something>
</test>
<ref href="http://example.com/announcement.wma" />
<param name="aParameterName" value="aParameterValue" />
</entry>
Expand All @@ -14,10 +17,10 @@
<copyright>Copyright © 2005 Example.com</copyright>
</entry>

<Entry>
<ENTRY>
<TITLE>Capital Title</TITLE>
<ref href="http://example3.com:8080" />
<REF HREF="http://example3.com:8080" />
<AUTHOR>Capital Author</AUTHOR>
<copyright>Copyright © 2005 Example.com</copyright>
</Entry>
</asx>
<COPYRIGHT>Copyright © 2005 Example.com</COPYRIGHT>
</ENTRY>
</ASX>

0 comments on commit 1df4f58

Please sign in to comment.