Files
core/DesktopEditor/xml/src/xmldom.cpp
2023-09-06 19:57:49 +03:00

1053 lines
28 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (c) Copyright Ascensio System SIA 2010-2023
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
* street, Riga, Latvia, EU, LV-1050.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "../include/xmlutils.h"
#include "./xmllight_private.h"
#include <list>
namespace XmlUtils
{
std::wstring GetNameNoNS(const std::wstring& strNodeName)
{
int nFind = (int)strNodeName.find(L":");
if (-1 == nFind)
return strNodeName;
return strNodeName.substr(nFind + 1);
}
const char* GetNameNoNS(const char* strNodeName)
{
const char* find = strchr(strNodeName, ':');
if (NULL != find)
{
return find + 1;
}
else
{
return strNodeName;
}
}
std::wstring GetNamespace(const std::wstring& strNodeName)
{
int nFind = (int)strNodeName.find(L":");
if (-1 == nFind)
return L"";
return strNodeName.substr(0, nFind);
}
} // namespace XmlUtils
namespace XmlUtils
{
class CXmlNodeBase : public IXmlDOMDocument
{
public:
IXmlDOMDocument* m_pDocument;
std::map<std::string, std::string> m_attributes;
std::vector<CXmlNodeBase*> m_nodes;
std::string m_sText;
std::wstring m_sName;
public:
CXmlNodeBase();
~CXmlNodeBase();
void AddRefDoc();
void ReleaseDoc();
std::wstring GetXml();
void GetXml(NSStringUtils::CStringBuilder& oWriter);
};
CXmlNodeBase::CXmlNodeBase()
{
m_pDocument = NULL;
m_sText = "";
m_sName = L"";
}
CXmlNodeBase::~CXmlNodeBase()
{
if (NULL != m_pDocument)
m_pDocument->Release();
int nCount = (int)m_nodes.size();
for (int i = 0; i < nCount; ++i)
{
CXmlNodeBase* pNode = m_nodes[i];
if (NULL != pNode)
pNode->Release();
}
}
void CXmlNodeBase::AddRefDoc()
{
if (NULL != m_pDocument)
m_pDocument->AddRef();
}
void CXmlNodeBase::ReleaseDoc()
{
if (NULL != m_pDocument)
m_pDocument->Release();
}
std::wstring CXmlNodeBase::GetXml()
{
NSStringUtils::CStringBuilder oWriter;
GetXml(oWriter);
return oWriter.GetData();
}
void CXmlNodeBase::GetXml(NSStringUtils::CStringBuilder& oWriter)
{
oWriter.WriteString(L"<", 1);
oWriter.WriteEncodeXmlString(m_sName.c_str());
std::map<std::string, std::string>::iterator p;
for (p = m_attributes.begin(); p != m_attributes.end(); ++p)
{
oWriter.WriteString(L" ", 1);
oWriter.WriteEncodeXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)p->first.c_str(), (LONG)p->first.length()).c_str());
oWriter.WriteString(L"=\"", 2);
oWriter.WriteEncodeXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)p->second.c_str(), (LONG)p->second.length()).c_str());
oWriter.WriteString(L"\"", 1);
}
oWriter.WriteString(L">", 1);
int nCount = m_nodes.size();
for (int i = 0; i < nCount; ++i)
{
m_nodes[i]->GetXml(oWriter);
}
oWriter.WriteEncodeXmlString(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)m_sText.c_str(), (LONG)m_sText.length()).c_str());
oWriter.WriteString(L"</", 2);
oWriter.WriteEncodeXmlString(m_sName.c_str());
oWriter.WriteString(L">", 1);
}
} // namespace XmlUtils
namespace XmlUtils
{
class CXmlDOMDocument : public IXmlDOMDocument, public CXmlLiteReader_Private
{
public:
CXmlNodeBase* m_pNode;
private:
CXmlNodeBase* m_pCurrentNode;
std::list<CXmlNodeBase*> m_list;
public:
CXmlDOMDocument() : IXmlDOMDocument()
{
m_pNode = NULL;
m_pCurrentNode = NULL;
}
virtual ~CXmlDOMDocument()
{
}
void WriteElement()
{
if (NULL == m_pCurrentNode)
{
m_pNode = new CXmlNodeBase();
m_pNode->m_pDocument = this;
m_pNode->m_pDocument->AddRef();
m_pCurrentNode = m_pNode;
}
else
{
// это m_pCurrentNode
CXmlNodeBase* pNewBase = new CXmlNodeBase();
pNewBase->m_pDocument = this;
pNewBase->m_pDocument->AddRef();
m_pCurrentNode->m_nodes.insert(m_pCurrentNode->m_nodes.end(), pNewBase);
m_pCurrentNode = pNewBase;
}
m_pCurrentNode->m_sName = GetName();
m_list.push_back(m_pCurrentNode);
if (GetAttributesCount() > 0)
{
MoveToFirstAttribute();
std::string sName = GetNameA();
while (!sName.empty())
{
m_pCurrentNode->m_attributes.insert(std::make_pair(sName, GetTextA()));
if (!MoveToNextAttribute())
break;
sName = GetNameA();
}
MoveToElement();
}
if (IsEmptyNode())
{
m_list.pop_back();
if (0 != m_list.size())
{
std::list<CXmlNodeBase*>::iterator iter = m_list.end();
--iter;
m_pCurrentNode = *iter;
}
else
{
m_pCurrentNode = m_pNode;
}
}
}
void Parse()
{
ReadNextNode();
WriteElement();
int nDepth = GetDepth();
if (!IsEmptyElement())
{
XmlNodeType eNodeType = XmlNodeType_None;
int nCurDepth = -1;
// У закрывающего тэга глубина на 1 больше, чем у открывающего
while (true)
{
if (1 != xmlTextReaderRead(reader))
break;
int nTempType = xmlTextReaderNodeType(reader);
if (-1 == nTempType)
break;
eNodeType = (XmlNodeType)nTempType;
nCurDepth = GetDepth();
if (eNodeType == XmlNodeType_Text || eNodeType == XmlNodeType_Whitespace || eNodeType == XmlNodeType_SIGNIFICANT_WHITESPACE)
{
m_pCurrentNode->m_sText += GetTextA();
}
else if (eNodeType == XmlNodeType_CDATA)
{
m_pCurrentNode->m_sText += GetTextA();
}
else if (eNodeType == XmlNodeType_Element)
{
WriteElement();
}
else if (eNodeType == XmlNodeType_EndElement)
{
m_list.pop_back();
if (0 != m_list.size())
{
std::list<CXmlNodeBase*>::iterator iter = m_list.end();
--iter;
m_pCurrentNode = *iter;
}
else
{
m_pCurrentNode = m_pNode;
}
}
nCurDepth = GetDepth();
if (nCurDepth < nDepth)
break;
if (XmlNodeType_EndElement == eNodeType && nCurDepth == nDepth)
break;
}
}
}
};
} // namespace XmlUtils
namespace XmlUtils
{
CXmlNode::CXmlNode()
{
m_pBase = NULL;
}
CXmlNode::CXmlNode(const CXmlNode& oSrc)
{
m_pBase = NULL;
SetBase(oSrc.m_pBase);
}
CXmlNode::~CXmlNode()
{
Clear();
}
bool CXmlNode::FromXmlFile(const wchar_t* sFile, bool bRemoveRootNode)
{
return FromXmlFile(std::wstring(sFile), bRemoveRootNode);
}
bool CXmlNode::FromXmlFile(const std::wstring& sFile, bool bRemoveRootNode)
{
// ignore bRemoveRootNode
CXmlDOMDocument* m_pDocument = new CXmlDOMDocument();
bool bRes = m_pDocument->FromFile(sFile);
if (false == bRes)
{
delete m_pDocument;
return false;
}
m_pDocument->Parse();
if (NULL == m_pDocument->m_pNode)
{
delete m_pDocument;
return false;
}
// присваиваем m_pBase без AddRef, чтобы при удалении CXmlNode начался удаляться m_pBase(после конструктора RefCount==1, а если сделать AddRef то не удалится)
m_pBase = m_pDocument->m_pNode;
// после Parse все Node из m_pDocument сделали ему AddRef, поэтому можем вызвать Release(потому что напрямую нигде его не используем), а окончательно он удалится после удаления всех Node
m_pDocument->Release();
return true;
}
bool CXmlNode::FromXmlStringA(const std::string& sString)
{
CXmlDOMDocument* m_pDocument = new CXmlDOMDocument();
bool bRes = m_pDocument->FromStringA(sString);
if (false == bRes)
{
delete m_pDocument;
return false;
}
m_pDocument->Parse();
if (NULL == m_pDocument->m_pNode)
{
delete m_pDocument;
return false;
}
// присваиваем m_pBase без AddRef, чтобы при удалении CXmlNode начался удаляться m_pBase(после конструктора RefCount==1, а если сделать AddRef то не удалится)
m_pBase = m_pDocument->m_pNode;
// после Parse все Node из m_pDocument сделали ему AddRef, поэтому можем вызвать Release(потому что напрямую нигде его не используем), а окончательно он удалится после удаления всех Node
m_pDocument->Release();
return true;
}
bool CXmlNode::FromXmlString(const wchar_t* sString)
{
return FromXmlString(std::wstring(sString));
}
bool CXmlNode::FromXmlString(const std::wstring& sString)
{
return FromXmlStringA(NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(sString.c_str(), (LONG)sString.length()));
}
bool CXmlNode::IsValid() const
{
return (NULL != m_pBase);
}
void CXmlNode::Clear()
{
this->SetBase(NULL);
}
std::wstring CXmlNode::GetName()
{
return (IsValid() ? m_pBase->m_sName : L"");
}
std::string CXmlNode::GetNameA()
{
return (IsValid() ? U_TO_UTF8(m_pBase->m_sName) : "");
}
std::string CXmlNode::GetTextA()
{
if (IsValid())
{
return m_pBase->m_sText;
}
else
return "";
}
std::wstring CXmlNode::GetText()
{
if (IsValid())
{
return NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)m_pBase->m_sText.c_str(), (LONG)m_pBase->m_sText.length());
}
else
return L"";
}
bool CXmlNode::GetTextIfExist(std::wstring& sOutput)
{
bool bRes = false;
if (IsValid() && !m_pBase->m_sText.empty())
{
sOutput = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)m_pBase->m_sText.c_str(), (LONG)m_pBase->m_sText.length());
bRes = true;
}
return bRes;
}
std::wstring CXmlNode::GetTextExt(const std::wstring& strDefaultValue)
{
// todo xml:space preserve
std::wstring sRes;
if (!GetTextIfExist(sRes))
sRes = strDefaultValue;
return sRes;
}
std::wstring CXmlNode::GetXml(const std::wstring& strDefaultValue)
{
return private_GetXmlFast(strDefaultValue);
}
std::wstring CXmlNode::ReadAttributeBase(const wchar_t* bstrName)
{
return GetAttribute(std::wstring(bstrName));
}
std::wstring CXmlNode::ReadAttribute(const std::wstring& strAttibuteName)
{
return GetAttribute(std::wstring(strAttibuteName));
}
void CXmlNode::ReadAllAttributesA(std::vector<std::string>& strNames, std::vector<std::string>& strValues)
{
if (!IsValid())
return;
std::map<std::string, std::string>::iterator p;
for (p = m_pBase->m_attributes.begin(); p != m_pBase->m_attributes.end(); ++p)
{
strNames.push_back(p->first);
strValues.push_back(p->second);
}
}
void CXmlNode::ReadAllAttributes(std::vector<std::wstring>& strNames, std::vector<std::wstring>& strValues)
{
if (!IsValid())
return;
std::map<std::string, std::string>::iterator p;
for (p = m_pBase->m_attributes.begin(); p != m_pBase->m_attributes.end(); ++p)
{
strNames.push_back(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)p->first.c_str(), (long)p->first.length()));
strValues.push_back(NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)p->second.c_str(), (long)p->second.length()));
}
}
std::string CXmlNode::GetAttributeA(const std::string& sName, const std::string& _default)
{
if (!IsValid())
return _default;
std::map<std::string, std::string>::const_iterator pFind = m_pBase->m_attributes.find(sName);
if (pFind == m_pBase->m_attributes.end())
return _default;
return pFind->second;
}
std::string CXmlNode::GetAttributeA(const std::wstring& sName, const std::string& _default)
{
return GetAttributeA(NSFile::CUtf8Converter::GetUtf8StringFromUnicode2(sName.c_str(), (LONG)sName.length()));
}
std::wstring CXmlNode::GetAttribute(const std::string& sName, const std::wstring& _default)
{
if (!IsValid())
return _default;
std::map<std::string, std::string>::const_iterator pFind = m_pBase->m_attributes.find(sName);
if (pFind == m_pBase->m_attributes.end())
return _default;
return NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)pFind->second.c_str(), (LONG)pFind->second.length());
}
std::wstring CXmlNode::GetAttribute(const std::wstring& sName, const std::wstring& _default)
{
if (!IsValid())
return _default;
std::map<std::string, std::string>::const_iterator pFind = m_pBase->m_attributes.find(U_TO_UTF8(sName));
if (pFind == m_pBase->m_attributes.end())
return _default;
return NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)pFind->second.c_str(), (LONG)pFind->second.length());
}
std::wstring CXmlNode::GetAttribute(const wchar_t* sName, const std::wstring& _default)
{
return GetAttribute(std::wstring(sName), _default);
}
std::wstring CXmlNode::GetAttributeBase(const wchar_t* strAttributeName, const std::wstring& strDefaultValue)
{
return GetAttribute(std::wstring(strAttributeName), strDefaultValue);
}
int CXmlNode::GetAttributesCount()
{
if (IsValid())
{
return m_pBase->m_attributes.size();
}
else
return 0;
}
void CXmlNode::GetAllAttributes(std::vector<std::wstring>& names, std::vector<std::wstring>& values)
{
for (std::map<std::string, std::string>::iterator p = m_pBase->m_attributes.begin(); p != m_pBase->m_attributes.end(); ++p)
{
names.push_back(UTF8_TO_U(p->first));
values.push_back(UTF8_TO_U(p->second));
}
}
void CXmlNode::GetAllAttributes(std::vector<std::string>& names, std::vector<std::string>& values)
{
for (std::map<std::string, std::string>::iterator p = m_pBase->m_attributes.begin(); p != m_pBase->m_attributes.end(); ++p)
{
names.push_back(p->first);
values.push_back(p->second);
}
}
void CXmlNode::GetAllAttributes(std::list<std::wstring>& names, std::list<std::wstring>& values)
{
for (std::map<std::string, std::string>::iterator p = m_pBase->m_attributes.begin(); p != m_pBase->m_attributes.end(); ++p)
{
names.push_back(UTF8_TO_U(p->first));
values.push_back(UTF8_TO_U(p->second));
}
}
void CXmlNode::GetAllAttributes(std::list<std::string>& names, std::list<std::string>& values)
{
for (std::map<std::string, std::string>::iterator p = m_pBase->m_attributes.begin(); p != m_pBase->m_attributes.end(); ++p)
{
names.push_back(p->first);
values.push_back(p->second);
}
}
bool CXmlNode::GetAttributeIfExist(const std::wstring& sName, std::wstring& sOutput)
{
bool bRes = false;
if (IsValid())
{
std::map<std::string, std::string>::const_iterator pFind = m_pBase->m_attributes.find(U_TO_UTF8(sName));
if (pFind != m_pBase->m_attributes.end())
{
sOutput = NSFile::CUtf8Converter::GetUnicodeStringFromUTF8((BYTE*)pFind->second.c_str(), (LONG)pFind->second.length());
bRes = true;
}
}
return bRes;
}
int CXmlNode::GetAttributeInt(const std::string& sName, const int& _default)
{
if (!IsValid())
return _default;
std::map<std::string, std::string>::const_iterator pFind = m_pBase->m_attributes.find(sName);
if (pFind == m_pBase->m_attributes.end())
return _default;
if (0 == pFind->second.length())
return _default;
return atoi(pFind->second.c_str());
}
bool CXmlNode::SetAttributeInt(const std::wstring& sName, const int& value)
{
if (!IsValid())
return false;
std::map<std::string, std::string>::iterator pFind = m_pBase->m_attributes.find(U_TO_UTF8(sName));
if (pFind == m_pBase->m_attributes.end())
return false;
pFind->second = std::to_string(value);
return true;
}
int CXmlNode::GetAttributeInt(const std::wstring& sName, const int& _default)
{
if (!IsValid())
return _default;
std::map<std::string, std::string>::const_iterator pFind = m_pBase->m_attributes.find(U_TO_UTF8(sName));
if (pFind == m_pBase->m_attributes.end())
return _default;
if (0 == pFind->second.length())
return _default;
return atoi(pFind->second.c_str());
}
int CXmlNode::ReadAttributeInt(const std::wstring& str, const int& _default)
{
return GetAttributeInt(str, _default);
}
double CXmlNode::GetAttributeDouble(const std::string& sName, const double& _default)
{
if (!IsValid())
return _default;
std::map<std::string, std::string>::const_iterator pFind = m_pBase->m_attributes.find(sName);
if (pFind == m_pBase->m_attributes.end())
return _default;
if (0 == pFind->second.length())
return _default;
return atof(pFind->second.c_str());
}
double CXmlNode::GetAttributeDouble(const std::wstring& sName, const double& _default)
{
if (!IsValid())
return _default;
std::map<std::string, std::string>::const_iterator pFind = m_pBase->m_attributes.find(U_TO_UTF8(sName));
if (pFind == m_pBase->m_attributes.end())
return _default;
if (0 == pFind->second.length())
return _default;
return atof(pFind->second.c_str());
}
double CXmlNode::ReadAttributeDouble(const std::wstring& str, const double& _default)
{
return GetAttributeDouble(str, _default);
}
std::wstring CXmlNode::ReadNodeTextBase(const wchar_t* bsName)
{
return ReadNodeText(std::wstring(bsName));
}
std::wstring CXmlNode::ReadNodeText(const std::wstring& strName)
{
return ReadValueString(strName);
}
std::wstring CXmlNode::ReadValueString(const std::wstring& sName, const std::wstring& nDef)
{
CXmlNode oTemp;
if (GetNode(sName, oTemp))
return oTemp.GetText();
return L"";
}
int CXmlNode::ReadValueInt(const std::wstring& str, const int& nDef)
{
int nRes = nDef;
CXmlNode oTemp;
if (GetNode(str, oTemp))
{
std::wstring sText;
if (oTemp.GetTextIfExist(sText))
{
try
{
nRes = std::stoi(sText);
}
catch (...)
{
nRes = nDef;
}
}
}
return nRes;
}
std::wstring CXmlNode::GetAttributeOrValue(const std::wstring& strAttributeName, const std::wstring& strDefaultValue)
{
std::wstring sRes;
if (!GetAttributeIfExist(strAttributeName, sRes))
{
CXmlNode oTemp;
if (GetNode(strAttributeName, oTemp))
sRes = oTemp.GetText();
else
sRes = strDefaultValue;
}
return sRes;
}
CXmlNode CXmlNode::ReadNode(const wchar_t* strNodeName)
{
CXmlNode oNode;
GetNode(std::wstring(strNodeName), oNode);
return oNode;
}
CXmlNode CXmlNode::ReadNode(const std::wstring& strNodeName)
{
CXmlNode oNode;
GetNode(strNodeName, oNode);
return oNode;
}
CXmlNode CXmlNode::ReadNodeNoNS(const std::wstring& strNodeName)
{
CXmlNode node;
if (IsValid())
{
int nCount = (int)m_pBase->m_nodes.size();
for (int i = 0; i < nCount; ++i)
{
if (strNodeName == GetNameNoNS(m_pBase->m_nodes[i]->m_sName))
{
CXmlNodeBase* pBase = m_pBase->m_nodes[i];
node.SetBase(pBase);
break;
}
}
}
return node;
}
std::vector<CXmlNode> CXmlNode::ReadNodesNoNS(const std::wstring& sName)
{
std::vector<CXmlNode> oNodes;
if (IsValid())
{
bool bGetAll = false;
if (L"*" == sName)
bGetAll = true;
int nCount = (int)m_pBase->m_nodes.size();
for (int i = 0; i < nCount; ++i)
{
if (bGetAll || sName == GetNameNoNS(m_pBase->m_nodes[i]->m_sName))
{
CXmlNode oNode;
CXmlNodeBase* pBase = m_pBase->m_nodes[i];
oNode.SetBase(pBase);
oNodes.push_back(oNode);
}
}
}
return oNodes;
}
CXmlNode CXmlNode::GetNode(const std::wstring& sName)
{
CXmlNode oNode;
GetNode(sName, oNode);
return oNode;
}
std::vector<CXmlNode> CXmlNode::GetNodes(const std::wstring& sName)
{
std::vector<CXmlNode> oNodes;
if (IsValid())
{
bool bGetAll = false;
if (L"*" == sName)
bGetAll = true;
int nCount = (int)m_pBase->m_nodes.size();
for (int i = 0; i < nCount; ++i)
{
if (bGetAll || sName == m_pBase->m_nodes[i]->m_sName)
{
CXmlNode oNode;
CXmlNodeBase* pBase = m_pBase->m_nodes[i];
oNode.SetBase(pBase);
oNodes.push_back(oNode);
}
}
}
return oNodes;
}
bool CXmlNode::GetChilds(std::vector<CXmlNode>& oXmlNodes)
{
bool bRes = false;
if (IsValid())
{
int nCount = (int)m_pBase->m_nodes.size();
if (nCount > 0)
{
bRes = true;
for (int i = 0; i < nCount; ++i)
{
CXmlNode oNode;
CXmlNodeBase* pBase = m_pBase->m_nodes[i];
oNode.SetBase(pBase);
oXmlNodes.push_back(oNode);
}
}
}
return bRes;
}
bool CXmlNode::GetNode(const std::wstring& sName, CXmlNode& oNode)
{
bool bRes = false;
if (IsValid())
{
int nCount = (int)m_pBase->m_nodes.size();
for (int i = 0; i < nCount; ++i)
{
if (sName == m_pBase->m_nodes[i]->m_sName)
{
CXmlNodeBase* pBase = m_pBase->m_nodes[i];
oNode.SetBase(pBase);
bRes = true;
break;
}
}
}
return bRes;
}
bool CXmlNode::GetNodes(const std::wstring& sName, std::vector<CXmlNode>& oNodes)
{
oNodes = GetNodes(sName);
return (0 != oNodes.size());
}
CXmlNode& CXmlNode::operator=(const CXmlNode& oSrc)
{
this->SetBase(oSrc.m_pBase);
return *this;
}
std::wstring CXmlNode::private_GetXml()
{
return private_GetXml(L"");
}
std::wstring CXmlNode::private_GetXml(const std::wstring& strDefaultValue)
{
if (NULL == m_pBase)
return strDefaultValue;
return m_pBase->GetXml();
}
std::wstring CXmlNode::private_GetXmlFast()
{
return private_GetXmlFast(L"");
}
std::wstring CXmlNode::private_GetXmlFast(const std::wstring& strDefaultValue)
{
if (NULL == m_pBase)
return strDefaultValue;
NSStringUtils::CStringBuilder oWriter;
m_pBase->GetXml(oWriter);
return oWriter.GetData();
}
void CXmlNode::SetBase(CXmlNodeBase* pBase)
{
CXmlNodeBase* pBaseOld = m_pBase;
m_pBase = pBase;
if (NULL != m_pBase)
m_pBase->AddRef();
if (NULL != pBaseOld)
pBaseOld->Release();
}
std::wstring CXmlNode::GetNamespace(const std::wstring& strNodeName)
{
int nFind = strNodeName.find(wchar_t(':'));
if (-1 == nFind)
return L"";
return strNodeName.substr(0, nFind);
}
std::wstring CXmlNode::GetNameNoNS(const std::wstring& strNodeName)
{
int nFind = strNodeName.find(wchar_t(':'));
if (-1 == nFind)
return strNodeName;
return strNodeName.substr(nFind + 1);
}
} // namespace XmlUtils
namespace XmlUtils
{
class CXmlBuffer
{
public:
NSStringUtils::CStringBuilderA builder;
public:
CXmlBuffer()
{
}
~CXmlBuffer()
{
}
};
static int buffer_xmlBufferIOWrite(CXmlBuffer* buf, const char* buffer, int len)
{
buf->builder.WriteString(buffer, (size_t)len);
return len;
}
static int buffer_xmlBufferIOClose(CXmlBuffer* buf)
{
XML_UNUSED(buf);
return 0;
}
static int buffer_xmlC14NIsVisibleCallback(void* user_data, xmlNodePtr node, xmlNodePtr parent)
{
XML_UNUSED(user_data);
XML_UNUSED(parent);
if (node->type == XML_TEXT_NODE)
{
const char* cur = (char*)node->content;
size_t size = strlen(cur);
for (size_t i = 0; i < size; ++i, ++cur)
{
if (*cur != '\n' && *cur != '\r' && *cur != '\t')
return 1;
}
return 0;
}
return 1;
}
std::string NSXmlCanonicalizator::Execute(const std::string& sXml, int mode, bool withComments)
{
#ifdef LIBXML_C14N_ENABLED
xmlDocPtr xmlDoc = xmlParseMemory((char*)sXml.c_str(), (int)sXml.length());
CXmlBuffer bufferC14N;
xmlOutputBufferPtr _buffer = xmlOutputBufferCreateIO((xmlOutputWriteCallback)buffer_xmlBufferIOWrite, (xmlOutputCloseCallback)buffer_xmlBufferIOClose, &bufferC14N, NULL);
xmlC14NExecute(xmlDoc, buffer_xmlC14NIsVisibleCallback, NULL, mode, NULL, withComments ? 1 : 0, _buffer);
xmlOutputBufferClose(_buffer);
return bufferC14N.builder.GetData();
#else
return "";
#endif
}
std::string NSXmlCanonicalizator::Execute(const std::wstring& sXmlFile, int mode, bool withComments)
{
std::string sXml;
NSFile::CFileBinary::ReadAllTextUtf8A(sXmlFile, sXml);
return Execute(sXml, mode, withComments);
}
} // namespace XmlUtils
std::string XmlUtils::GetUtf8FromFileContent(unsigned char* pData, unsigned int len)
{
if (4 > len)
return std::string((char*)pData, (size_t)len);
if (pData[0] == 0xEF && pData[1] == 0xBB && pData[2] == 0xFE && pData[3] == 0xBF)
{
return std::string((char*)pData + 3, (size_t)(len - 3));
}
char markerUtf16 = 0;
if (pData[0] == 0xFF && pData[1] == 0xFE && !(pData[2] == 0x00 && pData[3] == 0x00))
markerUtf16 = 1;
if (pData[0] == 0xFE && pData[1] == 0xFF)
markerUtf16 = 2;
if (0 != markerUtf16)
{
int nCountSymbols = (len - 2) >> 1;
int nCountSymbolsNatural = 0;
unsigned int* pUnicodes = new unsigned int[nCountSymbols];
unsigned char* pCurrent = pData + 2;
for (int i = 0; i < nCountSymbols; ++i)
{
unsigned short nLeading = (markerUtf16 == 1) ? (pCurrent[0] | (pCurrent[1] << 8)) : (pCurrent[1] | (pCurrent[0] << 8));
pCurrent += 2;
if (nLeading < 0xD800 || nLeading > 0xDFFF)
{
pUnicodes[nCountSymbolsNatural++] = nLeading;
}
else
{
i++;
if (i == nCountSymbols)
break;
unsigned short nTrailing = (markerUtf16 == 1) ? (pCurrent[0] | (pCurrent[1] << 8)) : (pCurrent[1] | (pCurrent[0] << 8));
pCurrent += 2;
if (nTrailing >= 0xDC00 && nTrailing <= 0xDFFF)
{
pUnicodes[nCountSymbolsNatural++] = 0x10000 + (((nLeading & 0x03FF) << 10) | (nTrailing & 0x03FF));
}
}
}
std::string sRet = NSStringExt::CConverter::GetUtf8FromUTF32(pUnicodes, nCountSymbolsNatural);
RELEASEARRAYOBJECTS(pUnicodes);
return sRet;
}
char markerUtf32 = 0;
if (pData[0] == 0xFF && pData[1] == 0xFE && pData[2] == 0x00 && pData[3] == 0x00)
markerUtf32 = 1;
if (pData[0] == 0 && pData[1] == 0 && pData[2] == 0xFE && pData[3] == 0xFF)
markerUtf32 = 2;
if (0 != markerUtf16)
{
int nCountSymbols = (len - 4) >> 2;
int nCountSymbolsNatural = 0;
unsigned int* pUnicodes = new unsigned int[nCountSymbols];
unsigned char* pCurrent = pData + 4;
if (markerUtf32 == 1)
{
for (int i = 0; i < nCountSymbols; ++i, pCurrent += 4)
pUnicodes[nCountSymbolsNatural++] = (pCurrent[0] | (pCurrent[1] << 8) | (pCurrent[2] << 16) | (pCurrent[3] << 24));
}
else
{
for (int i = 0; i < nCountSymbols; ++i, pCurrent += 4)
pUnicodes[nCountSymbolsNatural++] = (pCurrent[3] | (pCurrent[2] << 8) | (pCurrent[1] << 16) | (pCurrent[0] << 24));
}
std::string sRet = NSStringExt::CConverter::GetUtf8FromUTF32(pUnicodes, nCountSymbolsNatural);
RELEASEARRAYOBJECTS(pUnicodes);
return sRet;
}
return std::string((char*)pData, (size_t)len);
}