Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

299 lines
7.9 KiB

  1. #include "stdinc.h"
  2. #include "debmacro.h"
  3. #include "xmlns.h"
  4. #include "fusionheap.h"
  5. #include "smartptr.h"
  6. CXMLNamespaceManager::CXMLNamespaceManager(
  7. ) : m_CurrentDepth(0),
  8. m_DefaultNamespacePrefix(NULL)
  9. {
  10. }
  11. CXMLNamespaceManager::~CXMLNamespaceManager()
  12. {
  13. CSxsPreserveLastError ple;
  14. CNamespacePrefix *pCurrent = m_DefaultNamespacePrefix;
  15. // Clean up any namespace prefixes hanging around...
  16. while (pCurrent != NULL)
  17. {
  18. CNamespacePrefix *pNext = pCurrent->m_Previous;
  19. FUSION_DELETE_SINGLETON(pCurrent);
  20. pCurrent = pNext;
  21. }
  22. m_DefaultNamespacePrefix = NULL;
  23. CStringPtrTableIter<CNamespacePrefix, CUnicodeCharTraits> iter(m_NamespacePrefixes);
  24. for (iter.Reset(); iter.More(); iter.Next())
  25. iter.Delete();
  26. ple.Restore();
  27. }
  28. BOOL
  29. CXMLNamespaceManager::Initialize()
  30. {
  31. BOOL fSuccess = FALSE;
  32. FN_TRACE_WIN32(fSuccess);
  33. IFW32FALSE_EXIT(m_NamespacePrefixes.Initialize());
  34. fSuccess = TRUE;
  35. Exit:
  36. return fSuccess;
  37. }
  38. HRESULT
  39. CXMLNamespaceManager::OnCreateNode(
  40. IXMLNodeSource *pSource,
  41. PVOID pNodeParent,
  42. USHORT cNumRecs,
  43. XML_NODE_INFO **apNodeInfo
  44. )
  45. {
  46. HRESULT hr = NOERROR;
  47. FN_TRACE_HR(hr);
  48. USHORT i;
  49. SMARTPTR(CNamespacePrefix) NamespacePrefix;
  50. if ((cNumRecs != 0) &&
  51. (apNodeInfo[0]->dwType == XML_ELEMENT))
  52. {
  53. m_CurrentDepth++;
  54. for (i=0; i<cNumRecs; i++)
  55. {
  56. XML_NODE_INFO *Node = apNodeInfo[i];
  57. if (Node->dwType == XML_ATTRIBUTE)
  58. {
  59. if (Node->ulLen >= 5)
  60. {
  61. CStringBuffer TextBuffer;
  62. PCWSTR pwcText = Node->pwcText;
  63. // if it's not prefixed by "xmlns", we're not interested.
  64. if ((pwcText[0] != L'x') ||
  65. (pwcText[1] != L'm') ||
  66. (pwcText[2] != L'l') ||
  67. (pwcText[3] != L'n') ||
  68. (pwcText[4] != L's'))
  69. continue;
  70. // If it's longer than 5 characters and the next character isn't
  71. // a colon, it's not interesting.
  72. if ((Node->ulLen > 5) && (pwcText[5] != L':'))
  73. continue;
  74. IFCOMFAILED_EXIT(NamespacePrefix.HrAllocate(__FILE__, __LINE__));
  75. // walk the subsequent nodes, concatenating the values...
  76. i++;
  77. while (i < cNumRecs)
  78. {
  79. if (apNodeInfo[i]->dwType != XML_PCDATA)
  80. break;
  81. IFW32FALSE_EXIT(NamespacePrefix->m_NamespaceURI.Win32Append(apNodeInfo[i]->pwcText, apNodeInfo[i]->ulLen));
  82. i++;
  83. }
  84. i--;
  85. NamespacePrefix->m_Depth = m_CurrentDepth;
  86. if (Node->ulLen == 5)
  87. {
  88. NamespacePrefix->m_Previous = m_DefaultNamespacePrefix;
  89. m_DefaultNamespacePrefix = NamespacePrefix.Detach();
  90. }
  91. else
  92. {
  93. // Unfortunately, we need the node name in a null terminated buffer. I tried modifying the hash
  94. // table code to handle more than one parameter for a key being passed through, but it ended
  95. // up being too much work.
  96. IFW32FALSE_EXIT(TextBuffer.Win32Assign(pwcText + 6, Node->ulLen - 6));
  97. IFW32FALSE_EXIT(
  98. m_NamespacePrefixes.InsertOrUpdateIf<CXMLNamespaceManager>(
  99. TextBuffer,
  100. NamespacePrefix.Detach(),
  101. this,
  102. &CXMLNamespaceManager::InsertOrUpdateIfCallback));
  103. }
  104. }
  105. }
  106. }
  107. }
  108. hr = NOERROR;
  109. Exit:
  110. return hr;
  111. }
  112. HRESULT
  113. CXMLNamespaceManager::OnBeginChildren(
  114. IXMLNodeSource *pSource,
  115. XML_NODE_INFO *pNodeInfo
  116. )
  117. {
  118. // Nothing to do today, but we'll still have people reflect it through us so that we can do something
  119. // in the future if we need to.
  120. return NOERROR;
  121. }
  122. HRESULT
  123. CXMLNamespaceManager::OnEndChildren(
  124. IXMLNodeSource *pSource,
  125. BOOL fEmpty,
  126. XML_NODE_INFO *pNodeInfo
  127. )
  128. {
  129. HRESULT hr = E_FAIL;
  130. FN_TRACE_HR(hr);
  131. // Pop everything relevant off for this depth...
  132. if (m_DefaultNamespacePrefix != NULL)
  133. {
  134. if (m_DefaultNamespacePrefix->m_Depth == m_CurrentDepth)
  135. {
  136. CNamespacePrefix *Previous = m_DefaultNamespacePrefix->m_Previous;
  137. FUSION_DELETE_SINGLETON(m_DefaultNamespacePrefix);
  138. m_DefaultNamespacePrefix = Previous;
  139. }
  140. }
  141. CStringPtrTableIter<CNamespacePrefix, CUnicodeCharTraits> iter(m_NamespacePrefixes);
  142. for (iter.Reset(); iter.More(); iter.Next())
  143. {
  144. CNamespacePrefix *NamespacePrefix = iter;
  145. if (NamespacePrefix->m_Depth == m_CurrentDepth)
  146. {
  147. if (NamespacePrefix->m_Previous != NULL)
  148. iter.Update(NamespacePrefix->m_Previous);
  149. else{
  150. iter.Delete();
  151. NamespacePrefix = NULL;
  152. }
  153. FUSION_DELETE_SINGLETON(NamespacePrefix);
  154. }
  155. }
  156. m_CurrentDepth--;
  157. hr = NOERROR;
  158. // Exit:
  159. return hr;
  160. }
  161. HRESULT
  162. CXMLNamespaceManager::Map(
  163. DWORD dwMapFlags,
  164. const XML_NODE_INFO *pNodeInfo,
  165. CBaseStringBuffer *pbuffNamespace,
  166. SIZE_T *pcchNamespacePrefix
  167. )
  168. {
  169. HRESULT hr = E_FAIL;
  170. FN_TRACE_HR(hr);
  171. SIZE_T iColon;
  172. SIZE_T ulLen;
  173. PCWSTR pwcText;
  174. CNamespacePrefix *NamespacePrefix = NULL;
  175. if (pcchNamespacePrefix != NULL)
  176. *pcchNamespacePrefix = 0;
  177. PARAMETER_CHECK((dwMapFlags & ~(CXMLNamespaceManager::eMapFlag_DoNotApplyDefaultNamespace)) == 0);
  178. PARAMETER_CHECK(pNodeInfo != NULL);
  179. PARAMETER_CHECK(pbuffNamespace != NULL);
  180. PARAMETER_CHECK(pcchNamespacePrefix != NULL);
  181. ulLen = pNodeInfo->ulLen;
  182. pwcText = pNodeInfo->pwcText;
  183. // First let's see if there's a colon in the name. We can't use wcschr() since it's not
  184. // null terminated.
  185. for (iColon=0; iColon<ulLen; iColon++)
  186. {
  187. if (pwcText[iColon] == L':')
  188. break;
  189. }
  190. // If there was no namespace prefix, apply the default, if there is one.
  191. if (iColon == ulLen)
  192. {
  193. // Unless they asked us not to, apply the default namespace...
  194. if ((dwMapFlags & CXMLNamespaceManager::eMapFlag_DoNotApplyDefaultNamespace) == 0)
  195. NamespacePrefix = m_DefaultNamespacePrefix;
  196. }
  197. else
  198. {
  199. // Ok, so there was a namespace prefix. Look it up in the table...
  200. CCountedStringHolder<CUnicodeCharTraits> key;
  201. key.m_psz = pwcText;
  202. key.m_cch = iColon;
  203. if (!m_NamespacePrefixes.Find(key, NamespacePrefix))
  204. {
  205. hr = HRESULT_FROM_WIN32(::FusionpGetLastWin32Error());
  206. goto Exit;
  207. }
  208. }
  209. if (NamespacePrefix != NULL)
  210. IFW32FALSE_EXIT(pbuffNamespace->Win32Assign(NamespacePrefix->m_NamespaceURI));
  211. if ((pcchNamespacePrefix != NULL) && (iColon != ulLen))
  212. *pcchNamespacePrefix = iColon;
  213. hr = NOERROR;
  214. Exit:
  215. return hr;
  216. }
  217. BOOL
  218. CXMLNamespaceManager::InsertOrUpdateIfCallback(
  219. CNamespacePrefix *NewNamespacePrefix,
  220. CNamespacePrefix * const &rpOldNamespacePrefix,
  221. InsertOrUpdateIfDisposition &Disposition
  222. )
  223. {
  224. BOOL fSuccess = FALSE;
  225. FN_TRACE_WIN32(fSuccess);
  226. INTERNAL_ERROR_CHECK(rpOldNamespacePrefix != NULL);
  227. INTERNAL_ERROR_CHECK(NewNamespacePrefix != NULL);
  228. NewNamespacePrefix->m_Previous = rpOldNamespacePrefix;
  229. Disposition = eUpdateValue;
  230. fSuccess = TRUE;
  231. Exit:
  232. return fSuccess;
  233. }
  234. CXMLNamespaceManager::CNamespacePrefix::CNamespacePrefix(
  235. ) :
  236. m_Depth(0),
  237. m_Previous(NULL)
  238. {
  239. }
  240. CXMLNamespaceManager::CNamespacePrefix::~CNamespacePrefix()
  241. {
  242. }