windows-nt/Source/XPSP1/NT/base/win32/fusion/utils/xmlns.cpp
2020-09-26 16:20:57 +08:00

300 lines
7.9 KiB
C++

#include "stdinc.h"
#include "debmacro.h"
#include "xmlns.h"
#include "fusionheap.h"
#include "smartptr.h"
CXMLNamespaceManager::CXMLNamespaceManager(
) : m_CurrentDepth(0),
m_DefaultNamespacePrefix(NULL)
{
}
CXMLNamespaceManager::~CXMLNamespaceManager()
{
CSxsPreserveLastError ple;
CNamespacePrefix *pCurrent = m_DefaultNamespacePrefix;
// Clean up any namespace prefixes hanging around...
while (pCurrent != NULL)
{
CNamespacePrefix *pNext = pCurrent->m_Previous;
FUSION_DELETE_SINGLETON(pCurrent);
pCurrent = pNext;
}
m_DefaultNamespacePrefix = NULL;
CStringPtrTableIter<CNamespacePrefix, CUnicodeCharTraits> iter(m_NamespacePrefixes);
for (iter.Reset(); iter.More(); iter.Next())
iter.Delete();
ple.Restore();
}
BOOL
CXMLNamespaceManager::Initialize()
{
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
IFW32FALSE_EXIT(m_NamespacePrefixes.Initialize());
fSuccess = TRUE;
Exit:
return fSuccess;
}
HRESULT
CXMLNamespaceManager::OnCreateNode(
IXMLNodeSource *pSource,
PVOID pNodeParent,
USHORT cNumRecs,
XML_NODE_INFO **apNodeInfo
)
{
HRESULT hr = NOERROR;
FN_TRACE_HR(hr);
USHORT i;
SMARTPTR(CNamespacePrefix) NamespacePrefix;
if ((cNumRecs != 0) &&
(apNodeInfo[0]->dwType == XML_ELEMENT))
{
m_CurrentDepth++;
for (i=0; i<cNumRecs; i++)
{
XML_NODE_INFO *Node = apNodeInfo[i];
if (Node->dwType == XML_ATTRIBUTE)
{
if (Node->ulLen >= 5)
{
CStringBuffer TextBuffer;
PCWSTR pwcText = Node->pwcText;
// if it's not prefixed by "xmlns", we're not interested.
if ((pwcText[0] != L'x') ||
(pwcText[1] != L'm') ||
(pwcText[2] != L'l') ||
(pwcText[3] != L'n') ||
(pwcText[4] != L's'))
continue;
// If it's longer than 5 characters and the next character isn't
// a colon, it's not interesting.
if ((Node->ulLen > 5) && (pwcText[5] != L':'))
continue;
IFCOMFAILED_EXIT(NamespacePrefix.HrAllocate(__FILE__, __LINE__));
// walk the subsequent nodes, concatenating the values...
i++;
while (i < cNumRecs)
{
if (apNodeInfo[i]->dwType != XML_PCDATA)
break;
IFW32FALSE_EXIT(NamespacePrefix->m_NamespaceURI.Win32Append(apNodeInfo[i]->pwcText, apNodeInfo[i]->ulLen));
i++;
}
i--;
NamespacePrefix->m_Depth = m_CurrentDepth;
if (Node->ulLen == 5)
{
NamespacePrefix->m_Previous = m_DefaultNamespacePrefix;
m_DefaultNamespacePrefix = NamespacePrefix.Detach();
}
else
{
// Unfortunately, we need the node name in a null terminated buffer. I tried modifying the hash
// table code to handle more than one parameter for a key being passed through, but it ended
// up being too much work.
IFW32FALSE_EXIT(TextBuffer.Win32Assign(pwcText + 6, Node->ulLen - 6));
IFW32FALSE_EXIT(
m_NamespacePrefixes.InsertOrUpdateIf<CXMLNamespaceManager>(
TextBuffer,
NamespacePrefix.Detach(),
this,
&CXMLNamespaceManager::InsertOrUpdateIfCallback));
}
}
}
}
}
hr = NOERROR;
Exit:
return hr;
}
HRESULT
CXMLNamespaceManager::OnBeginChildren(
IXMLNodeSource *pSource,
XML_NODE_INFO *pNodeInfo
)
{
// Nothing to do today, but we'll still have people reflect it through us so that we can do something
// in the future if we need to.
return NOERROR;
}
HRESULT
CXMLNamespaceManager::OnEndChildren(
IXMLNodeSource *pSource,
BOOL fEmpty,
XML_NODE_INFO *pNodeInfo
)
{
HRESULT hr = E_FAIL;
FN_TRACE_HR(hr);
// Pop everything relevant off for this depth...
if (m_DefaultNamespacePrefix != NULL)
{
if (m_DefaultNamespacePrefix->m_Depth == m_CurrentDepth)
{
CNamespacePrefix *Previous = m_DefaultNamespacePrefix->m_Previous;
FUSION_DELETE_SINGLETON(m_DefaultNamespacePrefix);
m_DefaultNamespacePrefix = Previous;
}
}
CStringPtrTableIter<CNamespacePrefix, CUnicodeCharTraits> iter(m_NamespacePrefixes);
for (iter.Reset(); iter.More(); iter.Next())
{
CNamespacePrefix *NamespacePrefix = iter;
if (NamespacePrefix->m_Depth == m_CurrentDepth)
{
if (NamespacePrefix->m_Previous != NULL)
iter.Update(NamespacePrefix->m_Previous);
else{
iter.Delete();
NamespacePrefix = NULL;
}
FUSION_DELETE_SINGLETON(NamespacePrefix);
}
}
m_CurrentDepth--;
hr = NOERROR;
// Exit:
return hr;
}
HRESULT
CXMLNamespaceManager::Map(
DWORD dwMapFlags,
const XML_NODE_INFO *pNodeInfo,
CBaseStringBuffer *pbuffNamespace,
SIZE_T *pcchNamespacePrefix
)
{
HRESULT hr = E_FAIL;
FN_TRACE_HR(hr);
SIZE_T iColon;
SIZE_T ulLen;
PCWSTR pwcText;
CNamespacePrefix *NamespacePrefix = NULL;
if (pcchNamespacePrefix != NULL)
*pcchNamespacePrefix = 0;
PARAMETER_CHECK((dwMapFlags & ~(CXMLNamespaceManager::eMapFlag_DoNotApplyDefaultNamespace)) == 0);
PARAMETER_CHECK(pNodeInfo != NULL);
PARAMETER_CHECK(pbuffNamespace != NULL);
PARAMETER_CHECK(pcchNamespacePrefix != NULL);
ulLen = pNodeInfo->ulLen;
pwcText = pNodeInfo->pwcText;
// First let's see if there's a colon in the name. We can't use wcschr() since it's not
// null terminated.
for (iColon=0; iColon<ulLen; iColon++)
{
if (pwcText[iColon] == L':')
break;
}
// If there was no namespace prefix, apply the default, if there is one.
if (iColon == ulLen)
{
// Unless they asked us not to, apply the default namespace...
if ((dwMapFlags & CXMLNamespaceManager::eMapFlag_DoNotApplyDefaultNamespace) == 0)
NamespacePrefix = m_DefaultNamespacePrefix;
}
else
{
// Ok, so there was a namespace prefix. Look it up in the table...
CCountedStringHolder<CUnicodeCharTraits> key;
key.m_psz = pwcText;
key.m_cch = iColon;
if (!m_NamespacePrefixes.Find(key, NamespacePrefix))
{
hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
goto Exit;
}
}
if (NamespacePrefix != NULL)
IFW32FALSE_EXIT(pbuffNamespace->Win32Assign(NamespacePrefix->m_NamespaceURI));
if ((pcchNamespacePrefix != NULL) && (iColon != ulLen))
*pcchNamespacePrefix = iColon;
hr = NOERROR;
Exit:
return hr;
}
BOOL
CXMLNamespaceManager::InsertOrUpdateIfCallback(
CNamespacePrefix *NewNamespacePrefix,
CNamespacePrefix * const &rpOldNamespacePrefix,
InsertOrUpdateIfDisposition &Disposition
)
{
BOOL fSuccess = FALSE;
FN_TRACE_WIN32(fSuccess);
INTERNAL_ERROR_CHECK(rpOldNamespacePrefix != NULL);
INTERNAL_ERROR_CHECK(NewNamespacePrefix != NULL);
NewNamespacePrefix->m_Previous = rpOldNamespacePrefix;
Disposition = eUpdateValue;
fSuccess = TRUE;
Exit:
return fSuccess;
}
CXMLNamespaceManager::CNamespacePrefix::CNamespacePrefix(
) :
m_Depth(0),
m_Previous(NULL)
{
}
CXMLNamespaceManager::CNamespacePrefix::~CNamespacePrefix()
{
}